Implement stencil clipping in mixed sampled render targets

This change enables multisampled clipping for mixed sampled
render targets.  Previously clipping in mixed samples config
behaved the same as in the gpu config.

In order to retrofit non-MSAA draw methods, programmable sample
locations are used in order to colocate all samples at (0.5, 0.5).
Requires support for NV_sample_locations.

BUG=skia:4399

Review URL: https://codereview.chromium.org/1232103002
This commit is contained in:
vbuzinov 2015-09-30 23:02:06 -07:00 committed by Commit bot
parent 6634cbb427
commit 3e77ba96d5
13 changed files with 88 additions and 14 deletions

View File

@ -63,6 +63,7 @@ public:
bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; }
bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; }
bool mixedSamplesSupport() const { return fMixedSamplesSupport; }
bool programmableSampleLocationsSupport() const { return fProgrammableSampleLocationsSupport; }
/**
* Get the precision info for a variable of type kFloat_GrSLType, kVec2f_GrSLType, etc in a
@ -93,6 +94,7 @@ protected:
bool fDstReadInShaderSupport : 1;
bool fDualSourceBlendingSupport : 1;
bool fMixedSamplesSupport : 1;
bool fProgrammableSampleLocationsSupport : 1;
bool fShaderPrecisionVaries;
PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount];

View File

@ -390,6 +390,8 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetVertexArrayIntegeri_vProc)(GrGLuin
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLGetVertexArrayPointeri_vProc)(GrGLuint vaobj, GrGLuint index, GrGLenum pname, GrGLvoid **param);
typedef GrGLvoid* (GR_GL_FUNCTION_TYPE* GrGLMapNamedBufferRangeProc)(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length, GrGLbitfield access);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFlushMappedNamedBufferRangeProc)(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length);
// OpenGL 4.5
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLNamedFramebufferParameteriProc)(GrGLuint framebuffer, GrGLenum pname, GrGLint param);
/* KHR_debug */
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDebugMessageControlProc)(GrGLenum source, GrGLenum type, GrGLenum severity, GrGLsizei count, const GrGLuint* ids, GrGLboolean enabled);

View File

@ -490,6 +490,8 @@ public:
GLPtr<GrGLGetVertexArrayPointeri_vProc> fGetVertexArrayPointeri_v;
GLPtr<GrGLMapNamedBufferRangeProc> fMapNamedBufferRange;
GLPtr<GrGLFlushMappedNamedBufferRangeProc> fFlushMappedNamedBufferRange;
// OpenGL 4.5
GLPtr<GrGLNamedFramebufferParameteriProc> fNamedFramebufferParameteri;
/* KHR_debug */
GLPtr<GrGLDebugMessageControlProc> fDebugMessageControl;

View File

@ -16,6 +16,7 @@ GrShaderCaps::GrShaderCaps() {
fDstReadInShaderSupport = false;
fDualSourceBlendingSupport = false;
fMixedSamplesSupport = false;
fProgrammableSampleLocationsSupport = false;
fShaderPrecisionVaries = false;
}
@ -46,14 +47,15 @@ static const char* precision_to_string(GrSLPrecision p) {
SkString GrShaderCaps::dump() const {
SkString r;
static const char* gNY[] = { "NO", "YES" };
r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]);
r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]);
r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]);
r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]);
r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]);
r.appendf("Mixed Samples Support : %s\n", gNY[fMixedSamplesSupport]);
r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]);
r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]);
r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]);
r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]);
r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]);
r.appendf("Mixed Samples Support : %s\n", gNY[fMixedSamplesSupport]);
r.appendf("Programmable Sample Locations Support : %s\n", gNY[fProgrammableSampleLocationsSupport]);
r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]);
r.appendf("Shader Float Precisions (varies: %s) :\n", gNY[fShaderPrecisionVaries]);
for (int s = 0; s < kGrShaderTypeCount; ++s) {
GrShaderType shaderType = static_cast<GrShaderType>(s);

View File

@ -306,7 +306,7 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
}
// If MSAA is enabled we can do everything in the stencil buffer.
if (0 == rt->numColorSamples() && requiresAA) {
if (0 == rt->numStencilSamples() && requiresAA) {
GrTexture* result = nullptr;
// The top-left of the mask corresponds to the top-left corner of the bounds.
@ -757,7 +757,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
pipelineBuilder.setDisableColorXPFactory();
// if the target is MSAA then we want MSAA enabled when the clip is soft
if (rt->isUnifiedMultisampled()) {
if (rt->isStencilBufferMultisampled()) {
pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, element->isAA());
}

View File

@ -450,6 +450,10 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) {
}
}
if (glVer >= GR_GL_VER(4,5)) {
GET_PROC(NamedFramebufferParameteri);
}
if (glVer >= GR_GL_VER(4,3) || extensions.has("GL_KHR_debug")) {
// KHR_debug defines these methods to have no suffix in an OpenGL (not ES) context.
GET_PROC(DebugMessageControl);

View File

@ -355,6 +355,10 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
fDiscardRenderTargetSupport = false;
fInvalidateFBType = kNone_InvalidateFBType;
}
glslCaps->fProgrammableSampleLocationsSupport =
ctxInfo.hasExtension("GL_NV_sample_locations") ||
ctxInfo.hasExtension("GL_ARB_sample_locations");
/**************************************************************************
* GrCaps fields

View File

@ -889,6 +889,9 @@
#define GR_GL_MULTISAMPLE_RASTERIZATION_ALLOWED 0x932B
#define GR_GL_EFFECTIVE_RASTER_SAMPLES 0x932C
/* GL_NV_sample_locations and GL_ARB_sample_locations */
#define GR_GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS 0x9342
/* GL_KHR_debug */
#define GR_GL_DEBUG_OUTPUT 0x92E0
#define GR_GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242

View File

@ -1476,7 +1476,7 @@ bool GrGLGpu::flushGLState(const DrawArgs& args) {
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
this->flushStencil(pipeline.getStencil());
this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin());
this->flushHWAAState(glRT, pipeline.isHWAntialiasState());
this->flushHWAAState(glRT, pipeline.isHWAntialiasState(), !pipeline.getStencil().isDisabled());
// This must come after textures are flushed because a texture may need
// to be msaa-resolved (which will modify bound FBO state).
@ -1899,6 +1899,22 @@ bool GrGLGpu::onReadPixels(GrSurface* surface,
return true;
}
void GrGLGpu::setColocatedSampleLocations(GrRenderTarget* rt, bool useColocatedSampleLocations) {
GrGLRenderTarget* target = static_cast<GrGLRenderTarget*>(rt->asRenderTarget());
SkASSERT(0 != target->renderFBOID());
if (!rt->isStencilBufferMultisampled() ||
useColocatedSampleLocations == target->usesColocatedSampleLocations()) {
return;
}
GL_CALL(NamedFramebufferParameteri(target->renderFBOID(),
GR_GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS,
useColocatedSampleLocations));
target->flagAsUsingColocatedSampleLocations(useColocatedSampleLocations);
}
void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) {
SkASSERT(target);
@ -2146,9 +2162,19 @@ void GrGLGpu::flushStencil(const GrStencilSettings& stencilSettings) {
}
}
void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA) {
void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled) {
SkASSERT(!useHWAA || rt->isStencilBufferMultisampled());
if (rt->hasMixedSamples() && stencilEnabled &&
this->glCaps().glslCaps()->programmableSampleLocationsSupport()) {
if (useHWAA) {
this->setColocatedSampleLocations(rt, false);
} else {
this->setColocatedSampleLocations(rt, true);
}
useHWAA = true;
}
if (this->glCaps().multisampleDisableSupport()) {
if (useHWAA) {
if (kYes_TriState != fMSAAEnabled) {
@ -2928,7 +2954,7 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst,
this->flushBlend(blendInfo);
this->flushColorWrite(true);
this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
this->flushHWAAState(dstRT, false);
this->flushHWAAState(dstRT, false, false);
this->disableScissor();
GrStencilSettings stencil;
stencil.setDisabled();

View File

@ -255,12 +255,16 @@ private:
// ensures that such operations don't negatively interact with tracking bound textures.
void setScratchTextureUnit();
// colocates all samples at pixel center for render target, if MSAA.
// allows drawing coverage based AA shapes in MSAA mode.
void setColocatedSampleLocations(GrRenderTarget* rt, bool useColocatedSampleLocations);
// bounds is region that may be modified and therefore has to be resolved.
// nullptr means whole target. Can be an empty rect.
void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds);
void flushStencil(const GrStencilSettings&);
void flushHWAAState(GrRenderTarget* rt, bool useHWAA);
void flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled);
bool configToGLFormats(GrPixelConfig config,
bool getSizedInternal,

View File

@ -701,6 +701,12 @@ bool GrGLInterface::validate() const {
}
}
if (kGL_GrGLStandard == fStandard && glVer >= GR_GL_VER(4,5)) {
if (nullptr == fFunctions.fNamedFramebufferParameteri) {
RETURN_FALSE_INTERFACE
}
}
if ((kGL_GrGLStandard == fStandard && glVer >= GR_GL_VER(4,3)) ||
fExtensions.has("GL_KHR_debug")) {
if (nullptr == fFunctions.fDebugMessageControl ||

View File

@ -100,7 +100,7 @@ void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath*
SkISize size = SkISize::Make(rt->width(), rt->height());
this->setProjectionMatrix(*args.fViewMatrix, size, rt->origin());
gpu->flushScissor(*args.fScissor, rt->getViewport(), rt->origin());
gpu->flushHWAAState(rt, args.fUseHWAA);
gpu->flushHWAAState(rt, args.fUseHWAA, true);
gpu->flushRenderTarget(rt, nullptr);
const GrGLPath* glPath = static_cast<const GrGLPath*>(path);

View File

@ -70,6 +70,21 @@ public:
// components seperately.
void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const override;
/**
* @return true if sample locations colocated at pixel center have been set for this
* render target. Requires support for NV_sample_locations.
*/
bool usesColocatedSampleLocations() const {
return fUsesColocatedSampleLocations;
}
/**
* Flag render target as using or not using sample locations colocated at pixel center.
*/
void flagAsUsingColocatedSampleLocations(bool useColocatedSampleLocations) {
fUsesColocatedSampleLocations = useColocatedSampleLocations;
}
protected:
// The public constructor registers this object with the cache. However, only the most derived
// class should register with the cache. This constructor does not do the registration and
@ -116,6 +131,10 @@ private:
// release zero out the IDs and the cache needs to know the size even after those actions.
size_t fGpuMemorySize;
// True if sample locations colocated at pixel center are currently in use, false if default
// sample locations are currently in use.
bool fUsesColocatedSampleLocations;
typedef GrRenderTarget INHERITED;
};