Add support for reading the dst pixel value in an effect. Use in a new effect for the kDarken xfer mode.
The current implementation is to always make a copy of the entire dst before the draw.
It will only succeed if the RT is also a texture.
Obviously, there is lots of room for improvement.
Review URL: https://codereview.chromium.org/13314002
git-svn-id: http://skia.googlecode.com/svn/trunk@8449 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 64576af..4d4ba49 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -9,6 +9,7 @@
#include "GrDrawTarget.h"
+#include "GrContext.h"
#include "GrDrawTargetCaps.h"
#include "GrRenderTarget.h"
#include "GrTexture.h"
@@ -38,6 +39,9 @@
} else {
fDevBounds = NULL;
}
+
+ fDstCopy = di.fDstCopy;
+
return *this;
}
@@ -402,6 +406,62 @@
return true;
}
+bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
+ bool willReadDst = false;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ const GrEffectRef* effect = this->drawState()->getStage(s).getEffect();
+ if (NULL != effect && (*effect)->willReadDst()) {
+ willReadDst = true;
+ break;
+ }
+ }
+ if (!willReadDst) {
+ return true;
+ }
+ GrRenderTarget* rt = this->drawState()->getRenderTarget();
+ // If the dst is not a texture then we don't currently have a way of copying the
+ // texture. TODO: make copying RT->Tex (or Surface->Surface) a GrDrawTarget operation that can
+ // be built on top of GL/D3D APIs.
+ if (NULL == rt->asTexture()) {
+ GrPrintf("Reading Dst of non-texture render target is not currently supported.\n");
+ return false;
+ }
+ // TODO: Consider bounds of draw and bounds of clip
+
+ GrDrawTarget::AutoGeometryAndStatePush agasp(this, kReset_ASRInit);
+
+ // The draw will resolve dst if it has MSAA. Two things to consider in the future:
+ // 1) to make the dst values be pre-resolve we'd need to be able to copy to MSAA
+ // texture and sample it correctly in the shader. 2) If 1 isn't available then we
+ // should just resolve and use the resolved texture directly rather than making a
+ // copy of it.
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ desc.fWidth = rt->width();
+ desc.fHeight = rt->height();
+ desc.fSampleCnt = 0;
+ desc.fConfig = rt->config();
+
+ GrAutoScratchTexture ast(fContext, desc, GrContext::kApprox_ScratchTexMatch);
+
+ if (NULL == ast.texture()) {
+ GrPrintf("Failed to create temporary copy of destination texture.\n");
+ return false;
+ }
+ this->drawState()->disableState(GrDrawState::kClip_StateBit);
+ this->drawState()->setRenderTarget(ast.texture()->asRenderTarget());
+ static const int kTextureStage = 0;
+ SkMatrix matrix;
+ matrix.setIDiv(rt->width(), rt->height());
+ this->drawState()->createTextureEffect(kTextureStage, rt->asTexture(), matrix);
+ SkRect copyRect = SkRect::MakeWH(SkIntToScalar(desc.fWidth),
+ SkIntToScalar(desc.fHeight));
+ this->drawRect(copyRect, NULL, ©Rect, NULL);
+ info->fDstCopy.setTexture(ast.texture());
+ info->fDstCopy.setOffset(0, 0);
+ return true;
+}
+
void GrDrawTarget::drawIndexed(GrPrimitiveType type,
int startVertex,
int startIndex,
@@ -423,6 +483,10 @@
if (NULL != devBounds) {
info.setDevBounds(*devBounds);
}
+ // TODO: We should continue with incorrect blending.
+ if (!this->setupDstReadIfNecessary(&info)) {
+ return;
+ }
this->onDraw(info);
}
}
@@ -446,6 +510,10 @@
if (NULL != devBounds) {
info.setDevBounds(*devBounds);
}
+ // TODO: We should continue with incorrect blending.
+ if (!this->setupDstReadIfNecessary(&info)) {
+ return;
+ }
this->onDraw(info);
}
}
@@ -508,6 +576,10 @@
if (NULL != devBounds) {
info.setDevBounds(*devBounds);
}
+ // TODO: We should continue with incorrect blending.
+ if (!this->setupDstReadIfNecessary(&info)) {
+ return;
+ }
while (instanceCount) {
info.fInstanceCount = GrMin(instanceCount, maxInstancesPerDraw);