blob: 543f46012b6d3e153bb748f3c5c37f626beacade [file] [log] [blame]
Brian Salomoncbcb0a12017-11-19 13:20:13 -05001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GLTestAtlasTextRenderer.h"
9#include "../gl/GLTestContext.h"
10#include "SkBitmap.h"
11#include "TestAtlasTextRenderer.h"
12#include "gl/GrGLDefines.h"
13
14using sk_gpu_test::GLTestContext;
15
16namespace {
17
18class GLTestAtlasTextRenderer : public sk_gpu_test::TestAtlasTextRenderer {
19public:
20 GLTestAtlasTextRenderer(std::unique_ptr<GLTestContext>);
21
22 void* createTexture(AtlasFormat, int width, int height) override;
23
24 void deleteTexture(void* textureHandle) override;
25
26 void setTextureData(void* textureHandle, const void* data, int x, int y, int width, int height,
27 size_t rowBytes) override;
28
29 void drawSDFGlyphs(void* targetHandle, void* textureHandle, const SDFVertex vertices[],
30 int quadCnt) override;
31
32 void* makeTargetHandle(int width, int height) override;
33
34 void targetDeleted(void* target) override;
35
36 SkBitmap readTargetHandle(void* target) override;
37
38 bool initialized() const { return 0 != fProgram; }
39
40private:
41 struct AtlasTexture {
42 GrGLuint fID;
43 AtlasFormat fFormat;
44 int fWidth;
45 int fHeight;
46 };
47
48 struct Target {
49 GrGLuint fFBOID;
50 GrGLuint fRBID;
51 int fWidth;
52 int fHeight;
53 };
54
55 std::unique_ptr<GLTestContext> fContext;
56 GrGLuint fProgram = 0;
57 GrGLint fDstScaleAndTranslateLocation = 0;
58 GrGLint fAtlasInvSizeLocation = 0;
59 GrGLint fSamplerLocation = 0;
60};
61
62#define callgl(NAME, ...) fContext->gl()->fFunctions.f##NAME(__VA_ARGS__)
63#define checkgl() \
64 do { \
65 static constexpr auto line = __LINE__; \
66 auto error = fContext->gl()->fFunctions.fGetError(); \
67 if (error != GR_GL_NO_ERROR) { \
68 SkDebugf("GL ERROR: 0x%x, line %d\n", error, line); \
69 } \
70 } while (false)
71
72GLTestAtlasTextRenderer::GLTestAtlasTextRenderer(std::unique_ptr<GLTestContext> context)
73 : fContext(std::move(context)) {
74 auto restore = fContext->makeCurrentAndAutoRestore();
75 auto vs = callgl(CreateShader, GR_GL_VERTEX_SHADER);
76 static constexpr char kGLVersionString[] = "#version 430 compatibility";
77 static constexpr char kGLESVersionString[] = "#version 300 es";
78 GrGLint lengths[2];
79 const GrGLchar* strings[2];
80 switch (fContext->gl()->fStandard) {
81 case kGL_GrGLStandard:
82 strings[0] = kGLVersionString;
83 lengths[0] = static_cast<GrGLint>(SK_ARRAY_COUNT(kGLVersionString)) - 1;
84 break;
85 case kGLES_GrGLStandard:
86 strings[0] = kGLESVersionString;
87 lengths[0] = static_cast<GrGLint>(SK_ARRAY_COUNT(kGLESVersionString)) - 1;
88 break;
89 default:
90 strings[0] = nullptr;
91 lengths[0] = 0;
92 break;
93 }
94
95 static constexpr const char kVS[] = R"(
96 uniform vec4 uDstScaleAndTranslate;
97 uniform vec2 uAtlasInvSize;
98
99 layout (location = 0) in vec2 inPosition;
100 layout (location = 1) in vec4 inColor;
101 layout (location = 2) in uvec2 inTextureCoords;
102
103 out vec2 vTexCoord;
104 out vec4 vColor;
105 out vec2 vIntTexCoord;
106
107 void main() {
108 vec2 intCoords;
109 // floor(vec2) doesn't seem to work on some ES devices.
110 intCoords.x = floor(float(inTextureCoords.x));
111 intCoords.y = floor(float(inTextureCoords.y));
112 vTexCoord = intCoords * uAtlasInvSize;
113 vIntTexCoord = intCoords;
114 vColor = inColor;
115 gl_Position = vec4(inPosition.x * uDstScaleAndTranslate.x + uDstScaleAndTranslate.y,
116 inPosition.y * uDstScaleAndTranslate.z + uDstScaleAndTranslate.w,
117 0.0, 1.0);
118 }
119 )";
120 strings[1] = kVS;
121 lengths[1] = SK_ARRAY_COUNT(kVS) - 1;
122 callgl(ShaderSource, vs, 2, strings, lengths);
123 callgl(CompileShader, vs);
124 GrGLint compileStatus;
125 callgl(GetShaderiv, vs, GR_GL_COMPILE_STATUS, &compileStatus);
126 if (compileStatus == GR_GL_FALSE) {
127 GrGLint logLength;
128 callgl(GetShaderiv, vs, GR_GL_INFO_LOG_LENGTH, &logLength);
129 std::unique_ptr<GrGLchar[]> log(new GrGLchar[logLength + 1]);
130 log[logLength] = '\0';
131 callgl(GetShaderInfoLog, vs, logLength, &logLength, log.get());
132 SkDebugf("Vertex Shader failed to compile\n%s", log.get());
133 callgl(DeleteShader, vs);
134 return;
135 }
136
137 auto fs = callgl(CreateShader, GR_GL_FRAGMENT_SHADER);
138 static constexpr const char kFS[] = R"(
139 uniform sampler2D uSampler;
140
141 in vec2 vTexCoord;
142 in vec4 vColor;
143 in vec2 vIntTexCoord;
144
145 layout (location = 0) out vec4 outColor;
146
147 void main() {
148 float sdfValue = texture(uSampler, vTexCoord).r;
149 float distance = 7.96875 * (sdfValue - 0.50196078431000002);
150 vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));
151 vec2 Jdx = dFdx(vIntTexCoord);
152 vec2 Jdy = dFdy(vIntTexCoord);
153 float dg_len2 = dot(dist_grad, dist_grad);
154 if (dg_len2 < 0.0001) {
155 dist_grad = vec2(0.7071, 0.7071);
156 } else {
157 dist_grad = dist_grad * inversesqrt(dg_len2);
158 }
159 vec2 grad = vec2(dist_grad.x * Jdx.x + dist_grad.y * Jdy.x,
160 dist_grad.x * Jdx.y + dist_grad.y * Jdy.y);
161 float afwidth = abs(0.65000000000000002 * length(grad));
162 float value = smoothstep(-afwidth, afwidth, distance);
163 outColor = value * vec4(vColor.rgb * vColor.a, vColor.a);
164 }
165 )";
166 strings[1] = kFS;
167 lengths[1] = SK_ARRAY_COUNT(kFS) - 1;
168 callgl(ShaderSource, fs, 2, strings, lengths);
169 callgl(CompileShader, fs);
170 callgl(GetShaderiv, fs, GR_GL_COMPILE_STATUS, &compileStatus);
171 if (compileStatus == GR_GL_FALSE) {
172 GrGLint logLength;
173 callgl(GetShaderiv, fs, GR_GL_INFO_LOG_LENGTH, &logLength);
174 std::unique_ptr<GrGLchar[]> log(new GrGLchar[logLength + 1]);
175 log[logLength] = '\0';
176 callgl(GetShaderInfoLog, fs, logLength, &logLength, log.get());
177 SkDebugf("Fragment Shader failed to compile\n%s", log.get());
178 callgl(DeleteShader, vs);
179 callgl(DeleteShader, fs);
180 return;
181 }
182
183 fProgram = callgl(CreateProgram);
184 if (!fProgram) {
185 callgl(DeleteShader, vs);
186 callgl(DeleteShader, fs);
187 return;
188 }
189
190 callgl(AttachShader, fProgram, vs);
191 callgl(AttachShader, fProgram, fs);
192 callgl(LinkProgram, fProgram);
193 GrGLint linkStatus;
194 callgl(GetProgramiv, fProgram, GR_GL_LINK_STATUS, &linkStatus);
195 if (linkStatus == GR_GL_FALSE) {
196 GrGLint logLength = 0;
197 callgl(GetProgramiv, vs, GR_GL_INFO_LOG_LENGTH, &logLength);
198 std::unique_ptr<GrGLchar[]> log(new GrGLchar[logLength + 1]);
199 log[logLength] = '\0';
200 callgl(GetProgramInfoLog, vs, logLength, &logLength, log.get());
201 SkDebugf("Program failed to link\n%s", log.get());
202 callgl(DeleteShader, vs);
203 callgl(DeleteShader, fs);
204 callgl(DeleteProgram, fProgram);
205 fProgram = 0;
206 return;
207 }
208 fDstScaleAndTranslateLocation = callgl(GetUniformLocation, fProgram, "uDstScaleAndTranslate");
209 fAtlasInvSizeLocation = callgl(GetUniformLocation, fProgram, "uAtlasInvSize");
210 fSamplerLocation = callgl(GetUniformLocation, fProgram, "uSampler");
211 if (fDstScaleAndTranslateLocation < 0 || fAtlasInvSizeLocation < 0 || fSamplerLocation < 0) {
212 callgl(DeleteShader, vs);
213 callgl(DeleteShader, fs);
214 callgl(DeleteProgram, fProgram);
215 fProgram = 0;
216 }
217
218 checkgl();
219}
220
221inline bool atlas_format_to_gl_types(SkAtlasTextRenderer::AtlasFormat format,
222 GrGLenum* internalFormat, GrGLenum* externalFormat,
223 GrGLenum* type) {
224 switch (format) {
225 case SkAtlasTextRenderer::AtlasFormat::kA8:
226 *internalFormat = GR_GL_R8;
227 *externalFormat = GR_GL_RED;
228 *type = GR_GL_UNSIGNED_BYTE;
229 return true;
230 }
231 return false;
232}
233
234inline int atlas_format_bytes_per_pixel(SkAtlasTextRenderer::AtlasFormat format) {
235 switch (format) {
236 case SkAtlasTextRenderer::AtlasFormat::kA8:
237 return 1;
238 }
239 return 0;
240}
241
242void* GLTestAtlasTextRenderer::createTexture(AtlasFormat format, int width, int height) {
243 GrGLenum internalFormat;
244 GrGLenum externalFormat;
245 GrGLenum type;
246 if (!atlas_format_to_gl_types(format, &internalFormat, &externalFormat, &type)) {
247 return nullptr;
248 }
249 auto restore = fContext->makeCurrentAndAutoRestore();
250
251 GrGLuint id;
252 callgl(GenTextures, 1, &id);
253 if (!id) {
254 return nullptr;
255 }
256
257 callgl(BindTexture, GR_GL_TEXTURE_2D, id);
258 callgl(TexImage2D, GR_GL_TEXTURE_2D, 0, internalFormat, width, height, 0, externalFormat, type,
259 nullptr);
260 checkgl();
261
262 AtlasTexture* atlas = new AtlasTexture;
263 atlas->fID = id;
264 atlas->fFormat = format;
265 atlas->fWidth = width;
266 atlas->fHeight = height;
267 return atlas;
268}
269
270void GLTestAtlasTextRenderer::deleteTexture(void* textureHandle) {
271 auto restore = fContext->makeCurrentAndAutoRestore();
272
273 auto* atlasTexture = reinterpret_cast<const AtlasTexture*>(textureHandle);
274
275 callgl(DeleteTextures, 1, &atlasTexture->fID);
276 checkgl();
277
278 delete atlasTexture;
279}
280
281void GLTestAtlasTextRenderer::setTextureData(void* textureHandle, const void* data, int x, int y,
282 int width, int height, size_t rowBytes) {
283 auto restore = fContext->makeCurrentAndAutoRestore();
284
285 auto atlasTexture = reinterpret_cast<const AtlasTexture*>(textureHandle);
286
287 GrGLenum internalFormat;
288 GrGLenum externalFormat;
289 GrGLenum type;
290 if (!atlas_format_to_gl_types(atlasTexture->fFormat, &internalFormat, &externalFormat, &type)) {
291 return;
292 }
293 int bpp = atlas_format_bytes_per_pixel(atlasTexture->fFormat);
294 GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
295 if (static_cast<size_t>(rowLength * bpp) != rowBytes) {
296 return;
297 }
298 callgl(PixelStorei, GR_GL_UNPACK_ALIGNMENT, 1);
299 callgl(PixelStorei, GR_GL_UNPACK_ROW_LENGTH, rowLength);
300 callgl(BindTexture, GR_GL_TEXTURE_2D, atlasTexture->fID);
301 callgl(TexSubImage2D, GR_GL_TEXTURE_2D, 0, x, y, width, height, externalFormat, type, data);
302 checkgl();
303}
304
305void GLTestAtlasTextRenderer::drawSDFGlyphs(void* targetHandle, void* textureHandle,
306 const SDFVertex vertices[], int quadCnt) {
307 auto restore = fContext->makeCurrentAndAutoRestore();
308
309 auto target = reinterpret_cast<const Target*>(targetHandle);
310 auto atlas = reinterpret_cast<const AtlasTexture*>(textureHandle);
311
312 callgl(UseProgram, fProgram);
313
314 callgl(ActiveTexture, GR_GL_TEXTURE0);
315 callgl(BindTexture, GR_GL_TEXTURE_2D, atlas->fID);
316 callgl(TexParameteri, GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_GL_LINEAR);
317 callgl(TexParameteri, GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_GL_LINEAR);
318
319 float uniformScaleAndTranslate[4] = {2.f / target->fWidth, -1.f, 2.f / target->fHeight, -1.f};
320 callgl(Uniform4fv, fDstScaleAndTranslateLocation, 1, uniformScaleAndTranslate);
321 callgl(Uniform2f, fAtlasInvSizeLocation, 1.f / atlas->fWidth, 1.f / atlas->fHeight);
322 callgl(Uniform1i, fSamplerLocation, 0);
323
324 callgl(BindFramebuffer, GR_GL_FRAMEBUFFER, target->fFBOID);
325 callgl(Viewport, 0, 0, target->fWidth, target->fHeight);
326
327 callgl(Enable, GR_GL_BLEND);
328 callgl(BlendFunc, GR_GL_ONE, GR_GL_ONE_MINUS_SRC_ALPHA);
329 callgl(Disable, GR_GL_DEPTH_TEST);
330
331 callgl(BindVertexArray, 0);
332 callgl(BindBuffer, GR_GL_ARRAY_BUFFER, 0);
333 callgl(BindBuffer, GR_GL_ELEMENT_ARRAY_BUFFER, 0);
334 callgl(VertexAttribPointer, 0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(SDFVertex), vertices);
335 size_t colorOffset = 2 * sizeof(float);
336 callgl(VertexAttribPointer, 1, 4, GR_GL_UNSIGNED_BYTE, GR_GL_TRUE, sizeof(SDFVertex),
337 reinterpret_cast<const char*>(vertices) + colorOffset);
338 size_t texOffset = colorOffset + sizeof(uint32_t);
339 callgl(VertexAttribIPointer, 2, 2, GR_GL_UNSIGNED_SHORT, sizeof(SDFVertex),
340 reinterpret_cast<const char*>(vertices) + texOffset);
341 callgl(EnableVertexAttribArray, 0);
342 callgl(EnableVertexAttribArray, 1);
343 callgl(EnableVertexAttribArray, 2);
344
345 std::unique_ptr<uint16_t[]> indices(new uint16_t[quadCnt * 6]);
346 for (int q = 0; q < quadCnt; ++q) {
347 indices[q * 6 + 0] = 0 + 4 * q;
348 indices[q * 6 + 1] = 1 + 4 * q;
349 indices[q * 6 + 2] = 2 + 4 * q;
350 indices[q * 6 + 3] = 2 + 4 * q;
351 indices[q * 6 + 4] = 1 + 4 * q;
352 indices[q * 6 + 5] = 3 + 4 * q;
353 }
354 callgl(DrawElements, GR_GL_TRIANGLES, 6 * quadCnt, GR_GL_UNSIGNED_SHORT, indices.get());
355 checkgl();
356}
357
358void* GLTestAtlasTextRenderer::makeTargetHandle(int width, int height) {
359 auto restore = fContext->makeCurrentAndAutoRestore();
360
361 GrGLuint fbo;
362 callgl(GenFramebuffers, 1, &fbo);
363 if (!fbo) {
364 return nullptr;
365 }
366 GrGLuint rb;
367 callgl(GenRenderbuffers, 1, &rb);
368 if (!rb) {
369 callgl(DeleteFramebuffers, 1, &fbo);
370 return nullptr;
371 }
372 callgl(BindFramebuffer, GR_GL_FRAMEBUFFER, fbo);
373 callgl(BindRenderbuffer, GR_GL_RENDERBUFFER, rb);
374 callgl(RenderbufferStorage, GR_GL_RENDERBUFFER, GR_GL_RGBA8, width, height);
375 callgl(FramebufferRenderbuffer, GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_RENDERBUFFER,
376 rb);
377 GrGLenum status = callgl(CheckFramebufferStatus, GR_GL_FRAMEBUFFER);
378 if (GR_GL_FRAMEBUFFER_COMPLETE != status) {
379 callgl(DeleteFramebuffers, 1, &fbo);
380 callgl(DeleteRenderbuffers, 1, &rb);
381 return nullptr;
382 }
383 callgl(Disable, GR_GL_SCISSOR_TEST);
384 callgl(ClearColor, 0.5, 0.5, 0.5, 1.0);
385 callgl(Clear, GR_GL_COLOR_BUFFER_BIT);
386 checkgl();
387 Target* target = new Target;
388 target->fFBOID = fbo;
389 target->fRBID = rb;
390 target->fWidth = width;
391 target->fHeight = height;
392 return target;
393}
394
395void GLTestAtlasTextRenderer::targetDeleted(void* target) {
396 auto restore = fContext->makeCurrentAndAutoRestore();
397
398 Target* t = reinterpret_cast<Target*>(target);
399 callgl(DeleteFramebuffers, 1, &t->fFBOID);
400 callgl(DeleteRenderbuffers, 1, &t->fRBID);
401 delete t;
402}
403
404SkBitmap GLTestAtlasTextRenderer::readTargetHandle(void* target) {
405 auto restore = fContext->makeCurrentAndAutoRestore();
406
407 Target* t = reinterpret_cast<Target*>(target);
408
409 auto info =
410 SkImageInfo::Make(t->fWidth, t->fHeight, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
411 SkBitmap bmp;
412 bmp.setInfo(info, sizeof(uint32_t) * t->fWidth);
413 bmp.allocPixels();
414
415 callgl(BindFramebuffer, GR_GL_FRAMEBUFFER, t->fFBOID);
416 callgl(ReadPixels, 0, 0, t->fWidth, t->fHeight, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE,
417 bmp.getPixels());
418 checkgl();
419 return bmp;
420}
421
422} // anonymous namespace
423
424namespace sk_gpu_test {
425
426sk_sp<TestAtlasTextRenderer> MakeGLTestAtlasTextRenderer() {
427 std::unique_ptr<GLTestContext> context(CreatePlatformGLTestContext(kGL_GrGLStandard));
428 if (!context) {
429 context.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
430 }
431 if (!context) {
432 return nullptr;
433 }
434 auto restorer = context->makeCurrentAndAutoRestore();
435 auto renderer = sk_make_sp<GLTestAtlasTextRenderer>(std::move(context));
436 return renderer->initialized() ? std::move(renderer) : nullptr;
437}
438
439} // namespace sk_gpu_test