Added abstract methods to Renderer for state setting.
TRAC #22041
Added abstract methods for setting rasterizer, blend, depth stencil, render
targets and scissors on Renderer. Implemented methods on Renderer9 using the
state setting from Context as a reference and new members for storing prevously
set state to minimize graphics device calls. Implemented methods on Renderer11
with the UNIMPLEMENTED notice.
Signed-off-by: Shannon Woods
Signed-off-by: Daniel Koch
Author: Geoff Lang
git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1421 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
index b2e887d..bd51922 100644
--- a/src/libGLESv2/renderer/Renderer.h
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -71,6 +71,17 @@
virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler) = 0;
virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0;
+ virtual void setRasterizerState(const gl::RasterizerState &rasterState, unsigned int depthSize) = 0;
+ virtual void setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor,
+ unsigned int sampleMask) = 0;
+ virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, bool frontFaceCCW,
+ unsigned int stencilSize) = 0;
+
+ virtual void setScissorRectangle(const gl::Rectangle& scissor, unsigned int renderTargetWidth,
+ unsigned int renderTargetHeight) = 0;
+
+ virtual void applyRenderTarget(gl::Framebuffer *frameBuffer) = 0;
+
// lost device
virtual void markDeviceLost() = 0;
virtual bool isDeviceLost() = 0;
diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
index d88d33f..c31ef56 100644
--- a/src/libGLESv2/renderer/Renderer11.cpp
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -236,6 +236,38 @@
UNIMPLEMENTED();
}
+void Renderer11::setRasterizerState(const gl::RasterizerState &rasterState, unsigned int depthSize)
+{
+ // TODO
+ UNIMPLEMENTED();
+}
+
+void Renderer11::setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor,
+ unsigned int sampleMask)
+{
+ // TODO
+ UNIMPLEMENTED();
+}
+
+void Renderer11::setDepthStencilState(const gl::DepthStencilState &depthStencilState, bool frontFaceCCW,
+ unsigned int stencilSize)
+{
+ // TODO
+ UNIMPLEMENTED();
+}
+
+void Renderer11::setScissorRectangle(const gl::Rectangle& scissor, unsigned int renderTargetWidth,
+ unsigned int renderTargetHeight)
+{
+ // TODO
+ UNIMPLEMENTED();
+}
+
+void Renderer11::applyRenderTarget(gl::Framebuffer *frameBuffer)
+{
+ // TODO
+ UNIMPLEMENTED();
+}
void Renderer11::releaseDeviceResources()
{
diff --git a/src/libGLESv2/renderer/Renderer11.h b/src/libGLESv2/renderer/Renderer11.h
index 0997ad4..0e47be2 100644
--- a/src/libGLESv2/renderer/Renderer11.h
+++ b/src/libGLESv2/renderer/Renderer11.h
@@ -45,6 +45,17 @@
virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler);
virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture);
+ virtual void setRasterizerState(const gl::RasterizerState &rasterState, unsigned int depthSize);
+ virtual void setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor,
+ unsigned int sampleMask);
+ virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, bool frontFaceCCW,
+ unsigned int stencilSize);
+
+ virtual void setScissorRectangle(const gl::Rectangle& scissor, unsigned int renderTargetWidth,
+ unsigned int renderTargetHeight);
+
+ virtual void applyRenderTarget(gl::Framebuffer *frameBuffer);
+
// lost device
virtual void markDeviceLost();
virtual bool isDeviceLost();
diff --git a/src/libGLESv2/renderer/Renderer9.cpp b/src/libGLESv2/renderer/Renderer9.cpp
index 2474a99..d183750 100644
--- a/src/libGLESv2/renderer/Renderer9.cpp
+++ b/src/libGLESv2/renderer/Renderer9.cpp
@@ -7,7 +7,10 @@
// Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer.
#include "common/debug.h"
+#include "libGLESv2/main.h"
#include "libGLESv2/utilities.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/Framebuffer.h"
#include "libGLESv2/renderer/Renderer9.h"
#include "libGLESv2/renderer/renderer9_utils.h"
#include "libGLESv2/renderer/TextureStorage.h"
@@ -130,6 +133,11 @@
delete [] mMultiSampleSupport.begin()->second;
mMultiSampleSupport.erase(mMultiSampleSupport.begin());
}
+
+ mForceSetDepthStencilState = true;
+ mForceSetRasterState = true;
+ mForceSetBlendState = true;
+ mForceSetScissor = true;
}
EGLint Renderer9::initialize()
@@ -589,6 +597,273 @@
mDevice->SetTexture(d3dSampler, d3dTexture);
}
+void Renderer9::setRasterizerState(const gl::RasterizerState &rasterState, unsigned int depthSize)
+{
+ bool rasterStateChanged = mForceSetRasterState || memcmp(&rasterState, &mCurRasterState, sizeof(gl::RasterizerState)) != 0;
+ bool depthSizeChanged = mForceSetRasterState || depthSize != mCurDepthSize;
+
+ if (rasterStateChanged)
+ {
+ // Set the cull mode
+ if (rasterState.cullFace)
+ {
+ mDevice->SetRenderState(D3DRS_CULLMODE, gl_d3d9::ConvertCullMode(rasterState.cullMode, rasterState.frontFace));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ }
+
+ mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, rasterState.scissorTest ? TRUE : FALSE);
+
+ mCurRasterState = rasterState;
+ }
+
+ if (rasterStateChanged || depthSizeChanged)
+ {
+ if (rasterState.polygonOffsetFill)
+ {
+ if (depthSize > 0)
+ {
+ mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&rasterState.polygonOffsetFactor);
+
+ float depthBias = ldexp(rasterState.polygonOffsetUnits, -static_cast<int>(depthSize));
+ mDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)&depthBias);
+ }
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
+ mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
+ }
+
+ mCurDepthSize = depthSize;
+ }
+
+ mForceSetRasterState = false;
+}
+
+void Renderer9::setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor, unsigned int sampleMask)
+{
+ bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0;
+ bool blendColorChanged = mForceSetBlendState || memcmp(&blendColor, &mCurBlendColor, sizeof(gl::Color)) != 0;
+ bool sampleMaskChanged = mForceSetBlendState || sampleMask != mCurSampleMask;
+
+ if (blendStateChanged || blendColorChanged)
+ {
+ if (blendState.blend)
+ {
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA && blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
+ blendState.destBlendRGB != GL_CONSTANT_ALPHA && blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
+ {
+ mDevice->SetRenderState(D3DRS_BLENDFACTOR, gl_d3d9::ConvertColor(blendColor));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha),
+ gl::unorm<8>(blendColor.alpha),
+ gl::unorm<8>(blendColor.alpha),
+ gl::unorm<8>(blendColor.alpha)));
+ }
+
+ mDevice->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB));
+ mDevice->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB));
+ mDevice->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB));
+
+ if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha ||
+ blendState.destBlendRGB != blendState.destBlendAlpha ||
+ blendState.blendEquationRGB != blendState.blendEquationAlpha)
+ {
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+
+ mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha));
+ mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha));
+ mDevice->SetRenderState(D3DRS_BLENDOPALPHA, gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+ }
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ }
+
+ if (blendState.sampleAlphaToCoverage)
+ {
+ FIXME("Sample alpha to coverage is unimplemented.");
+ }
+
+ // Set the color mask
+ bool zeroColorMaskAllowed = getAdapterVendor() != VENDOR_ID_AMD;
+ // Apparently some ATI cards have a bug where a draw with a zero color
+ // write mask can cause later draws to have incorrect results. Instead,
+ // set a nonzero color write mask but modify the blend state so that no
+ // drawing is done.
+ // http://code.google.com/p/angleproject/issues/detail?id=169
+
+ DWORD colorMask = gl_d3d9::ConvertColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
+ blendState.colorMaskBlue, blendState.colorMaskAlpha);
+ if (colorMask == 0 && !zeroColorMaskAllowed)
+ {
+ // Enable green channel, but set blending so nothing will be drawn.
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+ mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+ mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
+ }
+
+ mDevice->SetRenderState(D3DRS_DITHERENABLE, blendState.dither ? TRUE : FALSE);
+
+ mCurBlendState = blendState;
+ mCurBlendColor = blendColor;
+ }
+
+ if (sampleMaskChanged)
+ {
+ // Set the multisample mask
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask));
+
+ mCurSampleMask = sampleMask;
+ }
+
+ mForceSetBlendState = false;
+}
+
+void Renderer9::setDepthStencilState(const gl::DepthStencilState &depthStencilState, bool frontFaceCCW,
+ unsigned int stencilSize)
+{
+ bool depthStencilStateChanged = mForceSetDepthStencilState ||
+ memcmp(&depthStencilState, &mCurDepthStencilState, sizeof(gl::DepthStencilState)) != 0;
+ bool frontFaceCCWChanged = mForceSetDepthStencilState || frontFaceCCW != mCurFrontFaceCCW;
+ bool stencilSizeChanged = mForceSetDepthStencilState || stencilSize != mCurStencilSize;
+
+ if (depthStencilStateChanged)
+ {
+ if (depthStencilState.depthTest)
+ {
+ mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthStencilState.depthFunc));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+ }
+
+ mCurDepthStencilState = depthStencilState;
+ }
+
+ if (depthStencilStateChanged || frontFaceCCWChanged || stencilSizeChanged)
+ {
+ if (depthStencilState.stencilTest && stencilSize > 0)
+ {
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
+
+ // FIXME: Unsupported by D3D9
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
+ if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
+ depthStencilState.stencilRef != depthStencilState.stencilBackRef ||
+ depthStencilState.stencilMask != depthStencilState.stencilBackMask)
+ {
+ ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL.");
+ return error(GL_INVALID_OPERATION);
+ }
+
+ // get the maximum size of the stencil ref
+ GLuint maxStencil = (1 << stencilSize) - 1;
+
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK,
+ depthStencilState.stencilWritemask);
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ gl_d3d9::ConvertComparison(depthStencilState.stencilFunc));
+
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
+ (depthStencilState.stencilRef < (GLint)maxStencil) ? depthStencilState.stencilRef : maxStencil);
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
+ depthStencilState.stencilMask);
+
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilFail));
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthFail));
+ mDevice->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilPassDepthPass));
+
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK,
+ depthStencilState.stencilBackWritemask);
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ gl_d3d9::ConvertComparison(depthStencilState.stencilBackFunc));
+
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
+ (depthStencilState.stencilBackRef < (GLint)maxStencil) ? depthStencilState.stencilBackRef : maxStencil);
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
+ depthStencilState.stencilBackMask);
+
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackFail));
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthFail));
+ mDevice->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ gl_d3d9::ConvertStencilOp(depthStencilState.stencilBackPassDepthPass));
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ }
+
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, depthStencilState.depthMask ? TRUE : FALSE);
+
+ mCurFrontFaceCCW = frontFaceCCW;
+ mCurStencilSize = stencilSize;
+ }
+
+ mForceSetDepthStencilState = false;
+}
+
+void Renderer9::setScissorRectangle(const gl::Rectangle& scissor, unsigned int renderTargetWidth,
+ unsigned int renderTargetHeight)
+{
+ bool renderTargetSizedChanged = mForceSetScissor ||
+ renderTargetWidth != mCurRenderTargetWidth ||
+ renderTargetHeight != mCurRenderTargetHeight;
+ bool scissorChanged = mForceSetScissor || memcmp(&scissor, &mCurScissor, sizeof(gl::Rectangle)) != 0;
+
+ if (renderTargetSizedChanged || scissorChanged)
+ {
+ RECT rect;
+ rect.left = gl::clamp(scissor.x, 0, static_cast<int>(renderTargetWidth));
+ rect.top = gl::clamp(scissor.y, 0, static_cast<int>(renderTargetWidth));
+ rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(renderTargetWidth));
+ rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(renderTargetWidth));
+ mDevice->SetScissorRect(&rect);
+
+ mCurScissor = scissor;
+ mCurRenderTargetWidth = renderTargetWidth;
+ mCurRenderTargetHeight = renderTargetHeight;
+ }
+
+ mForceSetScissor = false;
+}
+
+void Renderer9::applyRenderTarget(gl::Framebuffer *frameBuffer)
+{
+ mForceSetScissor = true;
+
+ // TODO
+}
void Renderer9::releaseDeviceResources()
{
@@ -717,6 +992,11 @@
initializeDevice();
mDeviceLost = false;
+ mForceSetDepthStencilState = true;
+ mForceSetRasterState = true;
+ mForceSetBlendState = true;
+ mForceSetScissor = true;
+
return true;
}
diff --git a/src/libGLESv2/renderer/Renderer9.h b/src/libGLESv2/renderer/Renderer9.h
index c4fd36c..cbc0a01 100644
--- a/src/libGLESv2/renderer/Renderer9.h
+++ b/src/libGLESv2/renderer/Renderer9.h
@@ -68,6 +68,17 @@
virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler);
virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture);
+ virtual void setRasterizerState(const gl::RasterizerState &rasterState, unsigned int depthSize);
+ virtual void setBlendState(const gl::BlendState &blendState, const gl::Color &blendColor,
+ unsigned int sampleMask);
+ virtual void setDepthStencilState(const gl::DepthStencilState &depthStencilState, bool frontFaceCCW,
+ unsigned int stencilSize);
+
+ virtual void setScissorRectangle(const gl::Rectangle& scissor, unsigned int renderTargetWidth,
+ unsigned int renderTargetHeight);
+
+ virtual void applyRenderTarget(gl::Framebuffer *frameBuffer);
+
// lost device
virtual void markDeviceLost();
virtual bool isDeviceLost();
@@ -161,6 +172,26 @@
std::map<D3DFORMAT, bool *> mMultiSampleSupport;
GLsizei mMaxSupportedSamples;
+ // previously set render states
+ bool mForceSetDepthStencilState;
+ gl::DepthStencilState mCurDepthStencilState;
+ bool mCurFrontFaceCCW;
+ unsigned int mCurStencilSize;
+
+ bool mForceSetRasterState;
+ gl::RasterizerState mCurRasterState;
+ unsigned int mCurDepthSize;
+
+ bool mForceSetScissor;
+ gl::Rectangle mCurScissor;
+ unsigned int mCurRenderTargetWidth;
+ unsigned int mCurRenderTargetHeight;
+
+ bool mForceSetBlendState;
+ gl::BlendState mCurBlendState;
+ gl::Color mCurBlendColor;
+ GLuint mCurSampleMask;
+
// A pool of event queries that are currently unused.
std::vector<IDirect3DQuery9*> mEventQueryPool;
VertexShaderCache mVertexShaderCache;