Home | History | Annotate | Download | only in atlastext
      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