static GrGLuint load_shader(const GrGLInterface* gl, const char* shaderSrc, GrGLenum type) { GrGLuint shader; // Create the shader object GR_GL_CALL_RET(gl, shader, CreateShader(type)); // Load the shader source GR_GL_CALL(gl, ShaderSource(shader, 1, &shaderSrc, NULL)); // Compile the shader GR_GL_CALL(gl, CompileShader(shader)); // Check for compile time errors GrGLint success; GrGLchar infoLog[512]; GR_GL_CALL(gl, GetShaderiv(shader, GR_GL_COMPILE_STATUS, &success)); if (!success) { GR_GL_CALL(gl, GetShaderInfoLog(shader, 512, NULL, infoLog)); SkDebugf("ERROR::SHADER::COMPLIATION_FAILED: %s\n", infoLog); } return shader; }
void GLGpuPosInstancedArraysBench::onDraw(const int loops, SkCanvas* canvas) { const GrGLInterface* gl = get_interface(canvas); if (!gl) { return; } GR_GL_CALL(gl, DrawArraysInstanced(GR_GL_TRIANGLES, 0, 6, fNumQuads)); #ifdef DUMP_IMAGES const char* filename = "out.png"; dump_image(gl, kScreenWidth, kScreenHeight, filename); #endif SkFAIL("done\n"); }
void GrGLAttribArrayState::set(const GrGpuGL* gpu, int index, GrGLVertexBuffer* buffer, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, GrGLvoid* offset) { SkASSERT(index >= 0 && index < fAttribArrayStates.count()); AttribArrayState* array = &fAttribArrayStates[index]; if (!array->fEnableIsValid || !array->fEnabled) { GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(index)); array->fEnableIsValid = true; array->fEnabled = true; } if (!array->fAttribPointerIsValid || array->fVertexBufferID != buffer->bufferID() || array->fSize != size || array->fNormalized != normalized || array->fStride != stride || array->fOffset != offset) { buffer->bind(); GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index, size, type, normalized, stride, offset)); array->fAttribPointerIsValid = true; array->fVertexBufferID = buffer->bufferID(); array->fSize = size; array->fNormalized = normalized; array->fStride = stride; array->fOffset = offset; } }
void GLVec4ScalarBench::glDraw(int loops, const GrGLContext* ctx) { const GrGLInterface* gl = ctx->interface(); for (int i = 0; i < loops; i++) { GR_GL_CALL(gl, DrawArrays(GR_GL_TRIANGLES, 0, kVerticesPerTri * kNumTriPerDraw)); } // using -w when running nanobench will not produce correct images; // changing this to #if 1 will write the correct images to the Skia folder. #if 0 SkString filename("out"); filename.appendf("_%s.png", this->getName()); DumpImage(gl, kScreenWidth, kScreenHeight, filename.c_str()); #endif }
void GrGLAttribArrayState::disableUnusedArrays(const GrGpuGL* gpu, uint64_t usedMask) { int count = fAttribArrayStates.count(); for (int i = 0; i < count; ++i) { if (!(usedMask & 0x1)) { if (!fAttribArrayStates[i].fEnableIsValid || fAttribArrayStates[i].fEnabled) { GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i)); fAttribArrayStates[i].fEnableIsValid = true; fAttribArrayStates[i].fEnabled = false; } } else { SkASSERT(fAttribArrayStates[i].fEnableIsValid && fAttribArrayStates[i].fEnabled); } // if the count is greater than 64 then this will become 0 and we will disable arrays 64+. usedMask >>= 1; } }
bool GrGLRenderTarget::completeStencilAttachment() { GrGLGpu* gpu = this->getGLGpu(); const GrGLInterface* interface = gpu->glInterface(); GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment(); if (nullptr == stencil) { GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER, 0)); GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT, GR_GL_RENDERBUFFER, 0)); #ifdef SK_DEBUG if (kChromium_GrGLDriver != gpu->glContext().driver()) { // This check can cause problems in Chromium if the context has been asynchronously // abandoned (see skbug.com/5200) GrGLenum status; GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status); } #endif return true; } else { const GrGLStencilAttachment* glStencil = static_cast<const GrGLStencilAttachment*>(stencil); GrGLuint rb = glStencil->renderbufferID(); gpu->invalidateBoundRenderTarget(); gpu->stats()->incRenderTargetBinds(); GR_GL_CALL(interface, BindFramebuffer(GR_GL_FRAMEBUFFER, this->renderFBOID())); GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER, rb)); if (glStencil->format().fPacked) { GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT, GR_GL_RENDERBUFFER, rb)); } else { GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_DEPTH_ATTACHMENT, GR_GL_RENDERBUFFER, 0)); } #ifdef SK_DEBUG if (kChromium_GrGLDriver != gpu->glContext().driver()) { // This check can cause problems in Chromium if the context has been asynchronously // abandoned (see skbug.com/5200) GrGLenum status; GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status); } #endif return true; } }
void GLVec4ScalarBench::setup(const GrGLContext* ctx) { const GrGLInterface* gl = ctx->interface(); if (!gl) { SkFAIL("GL interface is nullptr in setup()!\n"); } fFboTextureId = SetupFramebuffer(gl, kScreenWidth, kScreenHeight); fProgram = this->setupShader(ctx); int index = 0; SkMatrix viewMatrices[kNumTriPerDraw]; setup_matrices(kNumTriPerDraw, [&index, &viewMatrices](const SkMatrix& m) { viewMatrices[index++] = m; }); this->setupSingleVbo(gl, viewMatrices); GR_GL_CALL(gl, UseProgram(fProgram)); }
void GrGLBufferImpl::unmap(GrGpuGL* gpu) { VALIDATE(); SkASSERT(this->isMapped()); if (0 != fDesc.fID) { switch (gpu->glCaps().mapBufferType()) { case GrGLCaps::kNone_MapBufferType: SkDEBUGFAIL("Shouldn't get here."); return; case GrGLCaps::kMapBuffer_MapBufferType: // fall through case GrGLCaps::kMapBufferRange_MapBufferType: this->bind(gpu); GL_CALL(gpu, UnmapBuffer(fBufferType)); break; case GrGLCaps::kChromium_MapBufferType: this->bind(gpu); GR_GL_CALL(gpu->glInterface(), UnmapBufferSubData(fMapPtr)); break; } } fMapPtr = NULL; }
static void cleanup(SkGLContext* glctx0, GrGLuint texID0, SkGLContext* glctx1, GrContext* grctx1, const GrGLTextureInfo* grbackendtex1, GrEGLImage image1) { if (glctx1) { glctx1->makeCurrent(); if (grctx1) { if (grbackendtex1) { GrGLGpu* gpu1 = static_cast<GrGLGpu*>(grctx1->getGpu()); GrBackendObject handle = reinterpret_cast<GrBackendObject>(grbackendtex1); gpu1->deleteTestingOnlyBackendTexture(handle, false); } grctx1->unref(); } if (GR_EGL_NO_IMAGE != image1) { glctx1->destroyEGLImage(image1); } } glctx0->makeCurrent(); if (texID0) { GR_GL_CALL(glctx0->gl(), DeleteTextures(1, &texID0)); } }
void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu, GrGLuint pathID, const SkPath& skPath) { SkASSERT(!skPath.isEmpty()); #ifdef SK_SCALAR_IS_FLOAT // This branch does type punning, converting SkPoint* to GrGLfloat*. if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) { int verbCnt = skPath.countVerbs(); int pointCnt = skPath.countPoints(); int coordCnt = pointCnt * 2; SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt); SkSTArray<16, GrGLfloat, true> pathCoords(coordCnt); static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_not_two_floats"); pathCommands.resize_back(verbCnt); pathCoords.resize_back(coordCnt); skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt); skPath.getVerbs(&pathCommands[0], verbCnt); SkDEBUGCODE(int verbCoordCnt = 0); for (int i = 0; i < verbCnt; ++i) { SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]); pathCommands[i] = verb_to_gl_path_cmd(v); SkDEBUGCODE(verbCoordCnt += num_coords(v)); } SkASSERT(verbCnt == pathCommands.count()); SkASSERT(verbCoordCnt == pathCoords.count()); SkDEBUGCODE(verify_floats(&pathCoords[0], pathCoords.count())); GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0], pathCoords.count(), GR_GL_FLOAT, &pathCoords[0])); return; } #endif SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath)); }
GrGLint SkGLContext::createTextureRectangle(int width, int height, GrGLenum internalFormat, GrGLenum externalFormat, GrGLenum externalType, GrGLvoid* data) { if (!(kGL_GrGLStandard == fGL->fStandard && GrGLGetVersion(fGL) >= GR_GL_VER(3, 2)) && !fGL->fExtensions.has("GL_ARB_texture_rectangle")) { return 0; } GrGLuint id; GR_GL_CALL(fGL, GenTextures(1, &id)); GR_GL_CALL(fGL, BindTexture(GR_GL_TEXTURE_RECTANGLE, id)); GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST)); GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST)); GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE)); GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE)); GR_GL_CALL(fGL, TexImage2D(GR_GL_TEXTURE_RECTANGLE, 0, internalFormat, width, height, 0, externalFormat, externalType, data)); return id; }
void GLVec4ScalarBench::setupSingleVbo(const GrGLInterface* gl, const SkMatrix* viewMatrices) { // triangles drawn will alternate between the top-right half of the screen and the bottom-left // half of the screen Vertex vertices[kVerticesPerTri * kNumTriPerDraw]; for (uint32_t i = 0; i < kNumTriPerDraw; i++) { Vertex* v = &vertices[i * kVerticesPerTri]; if (i % 2 == 0) { v[0].fPositions.set(-1.0f, -1.0f); v[1].fPositions.set( 1.0f, -1.0f); v[2].fPositions.set( 1.0f, 1.0f); } else { v[0].fPositions.set(-1.0f, -1.0f); v[1].fPositions.set( 1.0f, 1.0f); v[2].fPositions.set( -1.0f, 1.0f); } SkPoint* position = reinterpret_cast<SkPoint*>(v); viewMatrices[i].mapPointsWithStride(position, sizeof(Vertex), kVerticesPerTri); GrGLfloat color[3] = {1.0f, 0.0f, 1.0f}; for (uint32_t j = 0; j < kVerticesPerTri; j++) { v->fColors[0] = color[0]; v->fColors[1] = color[1]; v->fColors[2] = color[2]; v++; } } GR_GL_CALL(gl, GenBuffers(1, &fVboId)); GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, fVboId)); GR_GL_CALL(gl, EnableVertexAttribArray(0)); GR_GL_CALL(gl, EnableVertexAttribArray(1)); GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Vertex), (GrGLvoid*)0)); GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, sizeof(Vertex), (GrGLvoid*)(sizeof(SkPoint)))); GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(vertices), vertices, GR_GL_STATIC_DRAW)); }
void GLCpuPosInstancedArraysBench::setup(const GrGLContext* ctx) { const GrGLInterface* gl = ctx->interface(); fTexture = SetupFramebuffer(gl, kScreenWidth, kScreenHeight); fProgram = this->setupShader(ctx); // setup matrices int index = 0; SkMatrix viewMatrices[kNumTri]; setup_matrices(kNumTri, [&index, &viewMatrices](const SkMatrix& m) { viewMatrices[index++] = m; }); // setup VAO GR_GL_CALL(gl, GenVertexArrays(1, &fVAO)); GR_GL_CALL(gl, BindVertexArray(fVAO)); switch (fVboSetup) { case kUseOne_VboSetup: this->setupSingleVbo(gl, viewMatrices); break; case kUseTwo_VboSetup: this->setupDoubleVbo(gl, viewMatrices); break; case kUseInstance_VboSetup: this->setupInstanceVbo(gl, viewMatrices); break; } // clear screen GR_GL_CALL(gl, ClearColor(0.03f, 0.03f, 0.03f, 1.0f)); GR_GL_CALL(gl, Clear(GR_GL_COLOR_BUFFER_BIT)); // set us up to draw GR_GL_CALL(gl, UseProgram(fProgram)); GR_GL_CALL(gl, BindVertexArray(fVAO)); }
void GLTestContext::submit() { if (fGL) { GR_GL_CALL(fGL.get(), Flush()); } }
void GLTestContext::finish() { if (fGL) { GR_GL_CALL(fGL.get(), Finish()); } }
void GrGLResetRowLength(const GrGLInterface* gl) { if (gl->supportsDesktop()) { GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); } }
void GrGLPath::InitPathObjectEmptyPath(GrGLGpu* gpu, GrGLuint pathID) { GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr)); }
void GLCpuPosInstancedArraysBench::teardown(const GrGLInterface* gl) { GR_GL_CALL(gl, DeleteProgram(fProgram)); GR_GL_CALL(gl, DeleteBuffers(fBuffers.count(), fBuffers.begin())); GR_GL_CALL(gl, DeleteVertexArrays(1, &fVAO)); }
void GLGpuPosInstancedArraysBench::setup(const GrGLInterface* gl) { setup_framebuffer(gl, kScreenWidth, kScreenHeight); // compile and use shaders GrGLint shaderProgram = compile_shader(gl, gpu_vertex_shader, fragment_shader); // translations int index = 0; GrGLfloat viewMatrices[fNumQuads * fSkMatrixNumCells]; setup_matrices(fNumQuads, [&index, &viewMatrices](const SkMatrix& m) { GrGLGetMatrix<3>(&viewMatrices[index], m); index += fSkMatrixNumCells; }); // Constants for our various shader programs GrGLfloat quad_vertices[] = { // Positions // Colors -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }; // update vertex data GrGLuint quadVAO, quadVBO; GR_GL_CALL(gl, GenVertexArrays(1, &quadVAO)); GR_GL_CALL(gl, GenBuffers(1, &quadVBO)); GR_GL_CALL(gl, BindVertexArray(quadVAO)); GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, quadVBO)); GR_GL_CALL(gl, EnableVertexAttribArray(0)); GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, 5 * sizeof(GrGLfloat), (GrGLvoid*)0)); GR_GL_CALL(gl, EnableVertexAttribArray(1)); GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, 5 * sizeof(GrGLfloat), (GrGLvoid*)(2 * sizeof(GrGLfloat)))); GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_vertices, GR_GL_STATIC_DRAW)); // Also set instance data GrGLuint instanceVBO; GR_GL_CALL(gl, GenBuffers(1, &instanceVBO)); GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, instanceVBO)); GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(GrGLfloat) * fSkMatrixNumCells * fNumQuads, &viewMatrices[0], GR_GL_STATIC_DRAW)); GR_GL_CALL(gl, EnableVertexAttribArray(2)); GR_GL_CALL(gl, EnableVertexAttribArray(3)); GR_GL_CALL(gl, EnableVertexAttribArray(4)); GR_GL_CALL(gl, VertexAttribPointer(2, 3, GR_GL_FLOAT, GR_GL_FALSE, 9 * sizeof(GrGLfloat), (GrGLvoid*)0)); GR_GL_CALL(gl, VertexAttribPointer(3, 3, GR_GL_FLOAT, GR_GL_FALSE, 9 * sizeof(GrGLfloat), (GrGLvoid*)(3 * sizeof(GrGLfloat)))); GR_GL_CALL(gl, VertexAttribPointer(4, 3, GR_GL_FLOAT, GR_GL_FALSE, 9 * sizeof(GrGLfloat), (GrGLvoid*)(6 * sizeof(GrGLfloat)))); GR_GL_CALL(gl, VertexAttribDivisor(2, 1)); GR_GL_CALL(gl, VertexAttribDivisor(3, 1)); GR_GL_CALL(gl, VertexAttribDivisor(4, 1)); // draw GR_GL_CALL(gl, ClearColor(0.03f, 0.03f, 0.03f, 1.0f)); GR_GL_CALL(gl, Clear(GR_GL_COLOR_BUFFER_BIT)); // set us up to draw GR_GL_CALL(gl, UseProgram(shaderProgram)); GR_GL_CALL(gl, BindVertexArray(quadVAO)); }
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(RectangleTexture, reporter, ctxInfo) { GrContext* context = ctxInfo.grContext(); sk_gpu_test::GLTestContext* glContext = ctxInfo.glContext(); static const int kWidth = 13; static const int kHeight = 13; GrColor pixels[kWidth * kHeight]; for (int y = 0; y < kHeight; ++y) { for (int x = 0; x < kWidth; ++x) { pixels[y * kWidth + x] = y * kWidth + x; } } for (int origin = 0; origin < 2; ++origin) { GrGLuint rectTexID = glContext->createTextureRectangle(kWidth, kHeight, GR_GL_RGBA, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels); if (!rectTexID) { return; } // Let GrContext know that we messed with the GL context directly. context->resetContext(); // Wrap the rectangle texture ID in a GrTexture GrGLTextureInfo rectangleInfo; rectangleInfo.fID = rectTexID; rectangleInfo.fTarget = GR_GL_TEXTURE_RECTANGLE; GrBackendTextureDesc rectangleDesc; rectangleDesc.fFlags = kRenderTarget_GrBackendTextureFlag; rectangleDesc.fConfig = kRGBA_8888_GrPixelConfig; rectangleDesc.fWidth = kWidth; rectangleDesc.fHeight = kHeight; rectangleDesc.fOrigin = origin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin; rectangleDesc.fTextureHandle = reinterpret_cast<GrBackendObject>(&rectangleInfo); GrColor refPixels[kWidth * kHeight]; bool flipRef = rectangleDesc.fOrigin == kBottomLeft_GrSurfaceOrigin; for (int y = 0; y < kHeight; ++y) { for (int x = 0; x < kWidth; ++x) { int y0 = flipRef ? kHeight - y - 1 : y; refPixels[y * kWidth + x] = pixels[y0 * kWidth + x]; } } SkAutoTUnref<GrTexture> rectangleTexture( context->textureProvider()->wrapBackendTexture(rectangleDesc)); if (!rectangleTexture) { ERRORF(reporter, "Error wrapping rectangle texture in GrTexture."); GR_GL_CALL(glContext->gl(), DeleteTextures(1, &rectTexID)); continue; } test_read_pixels(reporter, context, rectangleTexture, refPixels); test_copy_surface_src(reporter, context, rectangleTexture, refPixels); test_copy_surface_dst(reporter, context, rectangleTexture); test_write_pixels(reporter, context, rectangleTexture); test_clear(reporter, context, rectangleTexture); GR_GL_CALL(glContext->gl(), DeleteTextures(1, &rectTexID)); } }
static GrGLuint compile_shader(const GrGLContext* ctx) { const char* version = GrGLGetGLSLVersionDecl(*ctx); // setup vertex shader GrGLShaderVar aPosition("a_position", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); GrGLShaderVar aColor("a_color", kVec3f_GrSLType, GrShaderVar::kAttribute_TypeModifier); GrGLShaderVar oColor("o_color", kVec3f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier); SkString vshaderTxt(version); aPosition.appendDecl(*ctx, &vshaderTxt); vshaderTxt.append(";\n"); aColor.appendDecl(*ctx, &vshaderTxt); vshaderTxt.append(";\n"); oColor.appendDecl(*ctx, &vshaderTxt); vshaderTxt.append(";\n"); vshaderTxt.append( "void main()\n" "{\n" "gl_Position = vec4(a_position, 0.f, 1.f);\n" "o_color = a_color;\n" "}\n"); const GrGLInterface* gl = ctx->interface(); GrGLuint vertexShader = load_shader(gl, vshaderTxt.c_str(), GR_GL_VERTEX_SHADER); // setup fragment shader GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier); SkString fshaderTxt(version); GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, gl->fStandard, &fshaderTxt); oColor.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); oColor.appendDecl(*ctx, &fshaderTxt); fshaderTxt.append(";\n"); const char* fsOutName; if (ctx->caps()->glslCaps()->mustDeclareFragmentShaderOutput()) { oFragColor.appendDecl(*ctx, &fshaderTxt); fshaderTxt.append(";\n"); fsOutName = oFragColor.c_str(); } else { fsOutName = "gl_FragColor"; } fshaderTxt.appendf( "void main()\n" "{\n" "%s = vec4(o_color, 1.0f);\n" "}\n", fsOutName); GrGLuint fragmentShader = load_shader(gl, fshaderTxt.c_str(), GR_GL_FRAGMENT_SHADER); GrGLint shaderProgram; GR_GL_CALL_RET(gl, shaderProgram, CreateProgram()); GR_GL_CALL(gl, AttachShader(shaderProgram, vertexShader)); GR_GL_CALL(gl, AttachShader(shaderProgram, fragmentShader)); GR_GL_CALL(gl, LinkProgram(shaderProgram)); // Check for linking errors GrGLint success; GrGLchar infoLog[512]; GR_GL_CALL(gl, GetProgramiv(shaderProgram, GR_GL_LINK_STATUS, &success)); if (!success) { GR_GL_CALL(gl, GetProgramInfoLog(shaderProgram, 512, NULL, infoLog)); SkDebugf("Linker Error: %s\n", infoLog); } GR_GL_CALL(gl, DeleteShader(vertexShader)); GR_GL_CALL(gl, DeleteShader(fragmentShader)); return shaderProgram; }
void GrGLPath::InitPathObject(GrGLGpu* gpu, GrGLuint pathID, const SkPath& skPath, const GrStrokeInfo& stroke) { SkASSERT(!stroke.isDashed()); if (!skPath.isEmpty()) { int verbCnt = skPath.countVerbs(); int pointCnt = skPath.countPoints(); int minCoordCnt = pointCnt * 2; SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt); SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt); SkDEBUGCODE(int numCoords = 0); if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) { // This branch does type punning, converting SkPoint* to GrGLfloat*. SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, sk_point_not_two_floats); // This branch does not convert with SkScalarToFloat. #ifndef SK_SCALAR_IS_FLOAT #error Need SK_SCALAR_IS_FLOAT. #endif pathCommands.resize_back(verbCnt); pathCoords.resize_back(minCoordCnt); skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt); skPath.getVerbs(&pathCommands[0], verbCnt); for (int i = 0; i < verbCnt; ++i) { SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]); pathCommands[i] = verb_to_gl_path_cmd(v); SkDEBUGCODE(numCoords += num_coords(v)); } } else { SkPoint points[4]; SkPath::RawIter iter(skPath); SkPath::Verb verb; while ((verb = iter.next(points)) != SkPath::kDone_Verb) { pathCommands.push_back(verb_to_gl_path_cmd(verb)); GrGLfloat coords[6]; int coordsForVerb; switch (verb) { case SkPath::kMove_Verb: points_to_coords(points, 0, 1, coords); coordsForVerb = 2; break; case SkPath::kLine_Verb: points_to_coords(points, 1, 1, coords); coordsForVerb = 2; break; case SkPath::kConic_Verb: points_to_coords(points, 1, 2, coords); coords[4] = SkScalarToFloat(iter.conicWeight()); coordsForVerb = 5; break; case SkPath::kQuad_Verb: points_to_coords(points, 1, 2, coords); coordsForVerb = 4; break; case SkPath::kCubic_Verb: points_to_coords(points, 1, 3, coords); coordsForVerb = 6; break; case SkPath::kClose_Verb: continue; default: SkASSERT(false); // Not reached. continue; } SkDEBUGCODE(numCoords += num_coords(verb)); pathCoords.push_back_n(coordsForVerb, coords); } } SkASSERT(verbCnt == pathCommands.count()); SkASSERT(numCoords == pathCoords.count()); GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0], pathCoords.count(), GR_GL_FLOAT, &pathCoords[0])); } else { GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, NULL, 0, GR_GL_FLOAT, NULL)); } if (stroke.needToApply()) { SkASSERT(!stroke.isHairlineStyle()); GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth()))); GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter()))); GrGLenum join = join_to_gl_join(stroke.getJoin()); GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join)); GrGLenum cap = cap_to_gl_cap(stroke.getCap()); GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap)); GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f)); } }
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EGLImageTest, reporter, context0, glCtx0) { // Try to create a second GL context and then check if the contexts have necessary // extensions to run this test. if (kGLES_GrGLStandard != glCtx0->gl()->fStandard) { return; } GrGLGpu* gpu0 = static_cast<GrGLGpu*>(context0->getGpu()); if (!gpu0->glCaps().glslCaps()->externalTextureSupport()) { return; } SkAutoTDelete<SkGLContext> glCtx1 = glCtx0->createNew(); if (!glCtx1) { return; } GrContext* context1 = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)glCtx1->gl()); const GrGLTextureInfo* backendTexture1 = nullptr; GrEGLImage image = GR_EGL_NO_IMAGE; GrGLTextureInfo externalTexture; externalTexture.fID = 0; if (!context1) { cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image); return; } if (!glCtx1->gl()->hasExtension("EGL_KHR_image") || !glCtx1->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) { cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image); return; } ///////////////////////////////// CONTEXT 1 /////////////////////////////////// // Use GL Context 1 to create a texture unknown to GrContext. context1->flush(); GrGpu* gpu1 = context1->getGpu(); static const int kSize = 100; backendTexture1 = reinterpret_cast<const GrGLTextureInfo*>( gpu1->createTestingOnlyBackendTexture(nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig)); if (!backendTexture1 || !backendTexture1->fID) { ERRORF(reporter, "Error creating texture for EGL Image"); cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image); return; } if (GR_GL_TEXTURE_2D != backendTexture1->fTarget) { ERRORF(reporter, "Expected backend texture to be 2D"); cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image); return; } // Wrap the texture in an EGLImage image = glCtx1->texture2DToEGLImage(backendTexture1->fID); if (GR_EGL_NO_IMAGE == image) { ERRORF(reporter, "Error creating EGL Image from texture"); cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image); return; } // Populate the texture using GL context 1. Important to use TexSubImage as TexImage orphans // the EGL image. Also, this must be done after creating the EGLImage as the texture // contents may not be preserved when the image is created. SkAutoTMalloc<uint32_t> pixels(kSize * kSize); for (int i = 0; i < kSize*kSize; ++i) { pixels.get()[i] = 0xDDAABBCC; } GR_GL_CALL(glCtx1->gl(), ActiveTexture(GR_GL_TEXTURE0)); GR_GL_CALL(glCtx1->gl(), BindTexture(backendTexture1->fTarget, backendTexture1->fID)); GR_GL_CALL(glCtx1->gl(), TexSubImage2D(backendTexture1->fTarget, 0, 0, 0, kSize, kSize, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels.get())); GR_GL_CALL(glCtx1->gl(), Finish()); // We've been making direct GL calls in GL context 1, let GrContext 1 know its internal // state is invalid. context1->resetContext(); ///////////////////////////////// CONTEXT 0 /////////////////////////////////// // Make a new texture ID in GL Context 0 from the EGL Image glCtx0->makeCurrent(); externalTexture.fTarget = GR_GL_TEXTURE_EXTERNAL; externalTexture.fID = glCtx0->eglImageToExternalTexture(image); // Wrap this texture ID in a GrTexture GrBackendTextureDesc externalDesc; externalDesc.fConfig = kRGBA_8888_GrPixelConfig; externalDesc.fWidth = kSize; externalDesc.fHeight = kSize; externalDesc.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture); SkAutoTUnref<GrTexture> externalTextureObj( context0->textureProvider()->wrapBackendTexture(externalDesc)); if (!externalTextureObj) { ERRORF(reporter, "Error wrapping external texture in GrTexture."); cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image); return; } // Should not be able to wrap as a RT externalDesc.fFlags = kRenderTarget_GrBackendTextureFlag; SkAutoTUnref<GrTexture> externalTextureRTObj( context0->textureProvider()->wrapBackendTexture(externalDesc)); if (externalTextureRTObj) { ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture as a RT."); } externalDesc.fFlags = kNone_GrBackendTextureFlag; // Should not be able to wrap with a sample count externalDesc.fSampleCnt = 4; SkAutoTUnref<GrTexture> externalTextureMSAAObj( context0->textureProvider()->wrapBackendTexture(externalDesc)); if (externalTextureMSAAObj) { ERRORF(reporter, "Should not be able to wrap an EXTERNAL texture with MSAA."); } externalDesc.fSampleCnt = 0; test_read_pixels(reporter, context0, externalTextureObj, pixels.get()); test_write_pixels(reporter, context0, externalTextureObj); test_copy_surface(reporter, context0, externalTextureObj, pixels.get()); cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image); }
void SkANGLEGLContext::destroyEGLImage(GrEGLImage image) const { GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image)); }
void GLCpuPosInstancedArraysBench::setupInstanceVbo(const GrGLInterface* gl, const SkMatrix* viewMatrices) { // We draw all of the instances at a single place because we aren't allowed to have per vertex // per instance attributes SkPoint positions[kVerticesPerTri]; positions[0].set(-1.0f, -1.0f); positions[1].set( 1.0f, -1.0f); positions[2].set( 1.0f, 1.0f); viewMatrices[0].mapPointsWithStride(positions, sizeof(SkPoint), kVerticesPerTri); // setup colors so we can detect we are actually drawing instances(the last triangle will be // a different color) GrGLfloat colors[kVerticesPerTri * kNumTri]; for (uint32_t i = 0; i < kNumTri; i++) { // set colors uint32_t offset = i * kVerticesPerTri; float color = i == kNumTri - 1 ? 1.0f : 0.0f; colors[offset++] = color; colors[offset++] = 0.0f; colors[offset++] = 0.0f; } GrGLuint posVBO; // setup position VBO GR_GL_CALL(gl, GenBuffers(1, &posVBO)); GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, posVBO)); GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(positions), positions, GR_GL_STATIC_DRAW)); GR_GL_CALL(gl, EnableVertexAttribArray(0)); GR_GL_CALL(gl, VertexAttribPointer(0, 2, GR_GL_FLOAT, GR_GL_FALSE, 2 * sizeof(GrGLfloat), (GrGLvoid*)0)); // setup color VBO GrGLuint instanceVBO; GR_GL_CALL(gl, GenBuffers(1, &instanceVBO)); GR_GL_CALL(gl, BindBuffer(GR_GL_ARRAY_BUFFER, instanceVBO)); GR_GL_CALL(gl, BufferData(GR_GL_ARRAY_BUFFER, sizeof(colors), colors, GR_GL_STATIC_DRAW)); GR_GL_CALL(gl, EnableVertexAttribArray(1)); GR_GL_CALL(gl, VertexAttribPointer(1, 3, GR_GL_FLOAT, GR_GL_FALSE, 3 * sizeof(GrGLfloat), (GrGLvoid*)0)); GR_GL_CALL(gl, VertexAttribDivisor(1, 1)); fBuffers.push_back(posVBO); fBuffers.push_back(instanceVBO); }
static void setup_framebuffer(const GrGLInterface* gl, int screenWidth, int screenHeight) { //Setup framebuffer GrGLuint texture; GR_GL_CALL(gl, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); GR_GL_CALL(gl, PixelStorei(GR_GL_PACK_ROW_LENGTH, 0)); GR_GL_CALL(gl, GenTextures(1, &texture)); GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE15)); GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, texture)); GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST)); GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST)); GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE)); GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE)); GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, //level GR_GL_RGBA8, //internal format screenWidth, // width screenHeight, // height 0, //border GR_GL_RGBA, //format GR_GL_UNSIGNED_BYTE, // type NULL)); // bind framebuffer GrGLuint framebuffer; GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); GR_GL_CALL(gl, GenFramebuffers(1, &framebuffer)); GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, framebuffer)); GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D, texture, 0)); GR_GL_CALL(gl, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); GR_GL_CALL(gl, Viewport(0, 0, screenWidth, screenHeight)); }
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(RectangleTexture, reporter, ctxInfo) { GrContext* context = ctxInfo.grContext(); GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); sk_gpu_test::GLTestContext* glContext = ctxInfo.glContext(); static const int kWidth = 13; static const int kHeight = 13; GrColor pixels[kWidth * kHeight]; for (int y = 0; y < kHeight; ++y) { for (int x = 0; x < kWidth; ++x) { pixels[y * kWidth + x] = y * kWidth + x; } } for (auto origin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) { bool useBLOrigin = kBottomLeft_GrSurfaceOrigin == origin; GrGLuint rectTexID = glContext->createTextureRectangle(kWidth, kHeight, GR_GL_RGBA, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels); if (!rectTexID) { return; } // Let GrContext know that we messed with the GL context directly. context->resetContext(); // Wrap the rectangle texture ID in a GrTexture GrGLTextureInfo rectangleInfo; rectangleInfo.fID = rectTexID; rectangleInfo.fTarget = GR_GL_TEXTURE_RECTANGLE; GrBackendTexture rectangleTex(kWidth, kHeight, kRGBA_8888_GrPixelConfig, rectangleInfo); GrColor refPixels[kWidth * kHeight]; for (int y = 0; y < kHeight; ++y) { for (int x = 0; x < kWidth; ++x) { int y0 = useBLOrigin ? kHeight - y - 1 : y; refPixels[y * kWidth + x] = pixels[y0 * kWidth + x]; } } sk_sp<GrTextureProxy> rectProxy = proxyProvider->wrapBackendTexture(rectangleTex, origin); if (!rectProxy) { ERRORF(reporter, "Error creating proxy for rectangle texture."); GR_GL_CALL(glContext->gl(), DeleteTextures(1, &rectTexID)); continue; } SkASSERT(rectProxy->texPriv().doesNotSupportMipMaps()); SkASSERT(rectProxy->priv().peekTexture()->surfacePriv().doesNotSupportMipMaps()); SkASSERT(rectProxy->texPriv().isClampOnly()); SkASSERT(rectProxy->priv().peekTexture()->surfacePriv().isClampOnly()); test_basic_draw_as_src(reporter, context, rectProxy, refPixels); // Test copy to both a texture and RT test_copy_from_surface(reporter, context, rectProxy.get(), refPixels, false, "RectangleTexture-copy-from"); sk_sp<GrSurfaceContext> rectContext = context->contextPriv().makeWrappedSurfaceContext( std::move(rectProxy)); SkASSERT(rectContext); test_read_pixels(reporter, rectContext.get(), refPixels, "RectangleTexture-read"); test_copy_to_surface(reporter, context->contextPriv().proxyProvider(), rectContext.get(), "RectangleTexture-copy-to"); test_write_pixels(reporter, rectContext.get(), true, "RectangleTexture-write"); test_clear(reporter, rectContext.get()); GR_GL_CALL(glContext->gl(), DeleteTextures(1, &rectTexID)); } }