Chromium Code Reviews| Index: src/gpu/gl/GrGLGpu.cpp |
| diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp |
| index 96b1625dd21f297fb5a8f1a22266d67eaa6a17fc..6cdc31fc008856381f12892626715539376fc6d1 100644 |
| --- a/src/gpu/gl/GrGLGpu.cpp |
| +++ b/src/gpu/gl/GrGLGpu.cpp |
| @@ -12,6 +12,7 @@ |
| #include "GrGLTextureRenderTarget.h" |
| #include "GrGpuResourcePriv.h" |
| #include "GrPipeline.h" |
| +#include "GrPLSGeometryProcessor.h" |
| #include "GrRenderTargetPriv.h" |
| #include "GrSurfacePriv.h" |
| #include "GrTexturePriv.h" |
| @@ -20,6 +21,7 @@ |
| #include "builders/GrGLShaderStringBuilder.h" |
| #include "glsl/GrGLSL.h" |
| #include "glsl/GrGLSLCaps.h" |
| +#include "glsl/GrGLSLPLSPathRendering.h" |
| #include "SkStrokeRec.h" |
| #include "SkTemplates.h" |
| @@ -38,7 +40,6 @@ |
| #define CHECK_ALLOC_ERROR(iface) GR_GL_NO_ERROR |
| #endif |
| - |
| /////////////////////////////////////////////////////////////////////////////// |
| @@ -224,6 +225,13 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) |
| this->createCopyPrograms(); |
| fWireRectProgram.fProgram = 0; |
| fWireRectArrayBuffer = 0; |
| + if (this->glCaps().shaderCaps()->plsPathRenderingSupport()) { |
| + this->createPLSSetupProgram(); |
| + } |
| + else { |
| + memset(&fPLSSetupProgram, 0, sizeof(fPLSSetupProgram)); |
| + } |
| + fHWPLSEnabled = false; |
| } |
| GrGLGpu::~GrGLGpu() { |
| @@ -265,9 +273,106 @@ GrGLGpu::~GrGLGpu() { |
| GL_CALL(DeleteBuffers(1, &fWireRectArrayBuffer)); |
| } |
| + if (0 != fPLSSetupProgram.fArrayBuffer) { |
| + GL_CALL(DeleteBuffers(1, &fPLSSetupProgram.fArrayBuffer)); |
| + } |
| + |
| + if (0 != fPLSSetupProgram.fProgram) { |
| + GL_CALL(DeleteProgram(fPLSSetupProgram.fProgram)); |
| + } |
| + |
| delete fProgramCache; |
| } |
| +void GrGLGpu::createPLSSetupProgram() { |
| + const char* version = this->glCaps().glslCaps()->versionDeclString(); |
| + |
| + GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); |
| + GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, |
| + GrShaderVar::kUniform_TypeModifier); |
| + GrGLSLShaderVar uPosXform("u_posXform", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); |
| + GrGLSLShaderVar uTexture("u_texture", kSampler2D_GrSLType, GrShaderVar::kUniform_TypeModifier); |
| + GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier); |
| + |
| + SkString vshaderTxt(version); |
| + aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); |
| + vshaderTxt.append(";"); |
| + uTexCoordXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); |
| + vshaderTxt.append(";"); |
| + uPosXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); |
| + vshaderTxt.append(";"); |
| + vTexCoord.appendDecl(this->glCaps().glslCaps(), &vshaderTxt); |
| + vshaderTxt.append(";"); |
| + |
| + vshaderTxt.append( |
| + "// PLS Setup Program VS\n" |
| + "void main() {" |
| + " gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;" |
| + " gl_Position.zw = vec2(0, 1);" |
| + "}" |
| + ); |
| + |
| + SkString fshaderTxt(version); |
| + fshaderTxt.append("#extension "); |
| + fshaderTxt.append(this->glCaps().glslCaps()->fbFetchExtensionString()); |
| + fshaderTxt.append(" : require\n"); |
| + fshaderTxt.append("#extension GL_EXT_shader_pixel_local_storage : require\n"); |
| + GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, |
| + *this->glCaps().glslCaps(), |
| + &fshaderTxt); |
| + vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier); |
| + vTexCoord.appendDecl(this->glCaps().glslCaps(), &fshaderTxt); |
| + fshaderTxt.append(";"); |
| + uTexture.appendDecl(this->glCaps().glslCaps(), &fshaderTxt); |
| + fshaderTxt.append(";"); |
| + |
| + fshaderTxt.appendf( |
| + "// PLS Setup Program FS\n" |
| + PLS_PATH_DATA_DECL |
| + "void main() {\n" |
| + " " PLS_DSTCOLOR_NAME " = gl_LastFragColorARM;\n" |
| + " pls.windings = ivec4(0, 0, 0, 0);\n" |
| + "}" |
| + ); |
| + GL_CALL_RET(fPLSSetupProgram.fProgram, CreateProgram()); |
| + const char* str; |
| + GrGLint length; |
| + |
| + str = vshaderTxt.c_str(); |
| + length = SkToInt(vshaderTxt.size()); |
| + GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram, |
| + GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats); |
| + |
| + str = fshaderTxt.c_str(); |
| + length = SkToInt(fshaderTxt.size()); |
| + GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram, |
| + GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats); |
| + |
| + GL_CALL(LinkProgram(fPLSSetupProgram.fProgram)); |
| + |
| + GL_CALL_RET(fPLSSetupProgram.fPosXformUniform, GetUniformLocation(fPLSSetupProgram.fProgram, |
| + "u_posXform")); |
| + |
| + GL_CALL(BindAttribLocation(fPLSSetupProgram.fProgram, 0, "a_vertex")); |
| + |
| + GL_CALL(DeleteShader(vshader)); |
| + GL_CALL(DeleteShader(fshader)); |
| + |
| + GL_CALL(GenBuffers(1, &fPLSSetupProgram.fArrayBuffer)); |
| + fHWGeometryState.setVertexBufferID(this, fPLSSetupProgram.fArrayBuffer); |
| + static const GrGLfloat vdata[] = { |
| + 0, 0, |
| + 0, 1, |
| + 1, 0, |
| + 1, 1 |
| + }; |
| + GL_ALLOC_CALL(this->glInterface(), |
| + BufferData(GR_GL_ARRAY_BUFFER, |
| + (GrGLsizeiptr) sizeof(vdata), |
| + vdata, // data ptr |
| + GR_GL_STATIC_DRAW)); |
| +} |
| + |
| void GrGLGpu::contextAbandoned() { |
| INHERITED::contextAbandoned(); |
| fProgramCache->abandon(); |
| @@ -2145,8 +2250,29 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, |
| return true; |
| } |
| -void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) { |
| +void GrGLGpu::performFlushWorkaround() { |
| + if (this->glCaps().shaderCaps()->plsPathRenderingSupport() && fMSAAEnabled == kNo_TriState) { |
|
bsalomon
2016/01/20 18:27:31
Why the fMSAAEnabled check here?
ethannicholas
2016/01/20 22:25:04
Enabling PLS in the presence of MSAA leads to GL_I
|
| + /* There is an ARM driver bug where if we use PLS, and then draw a frame which does not |
| + * use PLS, it leaves garbage all over the place. As a workaround, we use PLS in a |
| + * trivial way every frame. |
| + */ |
| + if (kYes_TriState == fHWScissorSettings.fEnabled) { |
|
bsalomon
2016/01/20 18:27:31
Probably better to just call this->disableScissor(
|
| + GL_CALL(Disable(GR_GL_SCISSOR_TEST)); |
| + } |
| + SkASSERT(!fHWPLSEnabled); |
| + GL_CALL(Enable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); |
| + this->stampRectUsingProgram(fPLSSetupProgram.fProgram, |
| + SkRect::MakeXYWH(-100.0f, -100.0f, 0.01f, 0.01f), |
| + fPLSSetupProgram.fPosXformUniform, |
| + fPLSSetupProgram.fArrayBuffer); |
| + GL_CALL(Disable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); |
| + if (kYes_TriState == fHWScissorSettings.fEnabled) { |
| + GL_CALL(Enable(GR_GL_SCISSOR_TEST)); |
| + } |
| + } |
| +} |
| +void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) { |
| SkASSERT(target); |
| uint32_t rtID = target->getUniqueID(); |
| @@ -2229,6 +2355,19 @@ void GrGLGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertice |
| return; |
| } |
| + GrPixelLocalStorageState plsState = args.fPrimitiveProcessor->getPixelLocalStorageState(); |
| + if (!fHWPLSEnabled && plsState != |
| + GrPixelLocalStorageState::kDisabled_GrPixelLocalStorageState) { |
| + GL_CALL(Enable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); |
| + this->setupPixelLocalStorage(args); |
| + fHWPLSEnabled = true; |
| + } |
| + if (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState) { |
| + GrStencilSettings stencil; |
| + stencil.setDisabled(); |
| + this->flushStencil(stencil); |
| + } |
| + |
| size_t indexOffsetInBytes = 0; |
| this->setupGeometry(*args.fPrimitiveProcessor, vertices, &indexOffsetInBytes); |
| @@ -2250,6 +2389,16 @@ void GrGLGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertice |
| GL_CALL(DrawArrays(gPrimitiveType2GLMode[vertices.primitiveType()], 0, |
| vertices.vertexCount())); |
| } |
| + |
| + if (fHWPLSEnabled && plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState) { |
| + // PLS draws always involve multiple draws, finishing up with a non-PLS |
| + // draw that writes to the color buffer. That draw ends up here; we wait |
| + // until after it is complete to actually disable PLS. |
| + GL_CALL(Disable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); |
| + fHWPLSEnabled = false; |
| + this->disableScissor(); |
| + } |
| + |
| #if SWAP_PER_DRAW |
| glFlush(); |
| #if defined(SK_BUILD_FOR_MAC) |
| @@ -2264,6 +2413,56 @@ void GrGLGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertice |
| #endif |
| } |
| +void GrGLGpu::stampRectUsingProgram(GrGLuint program, const SkRect& bounds, GrGLint posXformUniform, |
| + GrGLuint arrayBuffer) { |
| + GL_CALL(UseProgram(program)); |
| + this->fHWGeometryState.setVertexArrayID(this, 0); |
| + |
| + GrGLAttribArrayState* attribs = |
| + this->fHWGeometryState.bindArrayAndBufferToDraw(this, arrayBuffer); |
| + attribs->set(this, 0, arrayBuffer, 2, GR_GL_FLOAT, false, 2 * sizeof(GrGLfloat), 0); |
| + attribs->disableUnusedArrays(this, 0x1); |
| + |
| + GL_CALL(Uniform4f(posXformUniform, bounds.width(), bounds.height(), bounds.left(), |
| + bounds.top())); |
| + |
| + GrXferProcessor::BlendInfo blendInfo; |
| + blendInfo.reset(); |
| + this->flushBlend(blendInfo, GrSwizzle()); |
| + this->flushColorWrite(true); |
| + this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace); |
| + if (!fHWStencilSettings.isDisabled()) { |
| + GL_CALL(Disable(GR_GL_STENCIL_TEST)); |
| + } |
| + GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); |
| + GL_CALL(UseProgram(fHWProgramID)); |
| + if (!fHWStencilSettings.isDisabled()) { |
| + GL_CALL(Enable(GR_GL_STENCIL_TEST)); |
| + } |
| +} |
| + |
| +void GrGLGpu::setupPixelLocalStorage(const DrawArgs& args) { |
| + const SkRect& bounds = |
| + static_cast<const GrPLSGeometryProcessor*>(args.fPrimitiveProcessor)->getBounds(); |
| + // setup pixel local storage -- this means capturing and storing the current framebuffer color |
| + // and initializing the winding counts to zero |
| + GrRenderTarget* rt = args.fPipeline->getRenderTarget(); |
| + SkScalar width = rt->width(); |
| + SkScalar height = rt->height(); |
| + // dst rect edges in NDC (-1 to 1) |
| + // having some issues with rounding, just expand the bounds by 1 and trust the scissor to keep |
| + // it contained properly |
| + GrGLfloat dx0 = 2.0f * (bounds.left() - 1) / width - 1.0f; |
| + GrGLfloat dx1 = 2.0f * (bounds.right() + 1) / width - 1.0f; |
| + GrGLfloat dy0 = -2.0f * (bounds.top() - 1) / height + 1.0f; |
| + GrGLfloat dy1 = -2.0f * (bounds.bottom() + 1) / height + 1.0f; |
| + SkRect deviceBounds = SkRect::MakeXYWH(dx0, dy0, dx1 - dx0, dy1 - dy0); |
| + |
| + GL_CALL(Enable(GR_GL_FETCH_PER_SAMPLE_ARM)); |
| + this->stampRectUsingProgram(fPLSSetupProgram.fProgram, deviceBounds, |
| + fPLSSetupProgram.fPosXformUniform, fPLSSetupProgram.fArrayBuffer); |
| +} |
| + |
| void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) { |
| GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target); |
| if (rt->needsResolve()) { |