diff options
author | gman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-04 22:07:44 +0000 |
---|---|---|
committer | gman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-04 22:07:44 +0000 |
commit | c3bf65f5b6c64414996c80cbec80ade3bb6a68f3 (patch) | |
tree | eb12013ef1924927c7eda0b323c440fb8d10de0f | |
parent | 06e8a9d9635872338d5ac9956e24590e2ddcfb9e (diff) | |
download | chromium_src-c3bf65f5b6c64414996c80cbec80ade3bb6a68f3.zip chromium_src-c3bf65f5b6c64414996c80cbec80ade3bb6a68f3.tar.gz chromium_src-c3bf65f5b6c64414996c80cbec80ade3bb6a68f3.tar.bz2 |
Make O3D always clear the backbuffer one way or
another.
The issue is that given that we are using DISCARD
on D3D and on GL we are only drawing to the visible
portion of the O3D area, the state of the backbuffer
is undefined. This change should make it consistent
across platforms.
Review URL: http://codereview.chromium.org/201013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25522 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | o3d/core/cross/client.cc | 9 | ||||
-rw-r--r-- | o3d/core/cross/command_buffer/states_cb.cc | 22 | ||||
-rw-r--r-- | o3d/core/cross/gl/render_surface_gl.cc | 13 | ||||
-rw-r--r-- | o3d/core/cross/gl/renderer_gl.cc | 1 | ||||
-rw-r--r-- | o3d/core/cross/render_surface_set.cc | 9 | ||||
-rw-r--r-- | o3d/core/cross/render_surface_set.h | 1 | ||||
-rw-r--r-- | o3d/core/cross/render_surface_test.cc | 84 | ||||
-rw-r--r-- | o3d/core/cross/renderer.cc | 74 | ||||
-rw-r--r-- | o3d/core/cross/renderer.h | 49 | ||||
-rw-r--r-- | o3d/core/win/d3d9/renderer_d3d9.cc | 12 |
10 files changed, 186 insertions, 88 deletions
diff --git a/o3d/core/cross/client.cc b/o3d/core/cross/client.cc index 2e0224d..a7f5924 100644 --- a/o3d/core/cross/client.cc +++ b/o3d/core/cross/client.cc @@ -452,13 +452,16 @@ String Client::GetScreenshotAsDataURL() { const RenderSurface* old_render_surface_; const RenderDepthStencilSurface* old_depth_surface_; + bool is_back_buffer; - renderer_->GetRenderSurfaces(&old_render_surface_, &old_depth_surface_); - renderer_->SetRenderSurfaces(surface, depth); + renderer_->GetRenderSurfaces(&old_render_surface_, &old_depth_surface_, + &is_back_buffer); + renderer_->SetRenderSurfaces(surface, depth, true); RenderClientInner(false, true); - renderer_->SetRenderSurfaces(old_render_surface_, old_depth_surface_); + renderer_->SetRenderSurfaces(old_render_surface_, old_depth_surface_, + is_back_buffer); Bitmap::Ref bitmap(surface->GetBitmap()); if (bitmap.IsNull()) { diff --git a/o3d/core/cross/command_buffer/states_cb.cc b/o3d/core/cross/command_buffer/states_cb.cc index bf29c19..9126069 100644 --- a/o3d/core/cross/command_buffer/states_cb.cc +++ b/o3d/core/cross/command_buffer/states_cb.cc @@ -255,6 +255,26 @@ class BitFieldStateHandler : public TypedStateHandler<ParamInteger> { bool *dirty_; }; +// A handler for the color write state. +class ColorWriteStateHandler : public TypedStateHandler<ParamInteger> { + public: + ColorWriteStateHandler(uint32 *value, bool *dirty) + : value_(value), + dirty_(dirty) { + } + + virtual void SetStateFromTypedParam(RendererCB* renderer, + ParamInteger* param) const { + int mask = param->value(); + o3d::command_buffer::set_color_write::AllColorsMask::Set(value_, mask); + renderer->SetWriteMask(mask); + *dirty_ = true; + } + private: + uint32 *value_; + bool *dirty_; +}; + // A template that generates a handler for full-size values (uint32, int32, // float). // Template Parameters: @@ -618,7 +638,7 @@ void RendererCB::StateManager::AddStateHandlers(RendererCB *renderer) { new EnableStateHandler<DitherEnable>(arg, dirty)); renderer->AddStateHandler( State::kColorWriteEnableParamName, - new BitFieldStateHandler<AllColorsMask>(arg, dirty)); + new ColorWriteStateHandler(arg, dirty)); } } diff --git a/o3d/core/cross/gl/render_surface_gl.cc b/o3d/core/cross/gl/render_surface_gl.cc index 52f7cc9..6570baa 100644 --- a/o3d/core/cross/gl/render_surface_gl.cc +++ b/o3d/core/cross/gl/render_surface_gl.cc @@ -62,16 +62,19 @@ Bitmap::Ref RenderSurfaceGL::PlatformSpecificGetBitmap() const { bitmap->Allocate( Texture::ARGB8, clip_width(), clip_height(), 1, Bitmap::IMAGE); - const RenderSurface* old_render_surface_; - const RenderDepthStencilSurface* old_depth_surface_; + const RenderSurface* old_render_surface; + const RenderDepthStencilSurface* old_depth_surface; + bool old_is_back_buffer; - renderer->GetRenderSurfaces(&old_render_surface_, &old_depth_surface_); - renderer->SetRenderSurfaces(this, NULL); + renderer->GetRenderSurfaces(&old_render_surface, &old_depth_surface, + &old_is_back_buffer); + renderer->SetRenderSurfaces(this, NULL, false); ::glReadPixels(0, 0, clip_width(), clip_height(), GL_BGRA, GL_UNSIGNED_BYTE, bitmap->image_data()); - renderer->SetRenderSurfaces(old_render_surface_, old_depth_surface_); + renderer->SetRenderSurfaces(old_render_surface, old_depth_surface, + old_is_back_buffer); return bitmap; } diff --git a/o3d/core/cross/gl/renderer_gl.cc b/o3d/core/cross/gl/renderer_gl.cc index 90fa3881..b52e324 100644 --- a/o3d/core/cross/gl/renderer_gl.cc +++ b/o3d/core/cross/gl/renderer_gl.cc @@ -492,6 +492,7 @@ class ColorWriteEnableHandler : public TypedStateHandler<ParamInteger> { (mask & 0x2) != 0, (mask & 0x4) != 0, (mask & 0x8) != 0); + renderer->SetWriteMask(mask); } }; diff --git a/o3d/core/cross/render_surface_set.cc b/o3d/core/cross/render_surface_set.cc index 7774b11..7ea058a 100644 --- a/o3d/core/cross/render_surface_set.cc +++ b/o3d/core/cross/render_surface_set.cc @@ -92,10 +92,12 @@ void RenderSurfaceSet::Render(RenderContext* render_context) { } render_context->renderer()->GetRenderSurfaces( &old_render_surface_, - &old_depth_stencil_surface_); + &old_depth_stencil_surface_, + &old_is_back_buffer_); render_context->renderer()->SetRenderSurfaces( render_surface(), - render_depth_stencil_surface()); + render_depth_stencil_surface(), + false); } void RenderSurfaceSet::PostRender(RenderContext* render_context) { @@ -103,7 +105,8 @@ void RenderSurfaceSet::PostRender(RenderContext* render_context) { return; } render_context->renderer()->SetRenderSurfaces(old_render_surface_, - old_depth_stencil_surface_); + old_depth_stencil_surface_, + old_is_back_buffer_); } } // namespace o3d diff --git a/o3d/core/cross/render_surface_set.h b/o3d/core/cross/render_surface_set.h index f46e1ab..d843df0 100644 --- a/o3d/core/cross/render_surface_set.h +++ b/o3d/core/cross/render_surface_set.h @@ -100,6 +100,7 @@ class RenderSurfaceSet : public RenderNode { const RenderSurface* old_render_surface_; const RenderDepthStencilSurface* old_depth_stencil_surface_; + bool old_is_back_buffer_; ParamRenderSurface::Ref render_surface_param_; ParamRenderDepthStencilSurface::Ref render_depth_stencil_surface_param_; diff --git a/o3d/core/cross/render_surface_test.cc b/o3d/core/cross/render_surface_test.cc index fd45a90..c70b3e0 100644 --- a/o3d/core/cross/render_surface_test.cc +++ b/o3d/core/cross/render_surface_test.cc @@ -47,30 +47,6 @@ extern o3d::DisplayWindow* g_display_window; namespace o3d {
-class MockRenderer {
- public:
- explicit MockRenderer(Renderer* renderer)
- : renderer_(renderer) {}
- virtual ~MockRenderer() {}
-
- void StartRendering() {
- renderer_->set_rendering(true);
- }
- void FinishRendering() {
- renderer_->set_rendering(false);
- }
- void SetRenderSurfaces(const RenderSurface* surface, - const RenderDepthStencilSurface* depth_surface) {
- renderer_->SetRenderSurfaces(surface, depth_surface);
- }
- void GetRenderSurfaces(const RenderSurface** surface, - const RenderDepthStencilSurface** depth_surface) {
- renderer_->GetRenderSurfaces(surface, depth_surface);
- }
- private:
- Renderer* renderer_;
-};
-
class RenderSurfaceTest : public testing::Test {
public:
RenderSurfaceTest()
@@ -80,8 +56,8 @@ class RenderSurfaceTest : public testing::Test { return service_locator_;
}
- MockRenderer* renderer() {
- return renderer_;
+ Renderer* renderer() {
+ return g_renderer;
}
protected:
@@ -89,16 +65,14 @@ class RenderSurfaceTest : public testing::Test { service_locator_ = new ServiceLocator;
features_ = new Features(service_locator_);
pack_ = object_manager_->CreatePack();
- renderer_ = new MockRenderer(g_renderer);
- renderer_->StartRendering();
+ g_renderer->StartRendering();
}
virtual void TearDown() {
- renderer_->FinishRendering();
+ g_renderer->FinishRendering();
pack_->Destroy();
delete features_;
delete service_locator_;
- delete renderer_;
}
Pack* pack() { return pack_; }
@@ -107,7 +81,6 @@ class RenderSurfaceTest : public testing::Test { ServiceLocator* service_locator_;
Features* features_;
Pack* pack_;
- MockRenderer* renderer_;
};
// Test that non PoT textures can't make render surfaces
@@ -151,41 +124,15 @@ TEST_F(RenderSurfaceTest, SwapRenderSurfaces) { pack()->CreateDepthStencilSurface(16, 32);
// Now swap surfaces.
- renderer()->SetRenderSurfaces(render_surface, depth_surface);
+ renderer()->SetRenderSurfaces(render_surface, depth_surface, false);
const RenderSurface* test_render_surface = NULL;
const RenderDepthStencilSurface* test_depth_surface = NULL;
- renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface);
+ bool test_is_back_buffer;
+ renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface,
+ &test_is_back_buffer);
ASSERT_TRUE(test_render_surface == render_surface);
ASSERT_TRUE(test_depth_surface == depth_surface);
-}
-
-TEST_F(RenderSurfaceTest, SetBackSurfaces) {
- Texture2D* texture = pack()->CreateTexture2D(16, 32, Texture::ARGB8, 2, true);
- ASSERT_TRUE(NULL != texture);
-
- RenderSurface::Ref render_surface = texture->GetRenderSurface(0);
- ASSERT_TRUE(NULL != render_surface);
- ASSERT_TRUE(texture == render_surface->texture());
-
- RenderDepthStencilSurface* depth_surface =
- pack()->CreateDepthStencilSurface(16, 32);
-
- // Save the original surfaces for comparison.
- const RenderSurface* original_render_surface = NULL;
- const RenderDepthStencilSurface* original_depth_surface = NULL;
- renderer()->GetRenderSurfaces(&original_render_surface,
- &original_depth_surface);
- // Now swap surfaces.
- renderer()->SetRenderSurfaces(render_surface, depth_surface);
- // Return the back buffers
- renderer()->SetRenderSurfaces(NULL, NULL);
- // Get the original surfaces again for comparison.
- const RenderSurface* restored_render_surface = NULL;
- const RenderDepthStencilSurface* restored_depth_surface = NULL;
- renderer()->GetRenderSurfaces(&original_render_surface,
- &original_depth_surface);
- ASSERT_TRUE(original_render_surface == restored_render_surface);
- ASSERT_TRUE(original_depth_surface == restored_depth_surface);
+ ASSERT_FALSE(test_is_back_buffer);
}
TEST_F(RenderSurfaceTest, RenderSurfaceSetTest) {
@@ -208,19 +155,26 @@ TEST_F(RenderSurfaceTest, RenderSurfaceSetTest) { const RenderSurface* old_render_surface = NULL;
const RenderDepthStencilSurface* old_depth_surface = NULL;
- renderer()->GetRenderSurfaces(&old_render_surface, &old_depth_surface);
+ bool old_is_back_buffer = false;
+ renderer()->GetRenderSurfaces(&old_render_surface, &old_depth_surface,
+ &old_is_back_buffer);
render_surface_set->Render(&render_context);
const RenderSurface* test_render_surface = NULL;
const RenderDepthStencilSurface* test_depth_surface = NULL;
- renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface);
+ bool test_is_back_buffer = false;
+ renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface,
+ &test_is_back_buffer);
ASSERT_TRUE(test_render_surface == render_surface);
ASSERT_TRUE(test_depth_surface == depth_surface);
+ ASSERT_FALSE(test_is_back_buffer);
render_surface_set->PostRender(&render_context);
- renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface);
+ renderer()->GetRenderSurfaces(&test_render_surface, &test_depth_surface,
+ &test_is_back_buffer);
ASSERT_TRUE(test_render_surface == old_render_surface);
ASSERT_TRUE(test_depth_surface == old_depth_surface);
+ ASSERT_TRUE(test_is_back_buffer == old_is_back_buffer);
}
} // namespace o3d
diff --git a/o3d/core/cross/renderer.cc b/o3d/core/cross/renderer.cc index 9bc9cf5..846c59c 100644 --- a/o3d/core/cross/renderer.cc +++ b/o3d/core/cross/renderer.cc @@ -101,11 +101,13 @@ bool Renderer::IsForceSoftwareRenderer() { Renderer::Renderer(ServiceLocator* service_locator) : current_render_surface_(NULL), current_depth_surface_(NULL), + current_render_surface_is_back_buffer_(true), service_locator_(service_locator), service_(service_locator, this), features_(service_locator), viewport_(0.0f, 0.0f, 1.0f, 1.0f), depth_range_(0.0f, 1.0f), + write_mask_(0xf), render_frame_count_(0), transforms_processed_(0), transforms_culled_(0), @@ -124,7 +126,8 @@ Renderer::Renderer(ServiceLocator* service_locator) display_height_(0), dest_x_offset_(0), dest_y_offset_(0), - supports_npot_(false) { + supports_npot_(false), + back_buffer_cleared_(false) { } Renderer::~Renderer() { @@ -259,6 +262,8 @@ bool Renderer::StartRendering() { draw_elements_processed_ = 0; draw_elements_rendered_ = 0; primitives_rendered_ = 0; + back_buffer_cleared_ = 0; + current_render_surface_is_back_buffer_ = true; result = PlatformSpecificStartRendering(); if (result) { @@ -317,9 +322,57 @@ void Renderer::Clear(const Float4 &color, bool depth_flag, int stencil, bool stencil_flag) { + // If we are currently rendering to the backbuffer and it has not been cleared + // AND if we are not about to clear it entirely then clear it. + bool covers_everything = false; + if (!back_buffer_cleared_ && current_render_surface_is_back_buffer_) { + covers_everything = + !(viewport_[0] != 0.0f || viewport_[1] != 0.0f || + viewport_[2] != 1.0f || viewport_[3] != 1.0f || + depth_range_[0] != 0.0f || depth_range_[1] != 1.0f) && + color_flag && depth_flag && stencil_flag && write_mask_ == 0xF; + if (!covers_everything) { + ClearBackBuffer(); + } + } + ApplyDirtyStates(); PlatformSpecificClear( color, color_flag, depth, depth_flag, stencil, stencil_flag); + + // If we are currently rendering to the backbuffer and it has not been cleared + // and we just cleared everything then mark it as cleared. + if (!back_buffer_cleared_ && current_render_surface_is_back_buffer_ && + covers_everything) { + back_buffer_cleared_ = true; + } +} + +void Renderer::ClearBackBuffer() { + DCHECK(rendering_); + DCHECK(!back_buffer_cleared_); + DCHECK(current_render_surface_is_back_buffer_); + + // Save all states that would effect clear the back buffer. + Float4 old_viewport; + Float2 old_depth_range; + GetViewport(&old_viewport, &old_depth_range); + + // Set the states needed to clear the entire backbuffer. + SetViewport(Float4(0.0f, 0.0f, 1.0f, 1.0f), Float2(0.0f, 1.0f)); + PushRenderStates(clear_back_buffer_state_); + ApplyDirtyStates(); + + // Clear the backbuffer. + PlatformSpecificClear( + Float4(0.5f, 0.5f, 0.5f, 1.0f), true, + 0.0f, true, + 0, true); + back_buffer_cleared_ = true; + + // restore the states. + SetViewport(old_viewport, old_depth_range); + PopRenderStates(); } void Renderer::GetViewport(Float4* viewport, Float2* depth_range) { @@ -475,8 +528,12 @@ void CreateStateParam(State *state, } void Renderer::AddDefaultStates() { + // TODO(gman): It's possible for the user to get these out of the client + // and then change them which could lead to inconsistent results. default_state_ = State::Ref(new State(service_locator_, this)); default_state_->set_name(O3D_STRING_CONSTANT("defaultState")); + clear_back_buffer_state_ = State::Ref(new State(service_locator_, this)); + clear_back_buffer_state_->set_name(O3D_STRING_CONSTANT("clearState")); CreateStateParam<ParamBoolean>(default_state_, State::kAlphaTestEnableParamName, @@ -605,6 +662,10 @@ void Renderer::AddDefaultStates() { DCHECK(param_stack.empty()); param_stack.push_back(param); } + + CreateStateParam<ParamInteger>(clear_back_buffer_state_, + State::kColorWriteEnableParamName, + 0xf); } void Renderer::RemoveDefaultStates() { @@ -647,6 +708,7 @@ void Renderer::RenderElement(Element* element, Material* material, ParamObject* override, ParamCache* param_cache) { + ClearBackBufferIfNotCleared(); IncrementDrawElementsRendered(); State *current_state = material ? material->state() : NULL; PushRenderStates(current_state); @@ -707,8 +769,10 @@ void Renderer::PopRenderStates() { void Renderer::SetRenderSurfaces( const RenderSurface* surface, - const RenderDepthStencilSurface* depth_surface) { + const RenderDepthStencilSurface* depth_surface, + bool is_back_buffer) { DCHECK(rendering_); + current_render_surface_is_back_buffer_ = is_back_buffer; if (surface != NULL || depth_surface != NULL) { SetRenderSurfacesPlatformSpecific(surface, depth_surface); current_render_surface_ = surface; @@ -733,11 +797,15 @@ void Renderer::SetRenderSurfaces( void Renderer::GetRenderSurfaces( const RenderSurface** surface, - const RenderDepthStencilSurface** depth_surface) { + const RenderDepthStencilSurface** depth_surface, + bool* is_back_buffer) { + DCHECK(rendering_); DCHECK(surface); DCHECK(depth_surface); + DCHECK(is_back_buffer); *surface = current_render_surface_; *depth_surface = current_depth_surface_; + *is_back_buffer = current_render_surface_is_back_buffer_; } bool Renderer::SafeToBindTexture(Texture* texture) const { diff --git a/o3d/core/cross/renderer.h b/o3d/core/cross/renderer.h index 3328e4d..20c6086 100644 --- a/o3d/core/cross/renderer.h +++ b/o3d/core/cross/renderer.h @@ -296,8 +296,11 @@ class Renderer { // surface: RenderSurface to bind to the color buffer. // depth_surface: RenderDepthStencilSurface to bind to the depth/stencil // buffer. + // is_back_buffer: True if the render surface being set should be considered + // the backbuffer. void SetRenderSurfaces(const RenderSurface* surface, - const RenderDepthStencilSurface* depth_surface); + const RenderDepthStencilSurface* depth_surface, + bool is_back_buffer); // Gets the current render surfaces. // Parameters: @@ -305,8 +308,11 @@ class Renderer { // buffer. // depth_surface: pointer to variable to hold RenderDepthStencilSurface to // bind to the depth/stencil buffer. + // is_back_buffer: pointer to variable to hold whether or not the surface + // returned is the back buffer. void GetRenderSurfaces(const RenderSurface** surface, - const RenderDepthStencilSurface** depth_surface); + const RenderDepthStencilSurface** depth_surface, + bool* is_back_buffer); // Creates a StreamBank, returning a platform specific implementation class. virtual StreamBank::Ref CreateStreamBank() = 0; @@ -518,6 +524,14 @@ class Renderer { rendering_ = rendering; } + // Used only by the ColorWriteEnable state handlers. Should not be used + // elsewhere. + // Sets the write mask. This must be called by platform specific renderers + // when the color write mask is changed. + void SetWriteMask(int mask) { + write_mask_ = mask & 0xF; + } + protected: typedef vector_map<String, StateHandler*> StateHandlerMap; typedef std::vector<ParamVector> ParamVectorArray; @@ -618,6 +632,7 @@ class Renderer { // The current render surfaces. NULL = no surface. const RenderSurface* current_render_surface_; const RenderDepthStencilSurface* current_depth_surface_; + bool current_render_surface_is_back_buffer_; Sampler::Ref error_sampler_; // sampler used when one is missing. Texture::Ref error_texture_; // texture used when one is missing. @@ -638,6 +653,10 @@ class Renderer { // State object holding the default state settings. State::Ref default_state_; + // A State object holding the settings required to be able to clear the + // back buffer. + State::Ref clear_back_buffer_state_; + // Lost Resources Callbacks. LostResourcesCallbackManager lost_resources_callback_manager_; @@ -654,6 +673,22 @@ class Renderer { } private: + // Adds the default states to their respective stacks. + void AddDefaultStates(); + + // Removes the default states from their respective stacks. + void RemoveDefaultStates(); + + // Clears the backbuffer. + void ClearBackBuffer(); + + // Clears the backbuffer if it has not been cleared. + void ClearBackBufferIfNotCleared() { + if (!back_buffer_cleared_ && current_render_surface_is_back_buffer_) { + ClearBackBuffer(); + } + } + ServiceLocator* service_locator_; ServiceImplementation<Renderer> service_; ServiceDependency<Features> features_; @@ -664,6 +699,9 @@ class Renderer { // Current depth range. Float2 depth_range_; + // Current write mask. + int write_mask_; + int render_frame_count_; // count of times we've rendered frame. int transforms_processed_; // count of transforms processed this frame. int transforms_culled_; // count of transforms culled this frame. @@ -702,11 +740,8 @@ class Renderer { // Whether or not the underlying API supports non-power-of-two textures. bool supports_npot_; - // Adds the default states to their respective stacks. - void AddDefaultStates(); - - // Removes the default states from their respective stacks. - void RemoveDefaultStates(); + // Whether the backbuffer has been cleared this frame. + bool back_buffer_cleared_; DISALLOW_COPY_AND_ASSIGN(Renderer); }; diff --git a/o3d/core/win/d3d9/renderer_d3d9.cc b/o3d/core/win/d3d9/renderer_d3d9.cc index 1089723..6a92bb9 100644 --- a/o3d/core/win/d3d9/renderer_d3d9.cc +++ b/o3d/core/win/d3d9/renderer_d3d9.cc @@ -735,6 +735,16 @@ class IntegerStateHandler : public TypedStateHandler<ParamInteger> { } }; +class ColorWriteStateHandler : public TypedStateHandler<ParamInteger> { + public: + virtual void SetStateFromTypedParam(RendererD3D9* renderer, + ParamInteger* param) const { + int mask = param->value(); + HR(renderer->d3d_device()->SetRenderState(D3DRS_COLORWRITEENABLE, mask)); + renderer->SetWriteMask(mask); + } +}; + class AlphaReferenceHandler : public TypedStateHandler<ParamFloat> { public: virtual void SetStateFromTypedParam(RendererD3D9* renderer, @@ -888,7 +898,7 @@ RendererD3D9::RendererD3D9(ServiceLocator* service_locator) AddStateHandler(State::kStencilWriteMaskParamName, new IntegerStateHandler<D3DRS_STENCILWRITEMASK>); AddStateHandler(State::kColorWriteEnableParamName, - new IntegerStateHandler<D3DRS_COLORWRITEENABLE>); + new ColorWriteStateHandler); AddStateHandler(State::kBlendEquationParamName, new BlendEquationHandler<D3DRS_BLENDOP>); AddStateHandler(State::kTwoSidedStencilEnableParamName, |