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