| Index: src/gpu/gl/GrGLGpu.cpp
|
| diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
|
| index 6d97804fc65ffa52ddf350c58cd9d6f2b0232723..56b3d42c4fabd05878b6edf03dd0fcba91d50482 100644
|
| --- a/src/gpu/gl/GrGLGpu.cpp
|
| +++ b/src/gpu/gl/GrGLGpu.cpp
|
| @@ -17,6 +17,7 @@
|
| #include "GrTexturePriv.h"
|
| #include "GrTypes.h"
|
| #include "GrVertices.h"
|
| +#include "builders/GrGLShaderStringBuilder.h"
|
| #include "SkStrokeRec.h"
|
| #include "SkTemplates.h"
|
|
|
| @@ -200,13 +201,14 @@ GrGLGpu::GrGLGpu(const GrGLContext& ctx, GrContext* context)
|
| if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
|
| fPathRendering.reset(new GrGLPathRendering(this));
|
| }
|
| +
|
| + this->createCopyProgram();
|
| }
|
|
|
| GrGLGpu::~GrGLGpu() {
|
| if (0 != fHWProgramID) {
|
| // detach the current program so there is no confusion on OpenGL's part
|
| // that we want it to be deleted
|
| - SkASSERT(fHWProgramID == fCurrentProgram->programID());
|
| GL_CALL(UseProgram(0));
|
| }
|
|
|
| @@ -220,6 +222,14 @@ GrGLGpu::~GrGLGpu() {
|
| GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID));
|
| }
|
|
|
| + if (0 != fCopyProgram.fArrayBuffer) {
|
| + GL_CALL(DeleteBuffers(1, &fCopyProgram.fArrayBuffer));
|
| + }
|
| +
|
| + if (0 != fCopyProgram.fProgram) {
|
| + GL_CALL(DeleteProgram(fCopyProgram.fProgram));
|
| + }
|
| +
|
| delete fProgramCache;
|
| }
|
|
|
| @@ -230,6 +240,8 @@ void GrGLGpu::contextAbandoned() {
|
| fTempSrcFBOID = 0;
|
| fTempDstFBOID = 0;
|
| fStencilClearFBOID = 0;
|
| + fCopyProgram.fArrayBuffer = 0;
|
| + fCopyProgram.fProgram = 0;
|
| if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
|
| this->glPathRendering()->abandonGpuResources();
|
| }
|
| @@ -1417,15 +1429,13 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) {
|
| this->flushColorWrite(blendInfo.fWriteColor);
|
| this->flushDrawFace(pipeline.getDrawFace());
|
|
|
| - fCurrentProgram.reset(fProgramCache->getProgram(args));
|
| - if (NULL == fCurrentProgram.get()) {
|
| + SkAutoTUnref<GrGLProgram> program(fProgramCache->refProgram(args));
|
| + if (!program) {
|
| GrContextDebugf(this->getContext(), "Failed to create program!\n");
|
| return false;
|
| }
|
|
|
| - fCurrentProgram.get()->ref();
|
| -
|
| - GrGLuint programID = fCurrentProgram->programID();
|
| + GrGLuint programID = program->programID();
|
| if (fHWProgramID != programID) {
|
| GL_CALL(UseProgram(programID));
|
| fHWProgramID = programID;
|
| @@ -1435,7 +1445,7 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) {
|
| this->flushBlend(blendInfo);
|
| }
|
|
|
| - fCurrentProgram->setData(*args.fPrimitiveProcessor, pipeline, *args.fBatchTracker);
|
| + program->setData(*args.fPrimitiveProcessor, pipeline, *args.fBatchTracker);
|
|
|
| GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
|
| this->flushStencil(pipeline.getStencil());
|
| @@ -1490,7 +1500,7 @@ void GrGLGpu::setupGeometry(const GrPrimitiveProcessor& primProc,
|
| GrVertexAttribType attribType = attrib.fType;
|
| attribState->set(this,
|
| attribIndex,
|
| - vbuf,
|
| + vbuf->bufferID(),
|
| GrGLAttribTypeToLayout(attribType).fCount,
|
| GrGLAttribTypeToLayout(attribType).fType,
|
| GrGLAttribTypeToLayout(attribType).fNormalized,
|
| @@ -2618,7 +2628,16 @@ void GrGLGpu::unbindTextureFromFBO(GrGLenum fboTarget) {
|
| }
|
|
|
| bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) {
|
| - // In here we look for opportunities to use CopyTexSubImage, or fbo blit. If neither are
|
| + // If the src is a texture, we can implement the blit as a draw assuming the config is
|
| + // renderable.
|
| + if (src->asTexture() && this->caps()->isConfigRenderable(src->config(), false)) {
|
| + desc->fOrigin = kDefault_GrSurfaceOrigin;
|
| + desc->fFlags = kRenderTarget_GrSurfaceFlag;
|
| + desc->fConfig = src->config();
|
| + return true;
|
| + }
|
| +
|
| + // We look for opportunities to use CopyTexSubImage, or fbo blit. If neither are
|
| // possible and we return false to fallback to creating a render target dst for render-to-
|
| // texture. This code prefers CopyTexSubImage to fbo blit and avoids triggering temporary fbo
|
| // creation. It isn't clear that avoiding temporary fbo creation is actually optimal.
|
| @@ -2664,129 +2683,297 @@ bool GrGLGpu::copySurface(GrSurface* dst,
|
| GrSurface* src,
|
| const SkIRect& srcRect,
|
| const SkIPoint& dstPoint) {
|
| - bool copied = false;
|
| - if (can_copy_texsubimage(dst, src, this)) {
|
| - GrGLuint srcFBO;
|
| - GrGLIRect srcVP;
|
| - srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget);
|
| - GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
|
| - SkASSERT(dstTex);
|
| - // We modified the bound FBO
|
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
|
| - GrGLIRect srcGLRect;
|
| - srcGLRect.setRelativeTo(srcVP,
|
| - srcRect.fLeft,
|
| - srcRect.fTop,
|
| - srcRect.width(),
|
| - srcRect.height(),
|
| - src->origin());
|
| -
|
| - this->setScratchTextureUnit();
|
| - GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID()));
|
| - GrGLint dstY;
|
| - if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
|
| - dstY = dst->height() - (dstPoint.fY + srcGLRect.fHeight);
|
| - } else {
|
| - dstY = dstPoint.fY;
|
| - }
|
| - GL_CALL(CopyTexSubImage2D(GR_GL_TEXTURE_2D, 0,
|
| - dstPoint.fX, dstY,
|
| - srcGLRect.fLeft, srcGLRect.fBottom,
|
| - srcGLRect.fWidth, srcGLRect.fHeight));
|
| - copied = true;
|
| - if (srcFBO) {
|
| - this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER);
|
| - }
|
| - } else if (can_blit_framebuffer(dst, src, this)) {
|
| - SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
|
| - srcRect.width(), srcRect.height());
|
| - bool selfOverlap = false;
|
| - if (dst == src) {
|
| - selfOverlap = SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect);
|
| - }
|
| -
|
| - if (!selfOverlap) {
|
| - GrGLuint dstFBO;
|
| - GrGLuint srcFBO;
|
| - GrGLIRect dstVP;
|
| - GrGLIRect srcVP;
|
| - dstFBO = this->bindSurfaceAsFBO(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP,
|
| - kDst_TempFBOTarget);
|
| - srcFBO = this->bindSurfaceAsFBO(src, GR_GL_READ_FRAMEBUFFER, &srcVP,
|
| - kSrc_TempFBOTarget);
|
| - // We modified the bound FBO
|
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
|
| - GrGLIRect srcGLRect;
|
| - GrGLIRect dstGLRect;
|
| - srcGLRect.setRelativeTo(srcVP,
|
| - srcRect.fLeft,
|
| - srcRect.fTop,
|
| - srcRect.width(),
|
| - srcRect.height(),
|
| - src->origin());
|
| - dstGLRect.setRelativeTo(dstVP,
|
| - dstRect.fLeft,
|
| - dstRect.fTop,
|
| - dstRect.width(),
|
| - dstRect.height(),
|
| - dst->origin());
|
| -
|
| - // BlitFrameBuffer respects the scissor, so disable it.
|
| - this->disableScissor();
|
| -
|
| - GrGLint srcY0;
|
| - GrGLint srcY1;
|
| - // Does the blit need to y-mirror or not?
|
| - if (src->origin() == dst->origin()) {
|
| - srcY0 = srcGLRect.fBottom;
|
| - srcY1 = srcGLRect.fBottom + srcGLRect.fHeight;
|
| - } else {
|
| - srcY0 = srcGLRect.fBottom + srcGLRect.fHeight;
|
| - srcY1 = srcGLRect.fBottom;
|
| - }
|
| - GL_CALL(BlitFramebuffer(srcGLRect.fLeft,
|
| - srcY0,
|
| - srcGLRect.fLeft + srcGLRect.fWidth,
|
| - srcY1,
|
| - dstGLRect.fLeft,
|
| - dstGLRect.fBottom,
|
| - dstGLRect.fLeft + dstGLRect.fWidth,
|
| - dstGLRect.fBottom + dstGLRect.fHeight,
|
| - GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
|
| - if (dstFBO) {
|
| - this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER);
|
| - }
|
| - if (srcFBO) {
|
| - this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER);
|
| - }
|
| - copied = true;
|
| - }
|
| + if (src->asTexture() && dst->asRenderTarget()) {
|
| + this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
|
| + return true;
|
| }
|
| - return copied;
|
| -}
|
| -
|
| -bool GrGLGpu::canCopySurface(const GrSurface* dst,
|
| - const GrSurface* src,
|
| - const SkIRect& srcRect,
|
| - const SkIPoint& dstPoint) {
|
| - // This mirrors the logic in onCopySurface.
|
| +
|
| if (can_copy_texsubimage(dst, src, this)) {
|
| + this->copySurfaceAsCopyTexSubImage(dst, src, srcRect, dstPoint);
|
| return true;
|
| }
|
| +
|
| if (can_blit_framebuffer(dst, src, this)) {
|
| - if (dst == src) {
|
| - SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
|
| - srcRect.width(), srcRect.height());
|
| - if(!SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect)) {
|
| - return true;
|
| - }
|
| - } else {
|
| - return true;
|
| - }
|
| + return this->copySurfaceAsBlitFramebuffer(dst, src, srcRect, dstPoint);
|
| }
|
| +
|
| return false;
|
| }
|
|
|
| +
|
| +void GrGLGpu::createCopyProgram() {
|
| + const char* version = GrGetGLSLVersionDecl(this->ctxInfo());
|
| +
|
| + GrGLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
|
| + GrGLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType,
|
| + GrShaderVar::kUniform_TypeModifier);
|
| + GrGLShaderVar uPosXform("u_posXform", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier);
|
| + GrGLShaderVar uTexture("u_texture", kSampler2D_GrSLType, GrShaderVar::kUniform_TypeModifier);
|
| + GrGLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier);
|
| + GrGLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
|
| +
|
| + SkString vshaderTxt(version);
|
| + aVertex.appendDecl(this->ctxInfo(), &vshaderTxt);
|
| + vshaderTxt.append(";");
|
| + uTexCoordXform.appendDecl(this->ctxInfo(), &vshaderTxt);
|
| + vshaderTxt.append(";");
|
| + uPosXform.appendDecl(this->ctxInfo(), &vshaderTxt);
|
| + vshaderTxt.append(";");
|
| + vTexCoord.appendDecl(this->ctxInfo(), &vshaderTxt);
|
| + vshaderTxt.append(";");
|
| +
|
| + vshaderTxt.append(
|
| + "// Copy Program VS\n"
|
| + "void main() {"
|
| + " v_texCoord = a_vertex.xy * u_texCoordXform.xy + u_texCoordXform.zw;"
|
| + " gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;"
|
| + " gl_Position.zw = vec2(0, 1);"
|
| + "}"
|
| + );
|
| +
|
| + SkString fshaderTxt(version);
|
| + GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, this->glStandard(),
|
| + &fshaderTxt);
|
| + vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
|
| + vTexCoord.appendDecl(this->ctxInfo(), &fshaderTxt);
|
| + fshaderTxt.append(";");
|
| + uTexture.appendDecl(this->ctxInfo(), &fshaderTxt);
|
| + fshaderTxt.append(";");
|
| + const char* fsOutName;
|
| + if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) {
|
| + oFragColor.appendDecl(this->ctxInfo(), &fshaderTxt);
|
| + fshaderTxt.append(";");
|
| + fsOutName = oFragColor.c_str();
|
| + } else {
|
| + fsOutName = "gl_FragColor";
|
| + }
|
| + fshaderTxt.appendf(
|
| + "// Copy Program FS\n"
|
| + "void main() {"
|
| + " %s = %s(u_texture, v_texCoord);"
|
| + "}",
|
| + fsOutName,
|
| + GrGLSLTexture2DFunctionName(kVec2f_GrSLType, this->glslGeneration())
|
| + );
|
| +
|
| + GL_CALL_RET(fCopyProgram.fProgram, CreateProgram());
|
| + const char* str;
|
| + GrGLint length;
|
| +
|
| + str = vshaderTxt.c_str();
|
| + length = SkToInt(vshaderTxt.size());
|
| + GrGLuint vshader = GrGLCompileAndAttachShader(fGLContext, fCopyProgram.fProgram,
|
| + GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats);
|
| +
|
| + str = fshaderTxt.c_str();
|
| + length = SkToInt(fshaderTxt.size());
|
| + GrGLuint fshader = GrGLCompileAndAttachShader(fGLContext, fCopyProgram.fProgram,
|
| + GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats);
|
| +
|
| + GL_CALL(LinkProgram(fCopyProgram.fProgram));
|
| +
|
| + GL_CALL_RET(fCopyProgram.fTextureUniform, GetUniformLocation(fCopyProgram.fProgram,
|
| + "u_texture"));
|
| + GL_CALL_RET(fCopyProgram.fPosXformUniform, GetUniformLocation(fCopyProgram.fProgram,
|
| + "u_posXform"));
|
| + GL_CALL_RET(fCopyProgram.fTexCoordXformUniform, GetUniformLocation(fCopyProgram.fProgram,
|
| + "u_texCoordXform"));
|
| +
|
| + GL_CALL(BindAttribLocation(fCopyProgram.fProgram, 0, "a_vertex"));
|
| +
|
| + GL_CALL(DeleteShader(vshader));
|
| + GL_CALL(DeleteShader(fshader));
|
| +
|
| + GL_CALL(GenBuffers(1, &fCopyProgram.fArrayBuffer));
|
| + fHWGeometryState.setVertexBufferID(this, fCopyProgram.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::copySurfaceAsDraw(GrSurface* dst,
|
| + GrSurface* src,
|
| + const SkIRect& srcRect,
|
| + const SkIPoint& dstPoint) {
|
| + int w = srcRect.width();
|
| + int h = srcRect.height();
|
| +
|
| + GrGLTexture* srcTex = static_cast<GrGLTexture*>(src->asTexture());
|
| + GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
|
| + this->bindTexture(0, params, srcTex);
|
| +
|
| + GrGLRenderTarget* dstRT = static_cast<GrGLRenderTarget*>(dst->asRenderTarget());
|
| + SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
|
| + this->flushRenderTarget(dstRT, &dstRect);
|
| +
|
| + GL_CALL(UseProgram(fCopyProgram.fProgram));
|
| + fHWProgramID = fCopyProgram.fProgram;
|
| +
|
| + fHWGeometryState.setVertexArrayID(this, 0);
|
| +
|
| + GrGLAttribArrayState* attribs =
|
| + fHWGeometryState.bindArrayAndBufferToDraw(this, fCopyProgram.fArrayBuffer);
|
| + attribs->set(this, 0, fCopyProgram.fArrayBuffer, 2, GR_GL_FLOAT, false,
|
| + 2 * sizeof(GrGLfloat), 0);
|
| +
|
| +
|
| + // dst rect edges in NDC (-1 to 1)
|
| + int dw = dst->width();
|
| + int dh = dst->height();
|
| + GrGLfloat dx0 = 2.f * dstPoint.fX / dw - 1.f;
|
| + GrGLfloat dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
|
| + GrGLfloat dy0 = 2.f * dstPoint.fY / dh - 1.f;
|
| + GrGLfloat dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
|
| + if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
|
| + dy0 = -dy0;
|
| + dy1 = -dy1;
|
| + }
|
| +
|
| + // src rect edges in normalized texture space (0 to 1)
|
| + int sw = src->width();
|
| + int sh = src->height();
|
| + GrGLfloat sx0 = (GrGLfloat)srcRect.fLeft / sw;
|
| + GrGLfloat sx1 = (GrGLfloat)(srcRect.fLeft + w) / sw;
|
| + GrGLfloat sy0 = (GrGLfloat)srcRect.fTop / sh;
|
| + GrGLfloat sy1 = (GrGLfloat)(srcRect.fTop + h) / sh;
|
| + if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
|
| + sy0 = 1.f - sy0;
|
| + sy1 = 1.f - sy1;
|
| + }
|
| +
|
| + GL_CALL(Uniform4f(fCopyProgram.fPosXformUniform, dx1 - dx0, dy1 - dy0, dx0, dy0));
|
| + GL_CALL(Uniform4f(fCopyProgram.fTexCoordXformUniform, sx1 - sx0, sy1 - sy0, sx0, sy0));
|
| + GL_CALL(Uniform1i(fCopyProgram.fTextureUniform, 0));
|
| +
|
| + GrXferProcessor::BlendInfo blendInfo;
|
| + blendInfo.reset();
|
| + this->flushBlend(blendInfo);
|
| + this->flushColorWrite(true);
|
| + this->flushDither(false);
|
| + this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
|
| + this->flushHWAAState(dstRT, false);
|
| + this->disableScissor();
|
| + GrStencilSettings stencil;
|
| + stencil.setDisabled();
|
| + this->flushStencil(stencil);
|
| +
|
| + GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4));
|
| +}
|
| +
|
| +void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst,
|
| + GrSurface* src,
|
| + const SkIRect& srcRect,
|
| + const SkIPoint& dstPoint) {
|
| + SkASSERT(can_copy_texsubimage(dst, src, this));
|
| + GrGLuint srcFBO;
|
| + GrGLIRect srcVP;
|
| + srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget);
|
| + GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
|
| + SkASSERT(dstTex);
|
| + // We modified the bound FBO
|
| + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
|
| + GrGLIRect srcGLRect;
|
| + srcGLRect.setRelativeTo(srcVP,
|
| + srcRect.fLeft,
|
| + srcRect.fTop,
|
| + srcRect.width(),
|
| + srcRect.height(),
|
| + src->origin());
|
| +
|
| + this->setScratchTextureUnit();
|
| + GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID()));
|
| + GrGLint dstY;
|
| + if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
|
| + dstY = dst->height() - (dstPoint.fY + srcGLRect.fHeight);
|
| + } else {
|
| + dstY = dstPoint.fY;
|
| + }
|
| + GL_CALL(CopyTexSubImage2D(GR_GL_TEXTURE_2D, 0,
|
| + dstPoint.fX, dstY,
|
| + srcGLRect.fLeft, srcGLRect.fBottom,
|
| + srcGLRect.fWidth, srcGLRect.fHeight));
|
| + if (srcFBO) {
|
| + this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER);
|
| + }
|
| +}
|
| +
|
| +bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst,
|
| + GrSurface* src,
|
| + const SkIRect& srcRect,
|
| + const SkIPoint& dstPoint) {
|
| + SkASSERT(can_blit_framebuffer(dst, src, this));
|
| + SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
|
| + srcRect.width(), srcRect.height());
|
| + if (dst == src) {
|
| + if (SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect)) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + GrGLuint dstFBO;
|
| + GrGLuint srcFBO;
|
| + GrGLIRect dstVP;
|
| + GrGLIRect srcVP;
|
| + dstFBO = this->bindSurfaceAsFBO(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP,
|
| + kDst_TempFBOTarget);
|
| + srcFBO = this->bindSurfaceAsFBO(src, GR_GL_READ_FRAMEBUFFER, &srcVP,
|
| + kSrc_TempFBOTarget);
|
| + // We modified the bound FBO
|
| + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
|
| + GrGLIRect srcGLRect;
|
| + GrGLIRect dstGLRect;
|
| + srcGLRect.setRelativeTo(srcVP,
|
| + srcRect.fLeft,
|
| + srcRect.fTop,
|
| + srcRect.width(),
|
| + srcRect.height(),
|
| + src->origin());
|
| + dstGLRect.setRelativeTo(dstVP,
|
| + dstRect.fLeft,
|
| + dstRect.fTop,
|
| + dstRect.width(),
|
| + dstRect.height(),
|
| + dst->origin());
|
| +
|
| + // BlitFrameBuffer respects the scissor, so disable it.
|
| + this->disableScissor();
|
| +
|
| + GrGLint srcY0;
|
| + GrGLint srcY1;
|
| + // Does the blit need to y-mirror or not?
|
| + if (src->origin() == dst->origin()) {
|
| + srcY0 = srcGLRect.fBottom;
|
| + srcY1 = srcGLRect.fBottom + srcGLRect.fHeight;
|
| + } else {
|
| + srcY0 = srcGLRect.fBottom + srcGLRect.fHeight;
|
| + srcY1 = srcGLRect.fBottom;
|
| + }
|
| + GL_CALL(BlitFramebuffer(srcGLRect.fLeft,
|
| + srcY0,
|
| + srcGLRect.fLeft + srcGLRect.fWidth,
|
| + srcY1,
|
| + dstGLRect.fLeft,
|
| + dstGLRect.fBottom,
|
| + dstGLRect.fLeft + dstGLRect.fWidth,
|
| + dstGLRect.fBottom + dstGLRect.fHeight,
|
| + GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
|
| + if (dstFBO) {
|
| + this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER);
|
| + }
|
| + if (srcFBO) {
|
| + this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| void GrGLGpu::xferBarrier(GrRenderTarget* rt, GrXferBarrierType type) {
|
| switch (type) {
|
| case kTexture_GrXferBarrierType: {
|
| @@ -2832,26 +3019,52 @@ void GrGLGpu::didRemoveGpuTraceMarker() {
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| -
|
| GrGLAttribArrayState* GrGLGpu::HWGeometryState::bindArrayAndBuffersToDraw(
|
| GrGLGpu* gpu,
|
| const GrGLVertexBuffer* vbuffer,
|
| const GrGLIndexBuffer* ibuffer) {
|
| SkASSERT(vbuffer);
|
| + GrGLuint vbufferID = vbuffer->bufferID();
|
| + GrGLuint* ibufferIDPtr = NULL;
|
| + GrGLuint ibufferID;
|
| + if (ibuffer) {
|
| + ibufferID = ibuffer->bufferID();
|
| + ibufferIDPtr = &ibufferID;
|
| + }
|
| + return this->internalBind(gpu, vbufferID, ibufferIDPtr);
|
| +}
|
| +
|
| +GrGLAttribArrayState* GrGLGpu::HWGeometryState::bindArrayAndBufferToDraw(GrGLGpu* gpu,
|
| + GrGLuint vbufferID) {
|
| + return this->internalBind(gpu, vbufferID, NULL);
|
| +}
|
| +
|
| +GrGLAttribArrayState* GrGLGpu::HWGeometryState::bindArrayAndBuffersToDraw(GrGLGpu* gpu,
|
| + GrGLuint vbufferID,
|
| + GrGLuint ibufferID) {
|
| + return this->internalBind(gpu, vbufferID, &ibufferID);
|
| +}
|
| +
|
| +GrGLAttribArrayState* GrGLGpu::HWGeometryState::internalBind(GrGLGpu* gpu,
|
| + GrGLuint vbufferID,
|
| + GrGLuint* ibufferID) {
|
| GrGLAttribArrayState* attribState;
|
|
|
| - // We use a vertex array if we're on a core profile and the verts are in a VBO.
|
| - if (gpu->glCaps().isCoreProfile() && !vbuffer->isCPUBacked()) {
|
| + if (gpu->glCaps().isCoreProfile() && 0 != vbufferID) {
|
| if (!fVBOVertexArray) {
|
| GrGLuint arrayID;
|
| GR_GL_CALL(gpu->glInterface(), GenVertexArrays(1, &arrayID));
|
| int attrCount = gpu->glCaps().maxVertexAttributes();
|
| fVBOVertexArray = SkNEW_ARGS(GrGLVertexArray, (arrayID, attrCount));
|
| }
|
| - attribState = fVBOVertexArray->bindWithIndexBuffer(gpu, ibuffer);
|
| + if (ibufferID) {
|
| + attribState = fVBOVertexArray->bindWithIndexBuffer(gpu, *ibufferID);
|
| + } else {
|
| + attribState = fVBOVertexArray->bind(gpu);
|
| + }
|
| } else {
|
| - if (ibuffer) {
|
| - this->setIndexBufferIDOnDefaultVertexArray(gpu, ibuffer->bufferID());
|
| + if (ibufferID) {
|
| + this->setIndexBufferIDOnDefaultVertexArray(gpu, *ibufferID);
|
| } else {
|
| this->setVertexArrayID(gpu, 0);
|
| }
|
|
|