Move copy-surface-as-draw fallback to GrGLGpu.
Review URL: https://codereview.chromium.org/1144433002
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 549ab37..7565cd1 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -100,13 +100,10 @@
return false;
}
SkIPoint dstPoint = {0, 0};
- if (this->copySurface(copy, rt, copyRect, dstPoint)) {
- dstCopy->setTexture(copy);
- dstCopy->setOffset(copyRect.fLeft, copyRect.fTop);
- return true;
- } else {
- return false;
- }
+ this->copySurface(copy, rt, copyRect, dstPoint);
+ dstCopy->setTexture(copy);
+ dstCopy->setOffset(copyRect.fLeft, copyRect.fTop);
+ return true;
}
void GrDrawTarget::flush() {
@@ -421,7 +418,7 @@
}
}
-bool GrDrawTarget::copySurface(GrSurface* dst,
+void GrDrawTarget::copySurface(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) {
@@ -437,56 +434,10 @@
dstPoint,
&clippedSrcRect,
&clippedDstPoint)) {
- return true;
+ return;
}
- if (this->getGpu()->canCopySurface(dst, src, clippedSrcRect, clippedDstPoint)) {
- this->onCopySurface(dst, src, clippedSrcRect, clippedDstPoint);
- return true;
- }
-
- GrRenderTarget* rt = dst->asRenderTarget();
- GrTexture* tex = src->asTexture();
-
- if ((dst == src) || !rt || !tex) {
- return false;
- }
-
- GrPipelineBuilder pipelineBuilder;
- pipelineBuilder.setRenderTarget(rt);
- SkMatrix matrix;
- matrix.setTranslate(SkIntToScalar(clippedSrcRect.fLeft - clippedDstPoint.fX),
- SkIntToScalar(clippedSrcRect.fTop - clippedDstPoint.fY));
- matrix.postIDiv(tex->width(), tex->height());
- pipelineBuilder.addColorTextureProcessor(tex, matrix);
- SkIRect dstRect = SkIRect::MakeXYWH(clippedDstPoint.fX,
- clippedDstPoint.fY,
- clippedSrcRect.width(),
- clippedSrcRect.height());
- this->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, SkMatrix::I(), dstRect);
- return true;
-}
-
-bool GrDrawTarget::canCopySurface(const GrSurface* dst,
- const GrSurface* src,
- const SkIRect& srcRect,
- const SkIPoint& dstPoint) {
- SkASSERT(dst);
- SkASSERT(src);
-
- SkIRect clippedSrcRect;
- SkIPoint clippedDstPoint;
- // If the rect is outside the src or dst then we're guaranteed success
- if (!clip_srcrect_and_dstpoint(dst,
- src,
- srcRect,
- dstPoint,
- &clippedSrcRect,
- &clippedDstPoint)) {
- return true;
- }
- return ((dst != src) && dst->asRenderTarget() && src->asTexture()) ||
- this->getGpu()->canCopySurface(dst, src, clippedSrcRect, clippedDstPoint);
+ this->onCopySurface(dst, src, clippedSrcRect, clippedDstPoint);
}
void GrDrawTarget::setupPipeline(const PipelineInfo& pipelineInfo,
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 84f7eb2..0157354 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -178,25 +178,15 @@
* copied are specified by srcRect. They are copied to a rect of the same
* size in dst with top left at dstPoint. If the src rect is clipped by the
* src bounds then pixel values in the dst rect corresponding to area clipped
- * by the src rect are not overwritten. This method can fail and return false
+ * by the src rect are not overwritten. This method is not guaranteed to succeed
* depending on the type of surface, configs, etc, and the backend-specific
- * limitations. If rect is clipped out entirely by the src or dst bounds then
- * true is returned since there is no actual copy necessary to succeed.
+ * limitations.
*/
- bool copySurface(GrSurface* dst,
+ void copySurface(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint);
/**
- * Function that determines whether a copySurface call would succeed without actually
- * performing the copy.
- */
- bool canCopySurface(const GrSurface* dst,
- const GrSurface* src,
- const SkIRect& srcRect,
- const SkIPoint& dstPoint);
-
- /**
* Release any resources that are cached but not currently in use. This
* is intended to give an application some recourse when resources are low.
*/
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index f2ad10f..e8d4939 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -257,16 +257,6 @@
const GrPipeline&,
const GrBatchTracker&) const = 0;
- // Called to determine whether a copySurface call would succeed or not. Derived
- // classes must keep this consistent with their implementation of onCopySurface(). Fallbacks
- // to issuing a draw from the src to dst take place at the GrDrawTarget level and this function
- // should only return true if a faster copy path exists. The rect and point are pre-clipped. The
- // src rect and implied dst rect are guaranteed to be within the src/dst bounds and non-empty.
- virtual bool canCopySurface(const GrSurface* dst,
- const GrSurface* src,
- const SkIRect& srcRect,
- const SkIPoint& dstPoint) = 0;
-
// Called to perform a surface to surface copy. Fallbacks to issuing a draw from the src to dst
// take place at the GrDrawTarget level and this function implement faster copy paths. The rect
// and point are pre-clipped. The src rect and implied dst rect are guaranteed to be within the
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 6b6490c..8cc3658 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -121,7 +121,6 @@
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) {
- SkASSERT(this->getGpu()->canCopySurface(dst, src, srcRect, dstPoint));
GrTargetCommands::Cmd* cmd = fCommands->recordCopySurface(dst, src, srcRect, dstPoint);
this->recordTraceMarkersIfNecessary(cmd);
}
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index 0b3d030..6504acf 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -155,11 +155,6 @@
void discard(GrRenderTarget*) override {}
- bool canCopySurface(const GrSurface* dst,
- const GrSurface* src,
- const SkIRect& srcRect,
- const SkIPoint& dstPoint) override { return false; };
-
bool copySurface(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 06ebe3d..5ee7546 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -942,6 +942,7 @@
GrGLSLCaps& GrGLSLCaps::operator= (const GrGLSLCaps& caps) {
INHERITED::operator=(caps);
+ fGLSLGeneration = caps.fGLSLGeneration;
fDropsTileOnZeroDivide = caps.fDropsTileOnZeroDivide;
fFBFetchSupport = caps.fFBFetchSupport;
fFBFetchNeedsCustomOutput = caps.fFBFetchNeedsCustomOutput;
@@ -960,6 +961,8 @@
return false;
}
+ fGLSLGeneration = ctxInfo.glslGeneration();
+
GrGLStandard standard = ctxInfo.standard();
GrGLVersion version = ctxInfo.version();
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 25c7889..dfc6233 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -374,6 +374,7 @@
typedef GrDrawTargetCaps INHERITED;
};
+#include "GrGLSL.h"
class GrGLSLCaps : public GrShaderCaps {
public:
@@ -438,6 +439,12 @@
bool mustEnableSpecificAdvBlendEqs() const {
return fAdvBlendEqInteraction == kSpecificEnables_AdvBlendEqInteraction;
}
+
+ bool mustDeclareFragmentShaderOutput() const {
+ return fGLSLGeneration > k110_GrGLSLGeneration;
+ }
+
+ GrGLSLGeneration generation() const { return fGLSLGeneration; }
/**
* Returns a string containing the caps info.
@@ -448,6 +455,8 @@
// Must be called after fGeometryShaderSupport is initialized.
void initShaderPrecisionTable(const GrGLContextInfo&, const GrGLInterface*);
+ GrGLSLGeneration fGLSLGeneration;
+
bool fDropsTileOnZeroDivide : 1;
bool fFBFetchSupport : 1;
bool fFBFetchNeedsCustomOutput : 1;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 6d97804..56b3d42 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 @@
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 @@
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 @@
fTempSrcFBOID = 0;
fTempDstFBOID = 0;
fStencilClearFBOID = 0;
+ fCopyProgram.fArrayBuffer = 0;
+ fCopyProgram.fProgram = 0;
if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
this->glPathRendering()->abandonGpuResources();
}
@@ -1417,15 +1429,13 @@
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 @@
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 @@
GrVertexAttribType attribType = attrib.fType;
attribState->set(this,
attribIndex,
- vbuf,
+ vbuf->bufferID(),
GrGLAttribTypeToLayout(attribType).fCount,
GrGLAttribTypeToLayout(attribType).fType,
GrGLAttribTypeToLayout(attribType).fNormalized,
@@ -2618,7 +2628,16 @@
}
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,127 +2683,295 @@
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;
- }
- }
- 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)) {
+ if (src->asTexture() && dst->asRenderTarget()) {
+ this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
return true;
}
+
+ 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;
}
}
- 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) {
@@ -2832,26 +3019,52 @@
}
///////////////////////////////////////////////////////////////////////////////
-
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);
}
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 3323ece..986045a 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -101,11 +101,6 @@
const SkIRect& srcRect,
const SkIPoint& dstPoint) override;
- bool canCopySurface(const GrSurface* dst,
- const GrSurface* src,
- const SkIRect& srcRect,
- const SkIPoint& dstPoint) override;
-
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override;
void buildProgramDesc(GrProgramDesc*,
@@ -183,6 +178,19 @@
// Subclasses should call this to flush the blend state.
void flushBlend(const GrXferProcessor::BlendInfo& blendInfo);
+ void copySurfaceAsDraw(GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint);
+ void copySurfaceAsCopyTexSubImage(GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint);
+ bool copySurfaceAsBlitFramebuffer(GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint);
+
bool hasExtension(const char* ext) const { return fGLContext.hasExtension(ext); }
static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
@@ -193,7 +201,7 @@
~ProgramCache();
void abandon();
- GrGLProgram* getProgram(const DrawArgs&);
+ GrGLProgram* refProgram(const DrawArgs&);
private:
enum {
@@ -294,11 +302,12 @@
void unbindTextureFromFBO(GrGLenum fboTarget);
+ void createCopyProgram();
+
GrGLContext fGLContext;
// GL program-related state
ProgramCache* fProgramCache;
- SkAutoTUnref<GrGLProgram> fCurrentProgram;
///////////////////////////////////////////////////////////////////////////
///@name Caching of GL State
@@ -420,7 +429,17 @@
const GrGLVertexBuffer* vbuffer,
const GrGLIndexBuffer* ibuffer);
+ /** Variants of the above that takes GL buffer IDs. Note that 0 does not imply that a
+ buffer won't be bound. The "default buffer" will be bound, which is used for client-side
+ array rendering. */
+ GrGLAttribArrayState* bindArrayAndBufferToDraw(GrGLGpu* gpu, GrGLuint vbufferID);
+ GrGLAttribArrayState* bindArrayAndBuffersToDraw(GrGLGpu* gpu,
+ GrGLuint vbufferID,
+ GrGLuint ibufferID);
+
private:
+ GrGLAttribArrayState* internalBind(GrGLGpu* gpu, GrGLuint vbufferID, GrGLuint* ibufferID);
+
GrGLuint fBoundVertexArrayID;
GrGLuint fBoundVertexBufferID;
bool fBoundVertexArrayIDIsValid;
@@ -454,6 +473,15 @@
}
} fHWBlendState;
+ /** IDs for copy surface program. */
+ struct {
+ GrGLuint fProgram;
+ GrGLint fTextureUniform;
+ GrGLint fTexCoordXformUniform;
+ GrGLint fPosXformUniform;
+ GrGLuint fArrayBuffer;
+ } fCopyProgram;
+
TriState fMSAAEnabled;
GrStencilSettings fHWStencilSettings;
diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp
index 911fd93..06efe29 100644
--- a/src/gpu/gl/GrGLGpuProgramCache.cpp
+++ b/src/gpu/gl/GrGLGpuProgramCache.cpp
@@ -90,7 +90,7 @@
return SkTSearch(fEntries, fCount, desc, sizeof(Entry*), less);
}
-GrGLProgram* GrGLGpu::ProgramCache::getProgram(const DrawArgs& args) {
+GrGLProgram* GrGLGpu::ProgramCache::refProgram(const DrawArgs& args) {
#ifdef PROGRAM_CACHE_STATS
++fTotalRequests;
#endif
@@ -193,5 +193,5 @@
}
}
++fCurrLRUStamp;
- return entry->fProgram;
+ return SkRef(entry->fProgram.get());
}
diff --git a/src/gpu/gl/GrGLSL.cpp b/src/gpu/gl/GrGLSL.cpp
index d388d91..f4caf52 100644
--- a/src/gpu/gl/GrGLSL.cpp
+++ b/src/gpu/gl/GrGLSL.cpp
@@ -91,6 +91,25 @@
}
}
+void GrGLSLAppendDefaultFloatPrecisionDeclaration(GrSLPrecision p, GrGLStandard s, SkString* out) {
+ // Desktop GLSL has added precision qualifiers but they don't do anything.
+ if (kGLES_GrGLStandard == s) {
+ switch (p) {
+ case kHigh_GrSLPrecision:
+ out->append("precision highp float;\n");
+ break;
+ case kMedium_GrSLPrecision:
+ out->append("precision mediump float;\n");
+ break;
+ case kLow_GrSLPrecision:
+ out->append("precision lowp float;\n");
+ break;
+ default:
+ SkFAIL("Unknown precision value.");
+ }
+ }
+}
+
void GrGLSLMulVarBy4f(SkString* outAppend, const char* vec4VarName, const GrGLSLExpr4& mulFactor) {
if (mulFactor.isOnes()) {
*outAppend = SkString();
diff --git a/src/gpu/gl/GrGLSL.h b/src/gpu/gl/GrGLSL.h
index 99671c1..db8e1bd 100644
--- a/src/gpu/gl/GrGLSL.h
+++ b/src/gpu/gl/GrGLSL.h
@@ -57,6 +57,24 @@
const char* GrGetGLSLVersionDecl(const GrGLContextInfo&);
/**
+ * Adds a line of GLSL code to declare the default precision for float types.
+ */
+void GrGLSLAppendDefaultFloatPrecisionDeclaration(GrSLPrecision, GrGLStandard, SkString* out);
+
+/**
+ * Gets the name of the function that should be used to sample a 2D texture. Coord type is used
+ * to indicate whether the texture is sampled using projective textured (kVec3f) or not (kVec2f).
+ */
+inline const char* GrGLSLTexture2DFunctionName(GrSLType coordType, GrGLSLGeneration glslGen) {
+ if (kVec2f_GrSLType == coordType) {
+ return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D";
+ } else {
+ SkASSERT(kVec3f_GrSLType == coordType);
+ return glslGen >= k130_GrGLSLGeneration ? "textureProj" : "texture2DProj";
+ }
+}
+
+/**
* Converts a GrSLType to a string containing the name of the equivalent GLSL type.
*/
static inline const char* GrGLSLTypeString(GrSLType t) {
diff --git a/src/gpu/gl/GrGLVertexArray.cpp b/src/gpu/gl/GrGLVertexArray.cpp
index e20dbb5..265b5b3 100644
--- a/src/gpu/gl/GrGLVertexArray.cpp
+++ b/src/gpu/gl/GrGLVertexArray.cpp
@@ -9,9 +9,10 @@
#include "GrGLGpu.h"
-void GrGLAttribArrayState::set(const GrGLGpu* gpu,
+
+void GrGLAttribArrayState::set(GrGLGpu* gpu,
int index,
- GrGLVertexBuffer* buffer,
+ GrGLuint vertexBufferID,
GrGLint size,
GrGLenum type,
GrGLboolean normalized,
@@ -25,13 +26,13 @@
array->fEnabled = true;
}
if (!array->fAttribPointerIsValid ||
- array->fVertexBufferID != buffer->bufferID() ||
+ array->fVertexBufferID != vertexBufferID ||
array->fSize != size ||
array->fNormalized != normalized ||
array->fStride != stride ||
array->fOffset != offset) {
- buffer->bind();
+ gpu->bindVertexBuffer(vertexBufferID);
GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index,
size,
type,
@@ -39,7 +40,7 @@
stride,
offset));
array->fAttribPointerIsValid = true;
- array->fVertexBufferID = buffer->bufferID();
+ array->fVertexBufferID = vertexBufferID;
array->fSize = size;
array->fNormalized = normalized;
array->fStride = stride;
@@ -80,15 +81,13 @@
return &fAttribArrays;
}
-GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu,
- const GrGLIndexBuffer* buffer) {
+GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(GrGLGpu* gpu, GrGLuint ibufferID) {
GrGLAttribArrayState* state = this->bind(gpu);
- if (state && buffer) {
- GrGLuint bufferID = buffer->bufferID();
- if (!fIndexBufferIDIsValid || bufferID != fIndexBufferID) {
- GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, bufferID));
+ if (state) {
+ if (!fIndexBufferIDIsValid || ibufferID != fIndexBufferID) {
+ GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, ibufferID));
fIndexBufferIDIsValid = true;
- fIndexBufferID = bufferID;
+ fIndexBufferID = ibufferID;
}
}
return state;
diff --git a/src/gpu/gl/GrGLVertexArray.h b/src/gpu/gl/GrGLVertexArray.h
index a8feb73..afb23c5 100644
--- a/src/gpu/gl/GrGLVertexArray.h
+++ b/src/gpu/gl/GrGLVertexArray.h
@@ -67,9 +67,9 @@
* assumed that the GrGLAttribArrayState is tracking the state of the currently bound vertex
* array object.
*/
- void set(const GrGLGpu*,
- int index,
- GrGLVertexBuffer*,
+ void set(GrGLGpu*,
+ int attribIndex,
+ GrGLuint vertexBufferID,
GrGLint size,
GrGLenum type,
GrGLboolean normalized,
@@ -147,7 +147,7 @@
* This is a version of the above function that also binds an index buffer to the vertex
* array object.
*/
- GrGLAttribArrayState* bindWithIndexBuffer(GrGLGpu* gpu, const GrGLIndexBuffer*);
+ GrGLAttribArrayState* bindWithIndexBuffer(GrGLGpu* gpu, GrGLuint indexBufferID);
void notifyIndexBufferDelete(GrGLuint bufferID);
diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
index 044752f..afb0718 100644
--- a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
@@ -15,26 +15,6 @@
const char* GrGLFragmentShaderBuilder::kDstCopyColorName = "_dstColor";
static const char* declared_color_output_name() { return "fsColorOut"; }
static const char* dual_source_output_name() { return "dualSourceOut"; }
-static void append_default_precision_qualifier(GrSLPrecision p,
- GrGLStandard standard,
- SkString* str) {
- // Desktop GLSL has added precision qualifiers but they don't do anything.
- if (kGLES_GrGLStandard == standard) {
- switch (p) {
- case kHigh_GrSLPrecision:
- str->append("precision highp float;\n");
- break;
- case kMedium_GrSLPrecision:
- str->append("precision mediump float;\n");
- break;
- case kLow_GrSLPrecision:
- str->append("precision lowp float;\n");
- break;
- default:
- SkFAIL("Unknown precision value.");
- }
- }
-}
static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
SkASSERT(GrBlendEquationIsAdvanced(equation));
@@ -270,9 +250,9 @@
SkTDArray<GrGLuint>* shaderIds) {
GrGLGpu* gpu = fProgramBuilder->gpu();
this->versionDecl() = GrGetGLSLVersionDecl(gpu->ctxInfo());
- append_default_precision_qualifier(kDefault_GrSLPrecision,
- gpu->glStandard(),
- &this->precisionQualifier());
+ GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
+ gpu->glStandard(),
+ &this->precisionQualifier());
this->compileAndAppendLayoutQualifiers();
fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility,
&this->uniforms());
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 28e1fba..95f75ff 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -343,8 +343,7 @@
fFS.enableSecondaryOutput();
}
- // On any post 1.10 GLSL supporting GPU, we declare custom output
- if (k110_GrGLSLGeneration != fFS.fProgramBuilder->gpu()->glslGeneration()) {
+ if (this->ctxInfo().caps()->glslCaps()->mustDeclareFragmentShaderOutput()) {
fFS.enableCustomOutput();
}
diff --git a/src/gpu/gl/builders/GrGLShaderBuilder.cpp b/src/gpu/gl/builders/GrGLShaderBuilder.cpp
index 67fbe24..984233d 100644
--- a/src/gpu/gl/builders/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLShaderBuilder.cpp
@@ -12,14 +12,6 @@
#include "../GrGLShaderVar.h"
namespace {
-inline const char* sample_function_name(GrSLType type, GrGLSLGeneration glslGen) {
- if (kVec2f_GrSLType == type) {
- return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D";
- } else {
- SkASSERT(kVec3f_GrSLType == type);
- return glslGen >= k130_GrGLSLGeneration ? "textureProj" : "texture2DProj";
- }
-}
void append_texture_lookup(SkString* out,
GrGLGpu* gpu,
const char* samplerName,
@@ -30,7 +22,7 @@
SkASSERT(coordName);
out->appendf("%s(%s, %s)",
- sample_function_name(varyingType, gpu->glslGeneration()),
+ GrGLSLTexture2DFunctionName(varyingType, gpu->glslGeneration()),
samplerName,
coordName);