1 //
2 // Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // StateManager9.cpp: Defines a class for caching D3D9 state
8 #include "libANGLE/renderer/d3d/d3d9/StateManager9.h"
9 
10 #include "common/BitSetIterator.h"
11 #include "common/utilities.h"
12 #include "libANGLE/formatutils.h"
13 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
14 #include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
15 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
16 
17 namespace rx
18 {
19 
StateManager9(Renderer9 * renderer9)20 StateManager9::StateManager9(Renderer9 *renderer9)
21     : mUsingZeroColorMaskWorkaround(false),
22       mCurBlendState(),
23       mCurBlendColor(0, 0, 0, 0),
24       mCurSampleMask(0),
25       mCurRasterState(),
26       mCurDepthSize(0),
27       mCurDepthStencilState(),
28       mCurStencilRef(0),
29       mCurStencilBackRef(0),
30       mCurFrontFaceCCW(0),
31       mCurStencilSize(0),
32       mCurScissorRect(),
33       mCurScissorEnabled(false),
34       mCurViewport(),
35       mCurNear(0.0f),
36       mCurFar(0.0f),
37       mCurDepthFront(0.0f),
38       mCurIgnoreViewport(false),
39       mRenderer9(renderer9),
40       mDirtyBits()
41 {
42     mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
43     mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
44     mBlendStateDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
45     mBlendStateDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE);
46     mBlendStateDirtyBits.set(DIRTY_BIT_COLOR_MASK);
47     mBlendStateDirtyBits.set(DIRTY_BIT_DITHER);
48     mBlendStateDirtyBits.set(DIRTY_BIT_SAMPLE_MASK);
49 
50     mRasterizerStateDirtyBits.set(DIRTY_BIT_CULL_MODE);
51     mRasterizerStateDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
52 
53     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_MASK);
54     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
55     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED);
56     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
57     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
58     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
59     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
60     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
61     mDepthStencilStateDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
62 
63     mScissorStateDirtyBits.set(DIRTY_BIT_SCISSOR_ENABLED);
64     mScissorStateDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
65 }
66 
~StateManager9()67 StateManager9::~StateManager9()
68 {
69 }
70 
initialize()71 void StateManager9::initialize()
72 {
73     mUsingZeroColorMaskWorkaround = IsAMD(mRenderer9->getVendorId());
74 }
75 
forceSetBlendState()76 void StateManager9::forceSetBlendState()
77 {
78     mDirtyBits |= mBlendStateDirtyBits;
79 }
80 
forceSetRasterState()81 void StateManager9::forceSetRasterState()
82 {
83     mDirtyBits |= mRasterizerStateDirtyBits;
84 }
85 
forceSetDepthStencilState()86 void StateManager9::forceSetDepthStencilState()
87 {
88     mDirtyBits |= mDepthStencilStateDirtyBits;
89 }
90 
forceSetScissorState()91 void StateManager9::forceSetScissorState()
92 {
93     mDirtyBits |= mScissorStateDirtyBits;
94 }
95 
forceSetViewportState()96 void StateManager9::forceSetViewportState()
97 {
98     mForceSetViewport = true;
99 }
100 
forceSetDXUniformsState()101 void StateManager9::forceSetDXUniformsState()
102 {
103     mDxUniformsDirty = true;
104 }
105 
updateStencilSizeIfChanged(bool depthStencilInitialized,unsigned int stencilSize)106 void StateManager9::updateStencilSizeIfChanged(bool depthStencilInitialized,
107                                                unsigned int stencilSize)
108 {
109     if (!depthStencilInitialized || stencilSize != mCurStencilSize)
110     {
111         mCurStencilSize = stencilSize;
112         forceSetDepthStencilState();
113     }
114 }
115 
syncState(const gl::State & state,const gl::State::DirtyBits & dirtyBits)116 void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits &dirtyBits)
117 {
118     if (!dirtyBits.any())
119     {
120         return;
121     }
122 
123     for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
124     {
125         switch (dirtyBit)
126         {
127             case gl::State::DIRTY_BIT_BLEND_ENABLED:
128                 if (state.getBlendState().blend != mCurBlendState.blend)
129                 {
130                     mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
131                     // BlendColor and funcs and equations has to be set if blend is enabled
132                     mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
133                     mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
134 
135                     // The color mask may have to be updated if the blend state changes
136                     if (mUsingZeroColorMaskWorkaround)
137                     {
138                         mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
139                     }
140                 }
141                 break;
142             case gl::State::DIRTY_BIT_BLEND_FUNCS:
143             {
144                 const gl::BlendState &blendState = state.getBlendState();
145                 if (blendState.sourceBlendRGB != mCurBlendState.sourceBlendRGB ||
146                     blendState.destBlendRGB != mCurBlendState.destBlendRGB ||
147                     blendState.sourceBlendAlpha != mCurBlendState.sourceBlendAlpha ||
148                     blendState.destBlendAlpha != mCurBlendState.destBlendAlpha)
149                 {
150                     mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
151                     // BlendColor depends on the values of blend funcs
152                     mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
153 
154                     // The color mask may have to be updated if the blend funcs change
155                     if (mUsingZeroColorMaskWorkaround)
156                     {
157                         mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
158                     }
159                 }
160                 break;
161             }
162             case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
163             {
164                 const gl::BlendState &blendState = state.getBlendState();
165                 if (blendState.blendEquationRGB != mCurBlendState.blendEquationRGB ||
166                     blendState.blendEquationAlpha != mCurBlendState.blendEquationAlpha)
167                 {
168                     mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
169 
170                     // The color mask may have to be updated if the blend funcs change
171                     if (mUsingZeroColorMaskWorkaround)
172                     {
173                         mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
174                     }
175                 }
176                 break;
177             }
178             case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
179                 if (state.getBlendState().sampleAlphaToCoverage !=
180                     mCurBlendState.sampleAlphaToCoverage)
181                 {
182                     mDirtyBits.set(DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE);
183                 }
184                 break;
185             case gl::State::DIRTY_BIT_COLOR_MASK:
186             {
187                 const gl::BlendState &blendState = state.getBlendState();
188                 if (blendState.colorMaskRed != mCurBlendState.colorMaskRed ||
189                     blendState.colorMaskGreen != mCurBlendState.colorMaskGreen ||
190                     blendState.colorMaskBlue != mCurBlendState.colorMaskBlue ||
191                     blendState.colorMaskAlpha != mCurBlendState.colorMaskAlpha)
192                 {
193                     mDirtyBits.set(DIRTY_BIT_COLOR_MASK);
194 
195                     // The color mask can cause the blend state to get out of sync when using the
196                     // zero color mask workaround
197                     if (mUsingZeroColorMaskWorkaround)
198                     {
199                         mDirtyBits.set(DIRTY_BIT_BLEND_ENABLED);
200                         mDirtyBits.set(DIRTY_BIT_BLEND_FUNCS_EQUATIONS);
201                     }
202                 }
203                 break;
204             }
205             case gl::State::DIRTY_BIT_DITHER_ENABLED:
206                 if (state.getBlendState().dither != mCurBlendState.dither)
207                 {
208                     mDirtyBits.set(DIRTY_BIT_DITHER);
209                 }
210                 break;
211             case gl::State::DIRTY_BIT_BLEND_COLOR:
212                 if (state.getBlendColor() != mCurBlendColor)
213                 {
214                     mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
215                 }
216                 break;
217             case gl::State::DIRTY_BIT_CULL_FACE_ENABLED:
218                 if (state.getRasterizerState().cullFace != mCurRasterState.cullFace)
219                 {
220                     mDirtyBits.set(DIRTY_BIT_CULL_MODE);
221                 }
222                 break;
223             case gl::State::DIRTY_BIT_CULL_FACE:
224                 if (state.getRasterizerState().cullMode != mCurRasterState.cullMode)
225                 {
226                     mDirtyBits.set(DIRTY_BIT_CULL_MODE);
227                 }
228                 break;
229             case gl::State::DIRTY_BIT_FRONT_FACE:
230                 if (state.getRasterizerState().frontFace != mCurRasterState.frontFace)
231                 {
232                     mDirtyBits.set(DIRTY_BIT_CULL_MODE);
233 
234                     // Viewport state depends on rasterizer.frontface
235                     mDirtyBits.set(DIRTY_BIT_VIEWPORT);
236                 }
237                 break;
238             case gl::State::DIRTY_BIT_POLYGON_OFFSET_FILL_ENABLED:
239                 if (state.getRasterizerState().polygonOffsetFill !=
240                     mCurRasterState.polygonOffsetFill)
241                 {
242                     mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
243                 }
244                 break;
245             case gl::State::DIRTY_BIT_POLYGON_OFFSET:
246             {
247                 const gl::RasterizerState &rasterizerState = state.getRasterizerState();
248                 if (rasterizerState.polygonOffsetFactor != mCurRasterState.polygonOffsetFactor ||
249                     rasterizerState.polygonOffsetUnits != mCurRasterState.polygonOffsetUnits)
250                 {
251                     mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS);
252                 }
253             }
254             case gl::State::DIRTY_BIT_DEPTH_MASK:
255                 if (state.getDepthStencilState().depthMask != mCurDepthStencilState.depthMask)
256                 {
257                     mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_MASK);
258                 }
259                 break;
260             case gl::State::DIRTY_BIT_DEPTH_TEST_ENABLED:
261                 if (state.getDepthStencilState().depthTest != mCurDepthStencilState.depthTest)
262                 {
263                     mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
264                 }
265                 break;
266             case gl::State::DIRTY_BIT_DEPTH_FUNC:
267                 if (state.getDepthStencilState().depthFunc != mCurDepthStencilState.depthFunc)
268                 {
269                     mDirtyBits.set(DIRTY_BIT_STENCIL_DEPTH_FUNC);
270                 }
271                 break;
272             case gl::State::DIRTY_BIT_STENCIL_TEST_ENABLED:
273                 if (state.getDepthStencilState().stencilTest != mCurDepthStencilState.stencilTest)
274                 {
275                     mDirtyBits.set(DIRTY_BIT_STENCIL_TEST_ENABLED);
276                     // If we enable the stencil test, all of these must be set
277                     mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
278                     mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
279                     mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
280                     mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
281                     mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
282                     mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
283                 }
284                 break;
285             case gl::State::DIRTY_BIT_STENCIL_FUNCS_FRONT:
286             {
287                 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
288                 if (depthStencilState.stencilFunc != mCurDepthStencilState.stencilFunc ||
289                     depthStencilState.stencilMask != mCurDepthStencilState.stencilMask ||
290                     state.getStencilRef() != mCurStencilRef)
291                 {
292                     mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_FRONT);
293                 }
294                 break;
295             }
296             case gl::State::DIRTY_BIT_STENCIL_FUNCS_BACK:
297             {
298                 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
299                 if (depthStencilState.stencilBackFunc != mCurDepthStencilState.stencilBackFunc ||
300                     depthStencilState.stencilBackMask != mCurDepthStencilState.stencilBackMask ||
301                     state.getStencilBackRef() != mCurStencilBackRef)
302                 {
303                     mDirtyBits.set(DIRTY_BIT_STENCIL_FUNCS_BACK);
304                 }
305                 break;
306             }
307             case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
308                 if (state.getDepthStencilState().stencilWritemask !=
309                     mCurDepthStencilState.stencilWritemask)
310                 {
311                     mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_FRONT);
312                 }
313                 break;
314             case gl::State::DIRTY_BIT_STENCIL_WRITEMASK_BACK:
315                 if (state.getDepthStencilState().stencilBackWritemask !=
316                     mCurDepthStencilState.stencilBackWritemask)
317                 {
318                     mDirtyBits.set(DIRTY_BIT_STENCIL_WRITEMASK_BACK);
319                 }
320                 break;
321             case gl::State::DIRTY_BIT_STENCIL_OPS_FRONT:
322             {
323                 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
324                 if (depthStencilState.stencilFail != mCurDepthStencilState.stencilFail ||
325                     depthStencilState.stencilPassDepthFail !=
326                         mCurDepthStencilState.stencilPassDepthFail ||
327                     depthStencilState.stencilPassDepthPass !=
328                         mCurDepthStencilState.stencilPassDepthPass)
329                 {
330                     mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_FRONT);
331                 }
332                 break;
333             }
334             case gl::State::DIRTY_BIT_STENCIL_OPS_BACK:
335             {
336                 const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
337                 if (depthStencilState.stencilBackFail != mCurDepthStencilState.stencilBackFail ||
338                     depthStencilState.stencilBackPassDepthFail !=
339                         mCurDepthStencilState.stencilBackPassDepthFail ||
340                     depthStencilState.stencilBackPassDepthPass !=
341                         mCurDepthStencilState.stencilBackPassDepthPass)
342                 {
343                     mDirtyBits.set(DIRTY_BIT_STENCIL_OPS_BACK);
344                 }
345                 break;
346             }
347             case gl::State::DIRTY_BIT_SCISSOR_TEST_ENABLED:
348                 if (state.isScissorTestEnabled() != mCurScissorEnabled)
349                 {
350                     mDirtyBits.set(DIRTY_BIT_SCISSOR_ENABLED);
351                     // If scissor is enabled, we have to set the scissor rect
352                     mDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
353                 }
354                 break;
355             case gl::State::DIRTY_BIT_SCISSOR:
356                 if (state.getScissor() != mCurScissorRect)
357                 {
358                     mDirtyBits.set(DIRTY_BIT_SCISSOR_RECT);
359                 }
360                 break;
361             case gl::State::DIRTY_BIT_DEPTH_RANGE:
362                 if (state.getNearPlane() != mCurNear || state.getFarPlane() != mCurFar)
363                 {
364                     mDirtyBits.set(DIRTY_BIT_VIEWPORT);
365                 }
366                 break;
367             case gl::State::DIRTY_BIT_VIEWPORT:
368                 if (state.getViewport() != mCurViewport)
369                 {
370                     mDirtyBits.set(DIRTY_BIT_VIEWPORT);
371                 }
372                 break;
373             default:
374                 break;
375         }
376     }
377 }
378 
setBlendDepthRasterStates(const gl::State & glState,unsigned int sampleMask)379 gl::Error StateManager9::setBlendDepthRasterStates(const gl::State &glState,
380                                                    unsigned int sampleMask)
381 {
382     const gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
383 
384     const gl::BlendState &blendState       = glState.getBlendState();
385     const gl::ColorF &blendColor           = glState.getBlendColor();
386     const gl::RasterizerState &rasterState = glState.getRasterizerState();
387 
388     const auto &depthStencilState = glState.getDepthStencilState();
389     bool frontFaceCCW             = (glState.getRasterizerState().frontFace == GL_CCW);
390     unsigned int maxStencil       = (1 << mCurStencilSize) - 1;
391 
392     // All the depth stencil states depends on the front face ccw variable
393     if (frontFaceCCW != mCurFrontFaceCCW)
394     {
395         forceSetDepthStencilState();
396         mCurFrontFaceCCW = frontFaceCCW;
397     }
398 
399     for (auto dirtyBit : angle::IterateBitSet(mDirtyBits))
400     {
401         switch (dirtyBit)
402         {
403             case DIRTY_BIT_BLEND_ENABLED:
404                 setBlendEnabled(blendState.blend);
405                 break;
406             case DIRTY_BIT_BLEND_COLOR:
407                 setBlendColor(blendState, blendColor);
408                 break;
409             case DIRTY_BIT_BLEND_FUNCS_EQUATIONS:
410                 setBlendFuncsEquations(blendState);
411                 break;
412             case DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE:
413                 setSampleAlphaToCoverage(blendState.sampleAlphaToCoverage);
414                 break;
415             case DIRTY_BIT_COLOR_MASK:
416                 setColorMask(framebuffer, blendState.colorMaskRed, blendState.colorMaskBlue,
417                              blendState.colorMaskGreen, blendState.colorMaskAlpha);
418                 break;
419             case DIRTY_BIT_DITHER:
420                 setDither(blendState.dither);
421                 break;
422             case DIRTY_BIT_CULL_MODE:
423                 setCullMode(rasterState.cullFace, rasterState.cullMode, rasterState.frontFace);
424                 break;
425             case DIRTY_BIT_DEPTH_BIAS:
426                 setDepthBias(rasterState.polygonOffsetFill, rasterState.polygonOffsetFactor,
427                              rasterState.polygonOffsetUnits);
428                 break;
429             case DIRTY_BIT_STENCIL_DEPTH_MASK:
430                 setDepthMask(depthStencilState.depthMask);
431                 break;
432             case DIRTY_BIT_STENCIL_DEPTH_FUNC:
433                 setDepthFunc(depthStencilState.depthTest, depthStencilState.depthFunc);
434                 break;
435             case DIRTY_BIT_STENCIL_TEST_ENABLED:
436                 setStencilTestEnabled(depthStencilState.stencilTest);
437                 break;
438             case DIRTY_BIT_STENCIL_FUNCS_FRONT:
439                 setStencilFuncsFront(depthStencilState.stencilFunc, depthStencilState.stencilMask,
440                                      glState.getStencilRef(), frontFaceCCW, maxStencil);
441                 break;
442             case DIRTY_BIT_STENCIL_FUNCS_BACK:
443                 setStencilFuncsBack(depthStencilState.stencilBackFunc,
444                                     depthStencilState.stencilBackMask, glState.getStencilBackRef(),
445                                     frontFaceCCW, maxStencil);
446                 break;
447             case DIRTY_BIT_STENCIL_WRITEMASK_FRONT:
448                 setStencilWriteMask(depthStencilState.stencilWritemask, frontFaceCCW);
449                 break;
450             case DIRTY_BIT_STENCIL_WRITEMASK_BACK:
451                 setStencilBackWriteMask(depthStencilState.stencilBackWritemask, frontFaceCCW);
452                 break;
453             case DIRTY_BIT_STENCIL_OPS_FRONT:
454                 setStencilOpsFront(depthStencilState.stencilFail,
455                                    depthStencilState.stencilPassDepthFail,
456                                    depthStencilState.stencilPassDepthPass, frontFaceCCW);
457                 break;
458             case DIRTY_BIT_STENCIL_OPS_BACK:
459                 setStencilOpsBack(depthStencilState.stencilBackFail,
460                                   depthStencilState.stencilBackPassDepthFail,
461                                   depthStencilState.stencilBackPassDepthPass, frontFaceCCW);
462                 break;
463             default:
464                 break;
465         }
466     }
467 
468     if (sampleMask != mCurSampleMask)
469     {
470         setSampleMask(sampleMask);
471     }
472 
473     return gl::Error(GL_NO_ERROR);
474 }
475 
setViewportState(const gl::Rectangle & viewport,float zNear,float zFar,GLenum drawMode,GLenum frontFace,bool ignoreViewport)476 void StateManager9::setViewportState(const gl::Rectangle &viewport,
477                                      float zNear,
478                                      float zFar,
479                                      GLenum drawMode,
480                                      GLenum frontFace,
481                                      bool ignoreViewport)
482 {
483     if (!mDirtyBits.test(DIRTY_BIT_VIEWPORT) && mCurIgnoreViewport == ignoreViewport)
484         return;
485 
486     gl::Rectangle actualViewport = viewport;
487     float actualZNear            = gl::clamp01(zNear);
488     float actualZFar             = gl::clamp01(zFar);
489 
490     if (ignoreViewport)
491     {
492         actualViewport.x      = 0;
493         actualViewport.y      = 0;
494         actualViewport.width  = static_cast<int>(mRenderTargetBounds.width);
495         actualViewport.height = static_cast<int>(mRenderTargetBounds.height);
496         actualZNear           = 0.0f;
497         actualZFar            = 1.0f;
498     }
499 
500     D3DVIEWPORT9 dxViewport;
501     dxViewport.X = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetBounds.width));
502     dxViewport.Y = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetBounds.height));
503     dxViewport.Width =
504         gl::clamp(actualViewport.width, 0,
505                   static_cast<int>(mRenderTargetBounds.width) - static_cast<int>(dxViewport.X));
506     dxViewport.Height =
507         gl::clamp(actualViewport.height, 0,
508                   static_cast<int>(mRenderTargetBounds.height) - static_cast<int>(dxViewport.Y));
509     dxViewport.MinZ = actualZNear;
510     dxViewport.MaxZ = actualZFar;
511 
512     float depthFront = !gl::IsTriangleMode(drawMode) ? 0.0f : (frontFace == GL_CCW ? 1.0f : -1.0f);
513 
514     mRenderer9->getDevice()->SetViewport(&dxViewport);
515 
516     mCurViewport       = actualViewport;
517     mCurNear           = actualZNear;
518     mCurFar            = actualZFar;
519     mCurDepthFront     = depthFront;
520     mCurIgnoreViewport = ignoreViewport;
521 
522     // Setting shader constants
523     dx_VertexConstants9 vc = {};
524     dx_PixelConstants9 pc  = {};
525 
526     vc.viewAdjust[0] =
527         static_cast<float>((actualViewport.width - static_cast<int>(dxViewport.Width)) +
528                            2 * (actualViewport.x - static_cast<int>(dxViewport.X)) - 1) /
529         dxViewport.Width;
530     vc.viewAdjust[1] =
531         static_cast<float>((actualViewport.height - static_cast<int>(dxViewport.Height)) +
532                            2 * (actualViewport.y - static_cast<int>(dxViewport.Y)) - 1) /
533         dxViewport.Height;
534     vc.viewAdjust[2] = static_cast<float>(actualViewport.width) / dxViewport.Width;
535     vc.viewAdjust[3] = static_cast<float>(actualViewport.height) / dxViewport.Height;
536 
537     pc.viewCoords[0] = actualViewport.width * 0.5f;
538     pc.viewCoords[1] = actualViewport.height * 0.5f;
539     pc.viewCoords[2] = actualViewport.x + (actualViewport.width * 0.5f);
540     pc.viewCoords[3] = actualViewport.y + (actualViewport.height * 0.5f);
541 
542     pc.depthFront[0] = (actualZFar - actualZNear) * 0.5f;
543     pc.depthFront[1] = (actualZNear + actualZFar) * 0.5f;
544     pc.depthFront[2] = depthFront;
545 
546     vc.depthRange[0] = actualZNear;
547     vc.depthRange[1] = actualZFar;
548     vc.depthRange[2] = actualZFar - actualZNear;
549 
550     pc.depthRange[0] = actualZNear;
551     pc.depthRange[1] = actualZFar;
552     pc.depthRange[2] = actualZFar - actualZNear;
553 
554     if (memcmp(&vc, &mVertexConstants, sizeof(dx_VertexConstants9)) != 0)
555     {
556         mVertexConstants = vc;
557         mDxUniformsDirty = true;
558     }
559 
560     if (memcmp(&pc, &mPixelConstants, sizeof(dx_PixelConstants9)) != 0)
561     {
562         mPixelConstants  = pc;
563         mDxUniformsDirty = true;
564     }
565 
566     mForceSetViewport = false;
567 }
568 
setShaderConstants()569 void StateManager9::setShaderConstants()
570 {
571     if (!mDxUniformsDirty)
572         return;
573 
574     IDirect3DDevice9 *device = mRenderer9->getDevice();
575     device->SetVertexShaderConstantF(0, reinterpret_cast<float *>(&mVertexConstants),
576                                      sizeof(dx_VertexConstants9) / sizeof(float[4]));
577     device->SetPixelShaderConstantF(0, reinterpret_cast<float *>(&mPixelConstants),
578                                     sizeof(dx_PixelConstants9) / sizeof(float[4]));
579     mDxUniformsDirty = false;
580 }
581 
582 // This is separate from the main state loop because other functions
583 // outside call only setScissorState to update scissor state
setScissorState(const gl::Rectangle & scissor,bool enabled)584 void StateManager9::setScissorState(const gl::Rectangle &scissor, bool enabled)
585 {
586     if (mDirtyBits.test(DIRTY_BIT_SCISSOR_ENABLED))
587         setScissorEnabled(enabled);
588 
589     if (mDirtyBits.test(DIRTY_BIT_SCISSOR_RECT))
590         setScissorRect(scissor, enabled);
591 }
592 
setRenderTargetBounds(size_t width,size_t height)593 void StateManager9::setRenderTargetBounds(size_t width, size_t height)
594 {
595     mRenderTargetBounds.width  = (int)width;
596     mRenderTargetBounds.height = (int)height;
597     forceSetViewportState();
598 }
599 
setScissorEnabled(bool scissorEnabled)600 void StateManager9::setScissorEnabled(bool scissorEnabled)
601 {
602     mRenderer9->getDevice()->SetRenderState(D3DRS_SCISSORTESTENABLE, scissorEnabled ? TRUE : FALSE);
603     mCurScissorEnabled = scissorEnabled;
604 }
605 
setScissorRect(const gl::Rectangle & scissor,bool enabled)606 void StateManager9::setScissorRect(const gl::Rectangle &scissor, bool enabled)
607 {
608     if (!enabled)
609         return;
610 
611     RECT rect;
612     rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetBounds.width));
613     rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetBounds.height));
614     rect.right =
615         gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetBounds.width));
616     rect.bottom =
617         gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetBounds.height));
618     mRenderer9->getDevice()->SetScissorRect(&rect);
619 }
620 
setDepthFunc(bool depthTest,GLenum depthFunc)621 void StateManager9::setDepthFunc(bool depthTest, GLenum depthFunc)
622 {
623     if (depthTest)
624     {
625         IDirect3DDevice9 *device = mRenderer9->getDevice();
626         device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
627         device->SetRenderState(D3DRS_ZFUNC, gl_d3d9::ConvertComparison(depthFunc));
628     }
629     else
630     {
631         mRenderer9->getDevice()->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
632     }
633 
634     mCurDepthStencilState.depthTest = depthTest;
635     mCurDepthStencilState.depthFunc = depthFunc;
636 }
637 
setStencilOpsFront(GLenum stencilFail,GLenum stencilPassDepthFail,GLenum stencilPassDepthPass,bool frontFaceCCW)638 void StateManager9::setStencilOpsFront(GLenum stencilFail,
639                                        GLenum stencilPassDepthFail,
640                                        GLenum stencilPassDepthPass,
641                                        bool frontFaceCCW)
642 {
643     // TODO(dianx) It may be slightly more efficient todo these and other similar areas
644     // with separate dirty bits.
645     IDirect3DDevice9 *device = mRenderer9->getDevice();
646     device->SetRenderState(frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
647                            gl_d3d9::ConvertStencilOp(stencilFail));
648     device->SetRenderState(frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
649                            gl_d3d9::ConvertStencilOp(stencilPassDepthFail));
650     device->SetRenderState(frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
651                            gl_d3d9::ConvertStencilOp(stencilPassDepthPass));
652 
653     mCurDepthStencilState.stencilFail          = stencilFail;
654     mCurDepthStencilState.stencilPassDepthFail = stencilPassDepthFail;
655     mCurDepthStencilState.stencilPassDepthPass = stencilPassDepthPass;
656 }
657 
setStencilOpsBack(GLenum stencilBackFail,GLenum stencilBackPassDepthFail,GLenum stencilBackPassDepthPass,bool frontFaceCCW)658 void StateManager9::setStencilOpsBack(GLenum stencilBackFail,
659                                       GLenum stencilBackPassDepthFail,
660                                       GLenum stencilBackPassDepthPass,
661                                       bool frontFaceCCW)
662 {
663     IDirect3DDevice9 *device = mRenderer9->getDevice();
664     device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
665                            gl_d3d9::ConvertStencilOp(stencilBackFail));
666     device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
667                            gl_d3d9::ConvertStencilOp(stencilBackPassDepthFail));
668     device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
669                            gl_d3d9::ConvertStencilOp(stencilBackPassDepthPass));
670 
671     mCurDepthStencilState.stencilBackFail          = stencilBackFail;
672     mCurDepthStencilState.stencilBackPassDepthFail = stencilBackPassDepthFail;
673     mCurDepthStencilState.stencilBackPassDepthPass = stencilBackPassDepthPass;
674 }
675 
setStencilBackWriteMask(GLuint stencilBackWriteMask,bool frontFaceCCW)676 void StateManager9::setStencilBackWriteMask(GLuint stencilBackWriteMask, bool frontFaceCCW)
677 {
678     mRenderer9->getDevice()->SetRenderState(
679         !frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilBackWriteMask);
680 
681     mCurDepthStencilState.stencilBackWritemask = stencilBackWriteMask;
682 }
683 
setStencilFuncsBack(GLenum stencilBackFunc,GLuint stencilBackMask,GLint stencilBackRef,bool frontFaceCCW,unsigned int maxStencil)684 void StateManager9::setStencilFuncsBack(GLenum stencilBackFunc,
685                                         GLuint stencilBackMask,
686                                         GLint stencilBackRef,
687                                         bool frontFaceCCW,
688                                         unsigned int maxStencil)
689 {
690     IDirect3DDevice9 *device = mRenderer9->getDevice();
691     device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
692                            gl_d3d9::ConvertComparison(stencilBackFunc));
693     device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
694                            (stencilBackRef < (int)maxStencil) ? stencilBackRef : maxStencil);
695     device->SetRenderState(!frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK,
696                            stencilBackMask);
697 
698     mCurDepthStencilState.stencilBackFunc = stencilBackFunc;
699     mCurStencilBackRef                    = stencilBackRef;
700     mCurDepthStencilState.stencilBackMask = stencilBackMask;
701 }
702 
setStencilWriteMask(GLuint stencilWriteMask,bool frontFaceCCW)703 void StateManager9::setStencilWriteMask(GLuint stencilWriteMask, bool frontFaceCCW)
704 {
705     mRenderer9->getDevice()->SetRenderState(
706         frontFaceCCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilWriteMask);
707     mCurDepthStencilState.stencilWritemask = stencilWriteMask;
708 }
709 
setStencilFuncsFront(GLenum stencilFunc,GLuint stencilMask,GLint stencilRef,bool frontFaceCCW,unsigned int maxStencil)710 void StateManager9::setStencilFuncsFront(GLenum stencilFunc,
711                                          GLuint stencilMask,
712                                          GLint stencilRef,
713                                          bool frontFaceCCW,
714                                          unsigned int maxStencil)
715 {
716     IDirect3DDevice9 *device = mRenderer9->getDevice();
717     device->SetRenderState(frontFaceCCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
718                            gl_d3d9::ConvertComparison(stencilFunc));
719     device->SetRenderState(frontFaceCCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF,
720                            (stencilRef < static_cast<int>(maxStencil)) ? stencilRef : maxStencil);
721     device->SetRenderState(frontFaceCCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilMask);
722 
723     mCurDepthStencilState.stencilFunc = stencilFunc;
724     mCurStencilRef                    = stencilRef;
725     mCurDepthStencilState.stencilMask = stencilMask;
726 }
setStencilTestEnabled(bool stencilTestEnabled)727 void StateManager9::setStencilTestEnabled(bool stencilTestEnabled)
728 {
729     if (stencilTestEnabled && mCurStencilSize > 0)
730     {
731         mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, TRUE);
732         mRenderer9->getDevice()->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
733     }
734     else
735     {
736         mRenderer9->getDevice()->SetRenderState(D3DRS_STENCILENABLE, FALSE);
737     }
738 
739     mCurDepthStencilState.stencilTest = stencilTestEnabled;
740 }
741 
setDepthMask(bool depthMask)742 void StateManager9::setDepthMask(bool depthMask)
743 {
744     mRenderer9->getDevice()->SetRenderState(D3DRS_ZWRITEENABLE, depthMask ? TRUE : FALSE);
745     mCurDepthStencilState.depthMask = depthMask;
746 }
747 
748 // TODO(dianx) one bit for sampleAlphaToCoverage
setSampleAlphaToCoverage(bool enabled)749 void StateManager9::setSampleAlphaToCoverage(bool enabled)
750 {
751     if (enabled)
752     {
753         FIXME("Sample alpha to coverage is unimplemented.");
754     }
755 }
756 
setBlendColor(const gl::BlendState & blendState,const gl::ColorF & blendColor)757 void StateManager9::setBlendColor(const gl::BlendState &blendState, const gl::ColorF &blendColor)
758 {
759     if (!blendState.blend)
760         return;
761 
762     if (blendState.sourceBlendRGB != GL_CONSTANT_ALPHA &&
763         blendState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
764         blendState.destBlendRGB != GL_CONSTANT_ALPHA &&
765         blendState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
766     {
767         mRenderer9->getDevice()->SetRenderState(D3DRS_BLENDFACTOR,
768                                                 gl_d3d9::ConvertColor(blendColor));
769     }
770     else
771     {
772         mRenderer9->getDevice()->SetRenderState(
773             D3DRS_BLENDFACTOR,
774             D3DCOLOR_RGBA(gl::unorm<8>(blendColor.alpha), gl::unorm<8>(blendColor.alpha),
775                           gl::unorm<8>(blendColor.alpha), gl::unorm<8>(blendColor.alpha)));
776     }
777     mCurBlendColor = blendColor;
778 }
779 
setBlendFuncsEquations(const gl::BlendState & blendState)780 void StateManager9::setBlendFuncsEquations(const gl::BlendState &blendState)
781 {
782     if (!blendState.blend)
783         return;
784 
785     IDirect3DDevice9 *device = mRenderer9->getDevice();
786 
787     device->SetRenderState(D3DRS_SRCBLEND, gl_d3d9::ConvertBlendFunc(blendState.sourceBlendRGB));
788     device->SetRenderState(D3DRS_DESTBLEND, gl_d3d9::ConvertBlendFunc(blendState.destBlendRGB));
789     device->SetRenderState(D3DRS_BLENDOP, gl_d3d9::ConvertBlendOp(blendState.blendEquationRGB));
790 
791     if (blendState.sourceBlendRGB != blendState.sourceBlendAlpha ||
792         blendState.destBlendRGB != blendState.destBlendAlpha ||
793         blendState.blendEquationRGB != blendState.blendEquationAlpha)
794     {
795         device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
796 
797         device->SetRenderState(D3DRS_SRCBLENDALPHA,
798                                gl_d3d9::ConvertBlendFunc(blendState.sourceBlendAlpha));
799         device->SetRenderState(D3DRS_DESTBLENDALPHA,
800                                gl_d3d9::ConvertBlendFunc(blendState.destBlendAlpha));
801         device->SetRenderState(D3DRS_BLENDOPALPHA,
802                                gl_d3d9::ConvertBlendOp(blendState.blendEquationAlpha));
803     }
804     else
805     {
806         device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
807     }
808 
809     mCurBlendState.sourceBlendRGB     = blendState.sourceBlendRGB;
810     mCurBlendState.destBlendRGB       = blendState.destBlendRGB;
811     mCurBlendState.blendEquationRGB   = blendState.blendEquationRGB;
812     mCurBlendState.blendEquationAlpha = blendState.blendEquationAlpha;
813 }
814 
setBlendEnabled(bool enabled)815 void StateManager9::setBlendEnabled(bool enabled)
816 {
817     mRenderer9->getDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, enabled ? TRUE : FALSE);
818     mCurBlendState.blend = enabled;
819 }
820 
setDither(bool dither)821 void StateManager9::setDither(bool dither)
822 {
823     mRenderer9->getDevice()->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE);
824     mCurBlendState.dither = dither;
825 }
826 
827 // TODO(dianx) one bit for color mask
setColorMask(const gl::Framebuffer * framebuffer,bool red,bool blue,bool green,bool alpha)828 void StateManager9::setColorMask(const gl::Framebuffer *framebuffer,
829                                  bool red,
830                                  bool blue,
831                                  bool green,
832                                  bool alpha)
833 {
834     // Set the color mask
835 
836     const auto *attachment = framebuffer->getFirstColorbuffer();
837     const auto &format     = attachment ? attachment->getFormat() : gl::Format::Invalid();
838 
839     DWORD colorMask = gl_d3d9::ConvertColorMask(
840         format.info->redBits > 0 && red, format.info->greenBits > 0 && green,
841         format.info->blueBits > 0 && blue, format.info->alphaBits > 0 && alpha);
842 
843     // Apparently some ATI cards have a bug where a draw with a zero color write mask can cause
844     // later draws to have incorrect results. Instead, set a nonzero color write mask but modify the
845     // blend state so that no drawing is done.
846     // http://anglebug.com/169
847     if (colorMask == 0 && mUsingZeroColorMaskWorkaround)
848     {
849         IDirect3DDevice9 *device = mRenderer9->getDevice();
850         // Enable green channel, but set blending so nothing will be drawn.
851         device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
852 
853         device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
854 
855         device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
856         device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
857         device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
858 
859         mCurBlendState.colorMaskRed   = false;
860         mCurBlendState.colorMaskGreen = true;
861         mCurBlendState.colorMaskBlue  = false;
862         mCurBlendState.colorMaskAlpha = false;
863 
864         mCurBlendState.blend              = true;
865         mCurBlendState.sourceBlendRGB     = GL_ZERO;
866         mCurBlendState.sourceBlendAlpha   = GL_ZERO;
867         mCurBlendState.destBlendRGB       = GL_ONE;
868         mCurBlendState.destBlendAlpha     = GL_ONE;
869         mCurBlendState.blendEquationRGB   = GL_FUNC_ADD;
870         mCurBlendState.blendEquationAlpha = GL_FUNC_ADD;
871     }
872     else
873     {
874         mRenderer9->getDevice()->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
875 
876         mCurBlendState.colorMaskRed   = red;
877         mCurBlendState.colorMaskGreen = green;
878         mCurBlendState.colorMaskBlue  = blue;
879         mCurBlendState.colorMaskAlpha = alpha;
880     }
881 }
882 
setSampleMask(unsigned int sampleMask)883 void StateManager9::setSampleMask(unsigned int sampleMask)
884 {
885     IDirect3DDevice9 *device = mRenderer9->getDevice();
886     // Set the multisample mask
887     device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
888     device->SetRenderState(D3DRS_MULTISAMPLEMASK, static_cast<DWORD>(sampleMask));
889 
890     mCurSampleMask = sampleMask;
891 }
892 
setCullMode(bool cullFace,GLenum cullMode,GLenum frontFace)893 void StateManager9::setCullMode(bool cullFace, GLenum cullMode, GLenum frontFace)
894 {
895     if (cullFace)
896     {
897         mRenderer9->getDevice()->SetRenderState(D3DRS_CULLMODE,
898                                                 gl_d3d9::ConvertCullMode(cullMode, frontFace));
899     }
900     else
901     {
902         mRenderer9->getDevice()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
903     }
904 
905     mCurRasterState.cullFace  = cullFace;
906     mCurRasterState.cullMode  = cullMode;
907     mCurRasterState.frontFace = frontFace;
908 }
909 
setDepthBias(bool polygonOffsetFill,GLfloat polygonOffsetFactor,GLfloat polygonOffsetUnits)910 void StateManager9::setDepthBias(bool polygonOffsetFill,
911                                  GLfloat polygonOffsetFactor,
912                                  GLfloat polygonOffsetUnits)
913 {
914     if (polygonOffsetFill)
915     {
916         if (mCurDepthSize > 0)
917         {
918             IDirect3DDevice9 *device = mRenderer9->getDevice();
919             device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD *)&polygonOffsetFactor);
920 
921             float depthBias = ldexp(polygonOffsetUnits, -static_cast<int>(mCurDepthSize));
922             device->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD *)&depthBias);
923         }
924     }
925     else
926     {
927         IDirect3DDevice9 *device = mRenderer9->getDevice();
928         device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
929         device->SetRenderState(D3DRS_DEPTHBIAS, 0);
930     }
931 
932     mCurRasterState.polygonOffsetFill   = polygonOffsetFill;
933     mCurRasterState.polygonOffsetFactor = polygonOffsetFactor;
934     mCurRasterState.polygonOffsetUnits  = polygonOffsetUnits;
935 }
936 
updateDepthSizeIfChanged(bool depthStencilInitialized,unsigned int depthSize)937 void StateManager9::updateDepthSizeIfChanged(bool depthStencilInitialized, unsigned int depthSize)
938 {
939     if (!depthStencilInitialized || depthSize != mCurDepthSize)
940     {
941         mCurDepthSize = depthSize;
942         forceSetRasterState();
943     }
944 }
945 }  // namespace rx
946