xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2012 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 // Renderer9.cpp: Implements a back-end specific class for the D3D9 renderer.
8 
9 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
10 
11 #include <EGL/eglext.h>
12 #include <sstream>
13 
14 #include "common/utilities.h"
15 #include "libANGLE/Buffer.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/Display.h"
18 #include "libANGLE/Framebuffer.h"
19 #include "libANGLE/FramebufferAttachment.h"
20 #include "libANGLE/Program.h"
21 #include "libANGLE/Renderbuffer.h"
22 #include "libANGLE/State.h"
23 #include "libANGLE/Surface.h"
24 #include "libANGLE/Texture.h"
25 #include "libANGLE/angletypes.h"
26 #include "libANGLE/features.h"
27 #include "libANGLE/formatutils.h"
28 #include "libANGLE/renderer/d3d/CompilerD3D.h"
29 #include "libANGLE/renderer/d3d/DisplayD3D.h"
30 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
31 #include "libANGLE/renderer/d3d/IndexDataManager.h"
32 #include "libANGLE/renderer/d3d/ProgramD3D.h"
33 #include "libANGLE/renderer/d3d/ProgramExecutableD3D.h"
34 #include "libANGLE/renderer/d3d/RenderbufferD3D.h"
35 #include "libANGLE/renderer/d3d/ShaderD3D.h"
36 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
37 #include "libANGLE/renderer/d3d/TextureD3D.h"
38 #include "libANGLE/renderer/d3d/d3d9/Blit9.h"
39 #include "libANGLE/renderer/d3d/d3d9/Buffer9.h"
40 #include "libANGLE/renderer/d3d/d3d9/Context9.h"
41 #include "libANGLE/renderer/d3d/d3d9/Device9.h"
42 #include "libANGLE/renderer/d3d/d3d9/Fence9.h"
43 #include "libANGLE/renderer/d3d/d3d9/Framebuffer9.h"
44 #include "libANGLE/renderer/d3d/d3d9/Image9.h"
45 #include "libANGLE/renderer/d3d/d3d9/IndexBuffer9.h"
46 #include "libANGLE/renderer/d3d/d3d9/NativeWindow9.h"
47 #include "libANGLE/renderer/d3d/d3d9/Query9.h"
48 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
49 #include "libANGLE/renderer/d3d/d3d9/ShaderExecutable9.h"
50 #include "libANGLE/renderer/d3d/d3d9/SwapChain9.h"
51 #include "libANGLE/renderer/d3d/d3d9/TextureStorage9.h"
52 #include "libANGLE/renderer/d3d/d3d9/VertexArray9.h"
53 #include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
54 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
55 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h"
56 #include "libANGLE/renderer/d3d/driver_utils_d3d.h"
57 #include "libANGLE/renderer/driver_utils.h"
58 #include "libANGLE/trace.h"
59 
60 #if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
61 #    define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
62 #endif
63 
64 // Enable ANGLE_SUPPORT_SHADER_MODEL_2 if you wish devices with only shader model 2.
65 // Such a device would not be conformant.
66 #ifndef ANGLE_SUPPORT_SHADER_MODEL_2
67 #    define ANGLE_SUPPORT_SHADER_MODEL_2 0
68 #endif
69 
70 namespace rx
71 {
72 
73 namespace
74 {
75 enum
76 {
77     MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256,
78     MAX_PIXEL_CONSTANT_VECTORS_SM2   = 32,
79     MAX_PIXEL_CONSTANT_VECTORS_SM3   = 224,
80     MAX_VARYING_VECTORS_SM2          = 8,
81     MAX_VARYING_VECTORS_SM3          = 10,
82 
83     MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4
84 };
85 
86 template <typename T>
DrawPoints(IDirect3DDevice9 * device,GLsizei count,const void * indices,int minIndex)87 static void DrawPoints(IDirect3DDevice9 *device, GLsizei count, const void *indices, int minIndex)
88 {
89     for (int i = 0; i < count; i++)
90     {
91         unsigned int indexValue =
92             static_cast<unsigned int>(static_cast<const T *>(indices)[i]) - minIndex;
93         device->DrawPrimitive(D3DPT_POINTLIST, indexValue, 1);
94     }
95 }
96 
97 // A hard limit on buffer size. This works around a problem in the NVIDIA drivers where buffer sizes
98 // close to MAX_UINT would give undefined results. The limit of MAX_UINT/2 should be generous enough
99 // for almost any demanding application.
100 constexpr UINT kMaximumBufferSizeHardLimit = std::numeric_limits<UINT>::max() >> 1;
101 }  // anonymous namespace
102 
Renderer9(egl::Display * display)103 Renderer9::Renderer9(egl::Display *display) : RendererD3D(display), mStateManager(this)
104 {
105     mD3d9Module = nullptr;
106 
107     mD3d9         = nullptr;
108     mD3d9Ex       = nullptr;
109     mDevice       = nullptr;
110     mDeviceEx     = nullptr;
111     mDeviceWindow = nullptr;
112     mBlit         = nullptr;
113 
114     mAdapter = D3DADAPTER_DEFAULT;
115 
116     const egl::AttributeMap &attributes = display->getAttributeMap();
117     EGLint requestedDeviceType          = static_cast<EGLint>(attributes.get(
118         EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE));
119     switch (requestedDeviceType)
120     {
121         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE:
122             mDeviceType = D3DDEVTYPE_HAL;
123             break;
124 
125         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE:
126             mDeviceType = D3DDEVTYPE_REF;
127             break;
128 
129         case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE:
130             mDeviceType = D3DDEVTYPE_NULLREF;
131             break;
132 
133         default:
134             UNREACHABLE();
135     }
136 
137     mMaskedClearSavedState = nullptr;
138 
139     mVertexDataManager = nullptr;
140     mIndexDataManager  = nullptr;
141     mLineLoopIB        = nullptr;
142     mCountingIB        = nullptr;
143 
144     mMaxNullColorbufferLRU = 0;
145     for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
146     {
147         mNullRenderTargetCache[i].lruCount     = 0;
148         mNullRenderTargetCache[i].width        = 0;
149         mNullRenderTargetCache[i].height       = 0;
150         mNullRenderTargetCache[i].renderTarget = nullptr;
151     }
152 
153     mAppliedVertexShader  = nullptr;
154     mAppliedPixelShader   = nullptr;
155     mAppliedProgramSerial = 0;
156 
157     gl::InitializeDebugAnnotations(&mAnnotator);
158 }
159 
setGlobalDebugAnnotator()160 void Renderer9::setGlobalDebugAnnotator()
161 {
162     gl::InitializeDebugAnnotations(&mAnnotator);
163 }
164 
~Renderer9()165 Renderer9::~Renderer9()
166 {
167     if (mDevice)
168     {
169         // If the device is lost, reset it first to prevent leaving the driver in an unstable state
170         if (testDeviceLost())
171         {
172             resetDevice();
173         }
174     }
175 
176     release();
177 }
178 
release()179 void Renderer9::release()
180 {
181     gl::UninitializeDebugAnnotations();
182 
183     mTranslatedAttribCache.clear();
184 
185     releaseDeviceResources();
186 
187     SafeRelease(mDevice);
188     SafeRelease(mDeviceEx);
189     SafeRelease(mD3d9);
190     SafeRelease(mD3d9Ex);
191 
192     mCompiler.release();
193 
194     if (mDeviceWindow)
195     {
196         DestroyWindow(mDeviceWindow);
197         mDeviceWindow = nullptr;
198     }
199 
200     mD3d9Module = nullptr;
201 }
202 
initialize()203 egl::Error Renderer9::initialize()
204 {
205     ANGLE_TRACE_EVENT0("gpu.angle", "GetModuleHandle_d3d9");
206     mD3d9Module = ::LoadLibrary(TEXT("d3d9.dll"));
207 
208     if (mD3d9Module == nullptr)
209     {
210         return egl::EglNotInitialized(D3D9_INIT_MISSING_DEP) << "No D3D9 module found.";
211     }
212 
213     typedef HRESULT(WINAPI * Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex **);
214     Direct3DCreate9ExFunc Direct3DCreate9ExPtr =
215         reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
216 
217     // Use Direct3D9Ex if available. Among other things, this version is less
218     // inclined to report a lost context, for example when the user switches
219     // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are
220     // available.
221     if (static_cast<bool>(ANGLE_D3D9EX) && Direct3DCreate9ExPtr &&
222         SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
223     {
224         ANGLE_TRACE_EVENT0("gpu.angle", "D3d9Ex_QueryInterface");
225         ASSERT(mD3d9Ex);
226         mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast<void **>(&mD3d9));
227         ASSERT(mD3d9);
228     }
229     else
230     {
231         ANGLE_TRACE_EVENT0("gpu.angle", "Direct3DCreate9");
232         mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
233     }
234 
235     if (!mD3d9)
236     {
237         return egl::EglNotInitialized(D3D9_INIT_MISSING_DEP) << "Could not create D3D9 device.";
238     }
239 
240     if (mDisplay->getNativeDisplayId() != nullptr)
241     {
242         //  UNIMPLEMENTED();   // FIXME: Determine which adapter index the device context
243         //  corresponds to
244     }
245 
246     HRESULT result;
247 
248     // Give up on getting device caps after about one second.
249     {
250         ANGLE_TRACE_EVENT0("gpu.angle", "GetDeviceCaps");
251         for (int i = 0; i < 10; ++i)
252         {
253             result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
254             if (SUCCEEDED(result))
255             {
256                 break;
257             }
258             else if (result == D3DERR_NOTAVAILABLE)
259             {
260                 Sleep(100);  // Give the driver some time to initialize/recover
261             }
262             else if (FAILED(result))  // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY,
263                                       // D3DERR_INVALIDDEVICE, or another error we can't recover
264                                       // from
265             {
266                 return egl::EglNotInitialized(D3D9_INIT_OTHER_ERROR)
267                        << "Failed to get device caps, " << gl::FmtHR(result);
268             }
269         }
270     }
271 
272 #if ANGLE_SUPPORT_SHADER_MODEL_2
273     size_t minShaderModel = 2;
274 #else
275     size_t minShaderModel = 3;
276 #endif
277 
278     if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(minShaderModel, 0))
279     {
280         return egl::EglNotInitialized(D3D9_INIT_UNSUPPORTED_VERSION)
281                << "Renderer does not support PS " << minShaderModel << ".0, aborting!";
282     }
283 
284     // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture
285     // to a render target texture is not supported. This is required by
286     // Texture2D::ensureRenderTarget.
287     if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
288     {
289         return egl::EglNotInitialized(D3D9_INIT_UNSUPPORTED_STRETCHRECT)
290                << "Renderer does not support StretctRect from textures.";
291     }
292 
293     {
294         ANGLE_TRACE_EVENT0("gpu.angle", "GetAdapterIdentifier");
295         mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
296     }
297 
298     static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
299     static const TCHAR className[]  = TEXT("STATIC");
300 
301     {
302         ANGLE_TRACE_EVENT0("gpu.angle", "CreateWindowEx");
303         mDeviceWindow =
304             CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1,
305                            1, HWND_MESSAGE, nullptr, GetModuleHandle(nullptr), nullptr);
306     }
307 
308     D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
309     DWORD behaviorFlags =
310         D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED;
311 
312     {
313         ANGLE_TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice");
314         result = mD3d9->CreateDevice(
315             mAdapter, mDeviceType, mDeviceWindow,
316             behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE,
317             &presentParameters, &mDevice);
318 
319         if (FAILED(result))
320         {
321             ERR() << "CreateDevice1 failed: (" << gl::FmtHR(result) << ")";
322         }
323     }
324     if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
325     {
326         return egl::EglBadAlloc(D3D9_INIT_OUT_OF_MEMORY)
327                << "CreateDevice failed: device lost or out of memory (" << gl::FmtHR(result) << ")";
328     }
329 
330     if (FAILED(result))
331     {
332         ANGLE_TRACE_EVENT0("gpu.angle", "D3d9_CreateDevice2");
333         result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow,
334                                      behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING,
335                                      &presentParameters, &mDevice);
336 
337         if (FAILED(result))
338         {
339             ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY ||
340                    result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
341             return egl::EglBadAlloc(D3D9_INIT_OUT_OF_MEMORY)
342                    << "CreateDevice2 failed: device lost, not available, or of out of memory ("
343                    << gl::FmtHR(result) << ")";
344         }
345     }
346 
347     if (mD3d9Ex)
348     {
349         ANGLE_TRACE_EVENT0("gpu.angle", "mDevice_QueryInterface");
350         result = mDevice->QueryInterface(__uuidof(IDirect3DDevice9Ex), (void **)&mDeviceEx);
351         ASSERT(SUCCEEDED(result));
352     }
353 
354     {
355         ANGLE_TRACE_EVENT0("gpu.angle", "ShaderCache initialize");
356         mVertexShaderCache.initialize(mDevice);
357         mPixelShaderCache.initialize(mDevice);
358     }
359 
360     D3DDISPLAYMODE currentDisplayMode;
361     mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
362 
363     // Check vertex texture support
364     // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
365     // We test this using D3D9 by checking support for the R16F format.
366     mVertexTextureSupport = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0) &&
367                             SUCCEEDED(mD3d9->CheckDeviceFormat(
368                                 mAdapter, mDeviceType, currentDisplayMode.Format,
369                                 D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F));
370 
371     ANGLE_TRY(initializeDevice());
372 
373     return egl::NoError();
374 }
375 
376 // do any one-time device initialization
377 // NOTE: this is also needed after a device lost/reset
378 // to reset the scene status and ensure the default states are reset.
initializeDevice()379 egl::Error Renderer9::initializeDevice()
380 {
381     // Permanent non-default states
382     mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
383     mDevice->SetRenderState(D3DRS_LASTPIXEL, FALSE);
384 
385     if (mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0))
386     {
387         mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, (DWORD &)mDeviceCaps.MaxPointSize);
388     }
389     else
390     {
391         mDevice->SetRenderState(D3DRS_POINTSIZE_MAX, 0x3F800000);  // 1.0f
392     }
393 
394     const gl::Caps &rendererCaps = getNativeCaps();
395 
396     mCurVertexSamplerStates.resize(rendererCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex]);
397     mCurPixelSamplerStates.resize(
398         rendererCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment]);
399 
400     mCurVertexTextures.resize(rendererCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex]);
401     mCurPixelTextures.resize(rendererCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment]);
402 
403     markAllStateDirty();
404 
405     mSceneStarted = false;
406 
407     ASSERT(!mBlit);
408     mBlit = new Blit9(this);
409 
410     ASSERT(!mVertexDataManager && !mIndexDataManager);
411     mIndexDataManager = new IndexDataManager(this);
412 
413     mTranslatedAttribCache.resize(getNativeCaps().maxVertexAttributes);
414 
415     mStateManager.initialize();
416 
417     return egl::NoError();
418 }
419 
getDefaultPresentParameters()420 D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters()
421 {
422     D3DPRESENT_PARAMETERS presentParameters = {};
423 
424     // The default swap chain is never actually used. Surface will create a new swap chain with the
425     // proper parameters.
426     presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
427     presentParameters.BackBufferCount        = 1;
428     presentParameters.BackBufferFormat       = D3DFMT_UNKNOWN;
429     presentParameters.BackBufferWidth        = 1;
430     presentParameters.BackBufferHeight       = 1;
431     presentParameters.EnableAutoDepthStencil = FALSE;
432     presentParameters.Flags                  = 0;
433     presentParameters.hDeviceWindow          = mDeviceWindow;
434     presentParameters.MultiSampleQuality     = 0;
435     presentParameters.MultiSampleType        = D3DMULTISAMPLE_NONE;
436     presentParameters.PresentationInterval   = D3DPRESENT_INTERVAL_DEFAULT;
437     presentParameters.SwapEffect             = D3DSWAPEFFECT_DISCARD;
438     presentParameters.Windowed               = TRUE;
439 
440     return presentParameters;
441 }
442 
generateConfigs()443 egl::ConfigSet Renderer9::generateConfigs()
444 {
445     static const GLenum colorBufferFormats[] = {
446         GL_BGR5_A1_ANGLEX,
447         GL_BGRA8_EXT,
448         GL_RGB565,
449 
450     };
451 
452     static const GLenum depthStencilBufferFormats[] = {
453         GL_NONE,
454         GL_DEPTH_COMPONENT32_OES,
455         GL_DEPTH24_STENCIL8_OES,
456         GL_DEPTH_COMPONENT24_OES,
457         GL_DEPTH_COMPONENT16,
458     };
459 
460     const gl::Caps &rendererCaps                  = getNativeCaps();
461     const gl::TextureCapsMap &rendererTextureCaps = getNativeTextureCaps();
462 
463     D3DDISPLAYMODE currentDisplayMode;
464     mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
465 
466     // Determine the min and max swap intervals
467     int minSwapInterval = 4;
468     int maxSwapInterval = 0;
469 
470     if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)
471     {
472         minSwapInterval = std::min(minSwapInterval, 0);
473         maxSwapInterval = std::max(maxSwapInterval, 0);
474     }
475     if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE)
476     {
477         minSwapInterval = std::min(minSwapInterval, 1);
478         maxSwapInterval = std::max(maxSwapInterval, 1);
479     }
480     if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO)
481     {
482         minSwapInterval = std::min(minSwapInterval, 2);
483         maxSwapInterval = std::max(maxSwapInterval, 2);
484     }
485     if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE)
486     {
487         minSwapInterval = std::min(minSwapInterval, 3);
488         maxSwapInterval = std::max(maxSwapInterval, 3);
489     }
490     if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR)
491     {
492         minSwapInterval = std::min(minSwapInterval, 4);
493         maxSwapInterval = std::max(maxSwapInterval, 4);
494     }
495 
496     egl::ConfigSet configs;
497     for (size_t formatIndex = 0; formatIndex < ArraySize(colorBufferFormats); formatIndex++)
498     {
499         GLenum colorBufferInternalFormat = colorBufferFormats[formatIndex];
500         const gl::TextureCaps &colorBufferFormatCaps =
501             rendererTextureCaps.get(colorBufferInternalFormat);
502         if (colorBufferFormatCaps.renderbuffer)
503         {
504             ASSERT(colorBufferFormatCaps.textureAttachment);
505             for (size_t depthStencilIndex = 0;
506                  depthStencilIndex < ArraySize(depthStencilBufferFormats); depthStencilIndex++)
507             {
508                 GLenum depthStencilBufferInternalFormat =
509                     depthStencilBufferFormats[depthStencilIndex];
510                 const gl::TextureCaps &depthStencilBufferFormatCaps =
511                     rendererTextureCaps.get(depthStencilBufferInternalFormat);
512                 if (depthStencilBufferFormatCaps.renderbuffer ||
513                     depthStencilBufferInternalFormat == GL_NONE)
514                 {
515                     ASSERT(depthStencilBufferFormatCaps.textureAttachment ||
516                            depthStencilBufferInternalFormat == GL_NONE);
517                     const gl::InternalFormat &colorBufferFormatInfo =
518                         gl::GetSizedInternalFormatInfo(colorBufferInternalFormat);
519                     const gl::InternalFormat &depthStencilBufferFormatInfo =
520                         gl::GetSizedInternalFormatInfo(depthStencilBufferInternalFormat);
521                     const d3d9::TextureFormat &d3d9ColorBufferFormatInfo =
522                         d3d9::GetTextureFormatInfo(colorBufferInternalFormat);
523 
524                     egl::Config config;
525                     config.renderTargetFormat = colorBufferInternalFormat;
526                     config.depthStencilFormat = depthStencilBufferInternalFormat;
527                     config.bufferSize         = colorBufferFormatInfo.getEGLConfigBufferSize();
528                     config.redSize            = colorBufferFormatInfo.redBits;
529                     config.greenSize          = colorBufferFormatInfo.greenBits;
530                     config.blueSize           = colorBufferFormatInfo.blueBits;
531                     config.luminanceSize      = colorBufferFormatInfo.luminanceBits;
532                     config.alphaSize          = colorBufferFormatInfo.alphaBits;
533                     config.alphaMaskSize      = 0;
534                     config.bindToTextureRGB   = (colorBufferFormatInfo.format == GL_RGB);
535                     config.bindToTextureRGBA  = (colorBufferFormatInfo.format == GL_RGBA ||
536                                                 colorBufferFormatInfo.format == GL_BGRA_EXT);
537                     config.colorBufferType    = EGL_RGB_BUFFER;
538                     // Mark as slow if blits to the back-buffer won't be straight forward
539                     config.configCaveat =
540                         (currentDisplayMode.Format == d3d9ColorBufferFormatInfo.renderFormat)
541                             ? EGL_NONE
542                             : EGL_SLOW_CONFIG;
543                     config.configID          = static_cast<EGLint>(configs.size() + 1);
544                     config.conformant        = EGL_OPENGL_ES2_BIT;
545                     config.depthSize         = depthStencilBufferFormatInfo.depthBits;
546                     config.level             = 0;
547                     config.matchNativePixmap = EGL_NONE;
548                     config.maxPBufferWidth   = rendererCaps.max2DTextureSize;
549                     config.maxPBufferHeight  = rendererCaps.max2DTextureSize;
550                     config.maxPBufferPixels =
551                         rendererCaps.max2DTextureSize * rendererCaps.max2DTextureSize;
552                     config.maxSwapInterval  = maxSwapInterval;
553                     config.minSwapInterval  = minSwapInterval;
554                     config.nativeRenderable = EGL_FALSE;
555                     config.nativeVisualID   = 0;
556                     config.nativeVisualType = EGL_NONE;
557                     config.renderableType   = EGL_OPENGL_ES2_BIT;
558                     config.sampleBuffers    = 0;  // FIXME: enumerate multi-sampling
559                     config.samples          = 0;
560                     config.stencilSize      = depthStencilBufferFormatInfo.stencilBits;
561                     config.surfaceType =
562                         EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
563                     config.transparentType       = EGL_NONE;
564                     config.transparentRedValue   = 0;
565                     config.transparentGreenValue = 0;
566                     config.transparentBlueValue  = 0;
567                     config.colorComponentType    = gl_egl::GLComponentTypeToEGLColorComponentType(
568                         colorBufferFormatInfo.componentType);
569 
570                     configs.add(config);
571                 }
572             }
573         }
574     }
575 
576     ASSERT(configs.size() > 0);
577     return configs;
578 }
579 
generateDisplayExtensions(egl::DisplayExtensions * outExtensions) const580 void Renderer9::generateDisplayExtensions(egl::DisplayExtensions *outExtensions) const
581 {
582     outExtensions->createContextRobustness = true;
583 
584     if (getShareHandleSupport())
585     {
586         outExtensions->d3dShareHandleClientBuffer     = true;
587         outExtensions->surfaceD3DTexture2DShareHandle = true;
588     }
589     outExtensions->d3dTextureClientBuffer = true;
590 
591     outExtensions->querySurfacePointer = true;
592     outExtensions->windowFixedSize     = true;
593     outExtensions->postSubBuffer       = true;
594 
595     outExtensions->image               = true;
596     outExtensions->imageBase           = true;
597     outExtensions->glTexture2DImage    = true;
598     outExtensions->glRenderbufferImage = true;
599 
600     outExtensions->noConfigContext = true;
601 
602     // Contexts are virtualized so textures and semaphores can be shared globally
603     outExtensions->displayTextureShareGroup   = true;
604     outExtensions->displaySemaphoreShareGroup = true;
605 
606     // D3D9 can be used without an output surface
607     outExtensions->surfacelessContext = true;
608 
609     outExtensions->robustResourceInitializationANGLE = true;
610 }
611 
startScene()612 void Renderer9::startScene()
613 {
614     if (!mSceneStarted)
615     {
616         long result = mDevice->BeginScene();
617         if (SUCCEEDED(result))
618         {
619             // This is defensive checking against the device being
620             // lost at unexpected times.
621             mSceneStarted = true;
622         }
623     }
624 }
625 
endScene()626 void Renderer9::endScene()
627 {
628     if (mSceneStarted)
629     {
630         // EndScene can fail if the device was lost, for example due
631         // to a TDR during a draw call.
632         mDevice->EndScene();
633         mSceneStarted = false;
634     }
635 }
636 
flush(const gl::Context * context)637 angle::Result Renderer9::flush(const gl::Context *context)
638 {
639     IDirect3DQuery9 *query = nullptr;
640     ANGLE_TRY(allocateEventQuery(context, &query));
641 
642     Context9 *context9 = GetImplAs<Context9>(context);
643 
644     HRESULT result = query->Issue(D3DISSUE_END);
645     ANGLE_TRY_HR(context9, result, "Failed to issue event query");
646 
647     // Grab the query data once
648     result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH);
649     freeEventQuery(query);
650     ANGLE_TRY_HR(context9, result, "Failed to get event query data");
651 
652     return angle::Result::Continue;
653 }
654 
finish(const gl::Context * context)655 angle::Result Renderer9::finish(const gl::Context *context)
656 {
657     IDirect3DQuery9 *query = nullptr;
658     ANGLE_TRY(allocateEventQuery(context, &query));
659 
660     Context9 *context9 = GetImplAs<Context9>(context);
661 
662     HRESULT result = query->Issue(D3DISSUE_END);
663     ANGLE_TRY_HR(context9, result, "Failed to issue event query");
664 
665     // Grab the query data once
666     result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH);
667     if (FAILED(result))
668     {
669         freeEventQuery(query);
670     }
671     ANGLE_TRY_HR(context9, result, "Failed to get event query data");
672 
673     // Loop until the query completes
674     unsigned int attempt = 0;
675     while (result == S_FALSE)
676     {
677         // Keep polling, but allow other threads to do something useful first
678         std::this_thread::yield();
679 
680         result = query->GetData(nullptr, 0, D3DGETDATA_FLUSH);
681         attempt++;
682 
683         if (result == S_FALSE)
684         {
685             // explicitly check for device loss
686             // some drivers seem to return S_FALSE even if the device is lost
687             // instead of D3DERR_DEVICELOST like they should
688             bool checkDeviceLost = (attempt % kPollingD3DDeviceLostCheckFrequency) == 0;
689             if (checkDeviceLost && testDeviceLost())
690             {
691                 result = D3DERR_DEVICELOST;
692             }
693         }
694 
695         if (FAILED(result))
696         {
697             freeEventQuery(query);
698         }
699         ANGLE_TRY_HR(context9, result, "Failed to get event query data");
700     }
701 
702     freeEventQuery(query);
703 
704     return angle::Result::Continue;
705 }
706 
isValidNativeWindow(EGLNativeWindowType window) const707 bool Renderer9::isValidNativeWindow(EGLNativeWindowType window) const
708 {
709     return NativeWindow9::IsValidNativeWindow(window);
710 }
711 
createNativeWindow(EGLNativeWindowType window,const egl::Config *,const egl::AttributeMap &) const712 NativeWindowD3D *Renderer9::createNativeWindow(EGLNativeWindowType window,
713                                                const egl::Config *,
714                                                const egl::AttributeMap &) const
715 {
716     return new NativeWindow9(window);
717 }
718 
createSwapChain(NativeWindowD3D * nativeWindow,HANDLE shareHandle,IUnknown * d3dTexture,GLenum backBufferFormat,GLenum depthBufferFormat,EGLint orientation,EGLint samples)719 SwapChainD3D *Renderer9::createSwapChain(NativeWindowD3D *nativeWindow,
720                                          HANDLE shareHandle,
721                                          IUnknown *d3dTexture,
722                                          GLenum backBufferFormat,
723                                          GLenum depthBufferFormat,
724                                          EGLint orientation,
725                                          EGLint samples)
726 {
727     return new SwapChain9(this, GetAs<NativeWindow9>(nativeWindow), shareHandle, d3dTexture,
728                           backBufferFormat, depthBufferFormat, orientation);
729 }
730 
getD3DTextureInfo(const egl::Config * configuration,IUnknown * d3dTexture,const egl::AttributeMap & attribs,EGLint * width,EGLint * height,GLsizei * samples,gl::Format * glFormat,const angle::Format ** angleFormat,UINT * arraySlice) const731 egl::Error Renderer9::getD3DTextureInfo(const egl::Config *configuration,
732                                         IUnknown *d3dTexture,
733                                         const egl::AttributeMap &attribs,
734                                         EGLint *width,
735                                         EGLint *height,
736                                         GLsizei *samples,
737                                         gl::Format *glFormat,
738                                         const angle::Format **angleFormat,
739                                         UINT *arraySlice) const
740 {
741     IDirect3DTexture9 *texture = nullptr;
742     if (FAILED(d3dTexture->QueryInterface(&texture)))
743     {
744         return egl::EglBadParameter() << "Client buffer is not a IDirect3DTexture9";
745     }
746 
747     IDirect3DDevice9 *textureDevice = nullptr;
748     texture->GetDevice(&textureDevice);
749     if (textureDevice != mDevice)
750     {
751         SafeRelease(texture);
752         return egl::EglBadParameter() << "Texture's device does not match.";
753     }
754     SafeRelease(textureDevice);
755 
756     D3DSURFACE_DESC desc;
757     texture->GetLevelDesc(0, &desc);
758     SafeRelease(texture);
759 
760     if (width)
761     {
762         *width = static_cast<EGLint>(desc.Width);
763     }
764     if (height)
765     {
766         *height = static_cast<EGLint>(desc.Height);
767     }
768 
769     // GetSamplesCount() returns 0 when multisampling isn't used.
770     GLsizei sampleCount = d3d9_gl::GetSamplesCount(desc.MultiSampleType);
771     if ((configuration && configuration->samples > 1) || sampleCount != 0)
772     {
773         return egl::EglBadParameter() << "Multisampling not supported for client buffer texture";
774     }
775     if (samples)
776     {
777         *samples = static_cast<EGLint>(sampleCount);
778     }
779 
780     // From table egl.restrictions in EGL_ANGLE_d3d_texture_client_buffer.
781     switch (desc.Format)
782     {
783         case D3DFMT_R8G8B8:
784         case D3DFMT_A8R8G8B8:
785         case D3DFMT_A16B16G16R16F:
786         case D3DFMT_A32B32G32R32F:
787             break;
788 
789         default:
790             return egl::EglBadParameter()
791                    << "Unknown client buffer texture format: " << desc.Format;
792     }
793 
794     const auto &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format);
795     ASSERT(d3dFormatInfo.info().id != angle::FormatID::NONE);
796 
797     if (glFormat)
798     {
799         *glFormat = gl::Format(d3dFormatInfo.info().glInternalFormat);
800     }
801 
802     if (angleFormat)
803     {
804 
805         *angleFormat = &d3dFormatInfo.info();
806     }
807 
808     if (arraySlice)
809     {
810         *arraySlice = 0;
811     }
812 
813     return egl::NoError();
814 }
815 
validateShareHandle(const egl::Config * config,HANDLE shareHandle,const egl::AttributeMap & attribs) const816 egl::Error Renderer9::validateShareHandle(const egl::Config *config,
817                                           HANDLE shareHandle,
818                                           const egl::AttributeMap &attribs) const
819 {
820     if (shareHandle == nullptr)
821     {
822         return egl::EglBadParameter() << "NULL share handle.";
823     }
824 
825     EGLint width  = attribs.getAsInt(EGL_WIDTH, 0);
826     EGLint height = attribs.getAsInt(EGL_HEIGHT, 0);
827     ASSERT(width != 0 && height != 0);
828 
829     const d3d9::TextureFormat &backBufferd3dFormatInfo =
830         d3d9::GetTextureFormatInfo(config->renderTargetFormat);
831 
832     IDirect3DTexture9 *texture = nullptr;
833     HRESULT result             = mDevice->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET,
834                                                         backBufferd3dFormatInfo.texFormat, D3DPOOL_DEFAULT,
835                                                         &texture, &shareHandle);
836     if (FAILED(result))
837     {
838         return egl::EglBadParameter() << "Failed to open share handle, " << gl::FmtHR(result);
839     }
840 
841     DWORD levelCount = texture->GetLevelCount();
842 
843     D3DSURFACE_DESC desc;
844     texture->GetLevelDesc(0, &desc);
845     SafeRelease(texture);
846 
847     if (levelCount != 1 || desc.Width != static_cast<UINT>(width) ||
848         desc.Height != static_cast<UINT>(height) ||
849         desc.Format != backBufferd3dFormatInfo.texFormat)
850     {
851         return egl::EglBadParameter() << "Invalid texture parameters in share handle texture.";
852     }
853 
854     return egl::NoError();
855 }
856 
createContext(const gl::State & state,gl::ErrorSet * errorSet)857 ContextImpl *Renderer9::createContext(const gl::State &state, gl::ErrorSet *errorSet)
858 {
859     return new Context9(state, errorSet, this);
860 }
861 
getD3DDevice()862 void *Renderer9::getD3DDevice()
863 {
864     return mDevice;
865 }
866 
allocateEventQuery(const gl::Context * context,IDirect3DQuery9 ** outQuery)867 angle::Result Renderer9::allocateEventQuery(const gl::Context *context, IDirect3DQuery9 **outQuery)
868 {
869     if (mEventQueryPool.empty())
870     {
871         HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, outQuery);
872         ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to allocate event query");
873     }
874     else
875     {
876         *outQuery = mEventQueryPool.back();
877         mEventQueryPool.pop_back();
878     }
879 
880     return angle::Result::Continue;
881 }
882 
freeEventQuery(IDirect3DQuery9 * query)883 void Renderer9::freeEventQuery(IDirect3DQuery9 *query)
884 {
885     if (mEventQueryPool.size() > 1000)
886     {
887         SafeRelease(query);
888     }
889     else
890     {
891         mEventQueryPool.push_back(query);
892     }
893 }
894 
createVertexShader(d3d::Context * context,const DWORD * function,size_t length,IDirect3DVertexShader9 ** outShader)895 angle::Result Renderer9::createVertexShader(d3d::Context *context,
896                                             const DWORD *function,
897                                             size_t length,
898                                             IDirect3DVertexShader9 **outShader)
899 {
900     return mVertexShaderCache.create(context, function, length, outShader);
901 }
902 
createPixelShader(d3d::Context * context,const DWORD * function,size_t length,IDirect3DPixelShader9 ** outShader)903 angle::Result Renderer9::createPixelShader(d3d::Context *context,
904                                            const DWORD *function,
905                                            size_t length,
906                                            IDirect3DPixelShader9 **outShader)
907 {
908     return mPixelShaderCache.create(context, function, length, outShader);
909 }
910 
createVertexBuffer(UINT Length,DWORD Usage,IDirect3DVertexBuffer9 ** ppVertexBuffer)911 HRESULT Renderer9::createVertexBuffer(UINT Length,
912                                       DWORD Usage,
913                                       IDirect3DVertexBuffer9 **ppVertexBuffer)
914 {
915     // Force buffers to be limited to a fixed max size.
916     if (Length > kMaximumBufferSizeHardLimit)
917     {
918         return E_OUTOFMEMORY;
919     }
920 
921     D3DPOOL Pool = getBufferPool(Usage);
922     return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, nullptr);
923 }
924 
createVertexBuffer()925 VertexBuffer *Renderer9::createVertexBuffer()
926 {
927     return new VertexBuffer9(this);
928 }
929 
createIndexBuffer(UINT Length,DWORD Usage,D3DFORMAT Format,IDirect3DIndexBuffer9 ** ppIndexBuffer)930 HRESULT Renderer9::createIndexBuffer(UINT Length,
931                                      DWORD Usage,
932                                      D3DFORMAT Format,
933                                      IDirect3DIndexBuffer9 **ppIndexBuffer)
934 {
935     // Force buffers to be limited to a fixed max size.
936     if (Length > kMaximumBufferSizeHardLimit)
937     {
938         return E_OUTOFMEMORY;
939     }
940 
941     D3DPOOL Pool = getBufferPool(Usage);
942     return mDevice->CreateIndexBuffer(Length, Usage, Format, Pool, ppIndexBuffer, nullptr);
943 }
944 
createIndexBuffer()945 IndexBuffer *Renderer9::createIndexBuffer()
946 {
947     return new IndexBuffer9(this);
948 }
949 
createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType,const egl::AttributeMap & attribs)950 StreamProducerImpl *Renderer9::createStreamProducerD3DTexture(
951     egl::Stream::ConsumerType consumerType,
952     const egl::AttributeMap &attribs)
953 {
954     // Streams are not supported under D3D9
955     UNREACHABLE();
956     return nullptr;
957 }
958 
supportsFastCopyBufferToTexture(GLenum internalFormat) const959 bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const
960 {
961     // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3.
962     return false;
963 }
964 
fastCopyBufferToTexture(const gl::Context * context,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,unsigned int offset,RenderTargetD3D * destRenderTarget,GLenum destinationFormat,GLenum sourcePixelsType,const gl::Box & destArea)965 angle::Result Renderer9::fastCopyBufferToTexture(const gl::Context *context,
966                                                  const gl::PixelUnpackState &unpack,
967                                                  gl::Buffer *unpackBuffer,
968                                                  unsigned int offset,
969                                                  RenderTargetD3D *destRenderTarget,
970                                                  GLenum destinationFormat,
971                                                  GLenum sourcePixelsType,
972                                                  const gl::Box &destArea)
973 {
974     // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3.
975     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
976     return angle::Result::Stop;
977 }
978 
setSamplerState(const gl::Context * context,gl::ShaderType type,int index,gl::Texture * texture,const gl::SamplerState & samplerState)979 angle::Result Renderer9::setSamplerState(const gl::Context *context,
980                                          gl::ShaderType type,
981                                          int index,
982                                          gl::Texture *texture,
983                                          const gl::SamplerState &samplerState)
984 {
985     CurSamplerState &appliedSampler = (type == gl::ShaderType::Fragment)
986                                           ? mCurPixelSamplerStates[index]
987                                           : mCurVertexSamplerStates[index];
988 
989     // Make sure to add the level offset for our tiny compressed texture workaround
990     TextureD3D *textureD3D = GetImplAs<TextureD3D>(texture);
991 
992     TextureStorage *storage = nullptr;
993     ANGLE_TRY(textureD3D->getNativeTexture(context, &storage));
994 
995     // Storage should exist, texture should be complete
996     ASSERT(storage);
997 
998     DWORD baseLevel = texture->getBaseLevel() + storage->getTopLevel();
999 
1000     if (appliedSampler.forceSet || appliedSampler.baseLevel != baseLevel ||
1001         memcmp(&samplerState, &appliedSampler, sizeof(gl::SamplerState)) != 0)
1002     {
1003         int d3dSamplerOffset = (type == gl::ShaderType::Fragment) ? 0 : D3DVERTEXTEXTURESAMPLER0;
1004         int d3dSampler       = index + d3dSamplerOffset;
1005 
1006         mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU,
1007                                  gl_d3d9::ConvertTextureWrap(samplerState.getWrapS()));
1008         mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV,
1009                                  gl_d3d9::ConvertTextureWrap(samplerState.getWrapT()));
1010 
1011         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER,
1012                                  gl_d3d9::ConvertMagFilter(samplerState.getMagFilter(),
1013                                                            samplerState.getMaxAnisotropy()));
1014 
1015         D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
1016         float lodBias;
1017         gl_d3d9::ConvertMinFilter(samplerState.getMinFilter(), &d3dMinFilter, &d3dMipFilter,
1018                                   &lodBias, samplerState.getMaxAnisotropy(), baseLevel);
1019         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
1020         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
1021         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel);
1022         mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPMAPLODBIAS, static_cast<DWORD>(lodBias));
1023         if (getNativeExtensions().textureFilterAnisotropicEXT)
1024         {
1025             DWORD maxAnisotropy = std::min(mDeviceCaps.MaxAnisotropy,
1026                                            static_cast<DWORD>(samplerState.getMaxAnisotropy()));
1027             mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, maxAnisotropy);
1028         }
1029 
1030         const gl::InternalFormat &info =
1031             gl::GetSizedInternalFormatInfo(textureD3D->getBaseLevelInternalFormat());
1032 
1033         mDevice->SetSamplerState(d3dSampler, D3DSAMP_SRGBTEXTURE, info.colorEncoding == GL_SRGB);
1034 
1035         if (samplerState.usesBorderColor())
1036         {
1037             angle::ColorGeneric borderColor = texture->getBorderColor();
1038             ASSERT(borderColor.type == angle::ColorGeneric::Type::Float);
1039 
1040             // Enforce opaque alpha for opaque formats, excluding DXT1 RGBA as it has no bits info.
1041             if (info.alphaBits == 0 && info.componentCount < 4)
1042             {
1043                 borderColor.colorF.alpha = 1.0f;
1044             }
1045 
1046             if (info.isLUMA())
1047             {
1048                 if (info.luminanceBits == 0)
1049                 {
1050                     borderColor.colorF.red = 0.0f;
1051                 }
1052                 // Older Intel drivers use RGBA border color when sampling from D3DFMT_A8L8.
1053                 // However, some recent Intel drivers sample alpha from green border channel
1054                 // when using this format. Assume the old behavior because newer GPUs should
1055                 // use D3D11 anyway.
1056                 borderColor.colorF.green = borderColor.colorF.red;
1057                 borderColor.colorF.blue  = borderColor.colorF.red;
1058             }
1059 
1060             D3DCOLOR d3dBorderColor;
1061             if (info.colorEncoding == GL_SRGB && getFeatures().borderColorSrgb.enabled)
1062             {
1063                 d3dBorderColor =
1064                     D3DCOLOR_RGBA(gl::linearToSRGB(gl::clamp01(borderColor.colorF.red)),
1065                                   gl::linearToSRGB(gl::clamp01(borderColor.colorF.green)),
1066                                   gl::linearToSRGB(gl::clamp01(borderColor.colorF.blue)),
1067                                   gl::unorm<8>(borderColor.colorF.alpha));
1068             }
1069             else
1070             {
1071                 d3dBorderColor = gl_d3d9::ConvertColor(borderColor.colorF);
1072             }
1073 
1074             mDevice->SetSamplerState(d3dSampler, D3DSAMP_BORDERCOLOR, d3dBorderColor);
1075         }
1076     }
1077 
1078     appliedSampler.forceSet     = false;
1079     appliedSampler.samplerState = samplerState;
1080     appliedSampler.baseLevel    = baseLevel;
1081 
1082     return angle::Result::Continue;
1083 }
1084 
setTexture(const gl::Context * context,gl::ShaderType type,int index,gl::Texture * texture)1085 angle::Result Renderer9::setTexture(const gl::Context *context,
1086                                     gl::ShaderType type,
1087                                     int index,
1088                                     gl::Texture *texture)
1089 {
1090     int d3dSamplerOffset = (type == gl::ShaderType::Fragment) ? 0 : D3DVERTEXTEXTURESAMPLER0;
1091     int d3dSampler       = index + d3dSamplerOffset;
1092     IDirect3DBaseTexture9 *d3dTexture = nullptr;
1093     bool forceSetTexture              = false;
1094 
1095     std::vector<uintptr_t> &appliedTextures =
1096         (type == gl::ShaderType::Fragment) ? mCurPixelTextures : mCurVertexTextures;
1097 
1098     if (texture)
1099     {
1100         TextureD3D *textureImpl = GetImplAs<TextureD3D>(texture);
1101 
1102         TextureStorage *texStorage = nullptr;
1103         ANGLE_TRY(textureImpl->getNativeTexture(context, &texStorage));
1104 
1105         // Texture should be complete and have a storage
1106         ASSERT(texStorage);
1107 
1108         TextureStorage9 *storage9 = GetAs<TextureStorage9>(texStorage);
1109         ANGLE_TRY(storage9->getBaseTexture(context, &d3dTexture));
1110 
1111         // If we get NULL back from getBaseTexture here, something went wrong
1112         // in the texture class and we're unexpectedly missing the d3d texture
1113         ASSERT(d3dTexture != nullptr);
1114 
1115         forceSetTexture = textureImpl->hasDirtyImages();
1116         textureImpl->resetDirty();
1117     }
1118 
1119     if (forceSetTexture || appliedTextures[index] != reinterpret_cast<uintptr_t>(d3dTexture))
1120     {
1121         mDevice->SetTexture(d3dSampler, d3dTexture);
1122     }
1123 
1124     appliedTextures[index] = reinterpret_cast<uintptr_t>(d3dTexture);
1125 
1126     return angle::Result::Continue;
1127 }
1128 
updateState(const gl::Context * context,gl::PrimitiveMode drawMode)1129 angle::Result Renderer9::updateState(const gl::Context *context, gl::PrimitiveMode drawMode)
1130 {
1131     const auto &glState = context->getState();
1132 
1133     // Applies the render target surface, depth stencil surface, viewport rectangle and
1134     // scissor rectangle to the renderer
1135     gl::Framebuffer *framebuffer = glState.getDrawFramebuffer();
1136     ASSERT(framebuffer && !framebuffer->hasAnyDirtyBit());
1137 
1138     Framebuffer9 *framebuffer9 = GetImplAs<Framebuffer9>(framebuffer);
1139 
1140     ANGLE_TRY(applyRenderTarget(context, framebuffer9->getCachedColorRenderTargets()[0],
1141                                 framebuffer9->getCachedDepthStencilRenderTarget()));
1142 
1143     // Setting viewport state
1144     setViewport(glState.getViewport(), glState.getNearPlane(), glState.getFarPlane(), drawMode,
1145                 glState.getRasterizerState().frontFace, false);
1146 
1147     // Setting scissors state
1148     setScissorRectangle(glState.getScissor(), glState.isScissorTestEnabled());
1149 
1150     // Setting blend, depth stencil, and rasterizer states
1151     // Since framebuffer->getSamples will return the original samples which may be different with
1152     // the sample counts that we set in render target view, here we use renderTarget->getSamples to
1153     // get the actual samples.
1154     GLsizei samples                                       = 0;
1155     const gl::FramebufferAttachment *firstColorAttachment = framebuffer->getFirstColorAttachment();
1156     if (firstColorAttachment)
1157     {
1158         ASSERT(firstColorAttachment->isAttached());
1159         RenderTarget9 *renderTarget = nullptr;
1160         ANGLE_TRY(firstColorAttachment->getRenderTarget(context, firstColorAttachment->getSamples(),
1161                                                         &renderTarget));
1162         samples = renderTarget->getSamples();
1163 
1164         mDevice->SetRenderState(D3DRS_SRGBWRITEENABLE,
1165                                 renderTarget->getInternalFormat() == GL_SRGB8_ALPHA8);
1166     }
1167     gl::RasterizerState rasterizer = glState.getRasterizerState();
1168     rasterizer.pointDrawMode       = (drawMode == gl::PrimitiveMode::Points);
1169     rasterizer.multiSample         = (samples != 0);
1170 
1171     ANGLE_TRY(setBlendDepthRasterStates(context, drawMode));
1172 
1173     mStateManager.resetDirtyBits();
1174 
1175     return angle::Result::Continue;
1176 }
1177 
setScissorRectangle(const gl::Rectangle & scissor,bool enabled)1178 void Renderer9::setScissorRectangle(const gl::Rectangle &scissor, bool enabled)
1179 {
1180     mStateManager.setScissorState(scissor, enabled);
1181 }
1182 
setBlendDepthRasterStates(const gl::Context * context,gl::PrimitiveMode drawMode)1183 angle::Result Renderer9::setBlendDepthRasterStates(const gl::Context *context,
1184                                                    gl::PrimitiveMode drawMode)
1185 {
1186     const auto &glState              = context->getState();
1187     gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
1188     ASSERT(!drawFramebuffer->hasAnyDirtyBit());
1189     // Since framebuffer->getSamples will return the original samples which may be different with
1190     // the sample counts that we set in render target view, here we use renderTarget->getSamples to
1191     // get the actual samples.
1192     GLsizei samples = 0;
1193     const gl::FramebufferAttachment *firstColorAttachment =
1194         drawFramebuffer->getFirstColorAttachment();
1195     if (firstColorAttachment)
1196     {
1197         ASSERT(firstColorAttachment->isAttached());
1198         RenderTarget9 *renderTarget = nullptr;
1199         ANGLE_TRY(firstColorAttachment->getRenderTarget(context, firstColorAttachment->getSamples(),
1200                                                         &renderTarget));
1201         samples = renderTarget->getSamples();
1202     }
1203     gl::RasterizerState rasterizer = glState.getRasterizerState();
1204     rasterizer.pointDrawMode       = (drawMode == gl::PrimitiveMode::Points);
1205     rasterizer.multiSample         = (samples != 0);
1206 
1207     unsigned int mask = GetBlendSampleMask(glState, samples);
1208     mStateManager.setBlendDepthRasterStates(glState, mask);
1209     return angle::Result::Continue;
1210 }
1211 
setViewport(const gl::Rectangle & viewport,float zNear,float zFar,gl::PrimitiveMode drawMode,GLenum frontFace,bool ignoreViewport)1212 void Renderer9::setViewport(const gl::Rectangle &viewport,
1213                             float zNear,
1214                             float zFar,
1215                             gl::PrimitiveMode drawMode,
1216                             GLenum frontFace,
1217                             bool ignoreViewport)
1218 {
1219     mStateManager.setViewportState(viewport, zNear, zFar, drawMode, frontFace, ignoreViewport);
1220 }
1221 
applyPrimitiveType(gl::PrimitiveMode mode,GLsizei count,bool usesPointSize)1222 bool Renderer9::applyPrimitiveType(gl::PrimitiveMode mode, GLsizei count, bool usesPointSize)
1223 {
1224     switch (mode)
1225     {
1226         case gl::PrimitiveMode::Points:
1227             mPrimitiveType  = D3DPT_POINTLIST;
1228             mPrimitiveCount = count;
1229             break;
1230         case gl::PrimitiveMode::Lines:
1231             mPrimitiveType  = D3DPT_LINELIST;
1232             mPrimitiveCount = count / 2;
1233             break;
1234         case gl::PrimitiveMode::LineLoop:
1235             mPrimitiveType = D3DPT_LINESTRIP;
1236             mPrimitiveCount =
1237                 count - 1;  // D3D doesn't support line loops, so we draw the last line separately
1238             break;
1239         case gl::PrimitiveMode::LineStrip:
1240             mPrimitiveType  = D3DPT_LINESTRIP;
1241             mPrimitiveCount = count - 1;
1242             break;
1243         case gl::PrimitiveMode::Triangles:
1244             mPrimitiveType  = D3DPT_TRIANGLELIST;
1245             mPrimitiveCount = count / 3;
1246             break;
1247         case gl::PrimitiveMode::TriangleStrip:
1248             mPrimitiveType  = D3DPT_TRIANGLESTRIP;
1249             mPrimitiveCount = count - 2;
1250             break;
1251         case gl::PrimitiveMode::TriangleFan:
1252             mPrimitiveType  = D3DPT_TRIANGLEFAN;
1253             mPrimitiveCount = count - 2;
1254             break;
1255         default:
1256             UNREACHABLE();
1257             return false;
1258     }
1259 
1260     return mPrimitiveCount > 0;
1261 }
1262 
getNullColorRenderTarget(const gl::Context * context,const RenderTarget9 * depthRenderTarget,const RenderTarget9 ** outColorRenderTarget)1263 angle::Result Renderer9::getNullColorRenderTarget(const gl::Context *context,
1264                                                   const RenderTarget9 *depthRenderTarget,
1265                                                   const RenderTarget9 **outColorRenderTarget)
1266 {
1267     ASSERT(depthRenderTarget);
1268 
1269     const gl::Extents &size = depthRenderTarget->getExtents();
1270 
1271     // search cached nullcolorbuffers
1272     for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
1273     {
1274         if (mNullRenderTargetCache[i].renderTarget != nullptr &&
1275             mNullRenderTargetCache[i].width == size.width &&
1276             mNullRenderTargetCache[i].height == size.height)
1277         {
1278             mNullRenderTargetCache[i].lruCount = ++mMaxNullColorbufferLRU;
1279             *outColorRenderTarget              = mNullRenderTargetCache[i].renderTarget;
1280             return angle::Result::Continue;
1281         }
1282     }
1283 
1284     RenderTargetD3D *nullRenderTarget = nullptr;
1285     ANGLE_TRY(createRenderTarget(context, size.width, size.height, GL_NONE, 0, &nullRenderTarget));
1286 
1287     // add nullbuffer to the cache
1288     NullRenderTargetCacheEntry *oldest = &mNullRenderTargetCache[0];
1289     for (int i = 1; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
1290     {
1291         if (mNullRenderTargetCache[i].lruCount < oldest->lruCount)
1292         {
1293             oldest = &mNullRenderTargetCache[i];
1294         }
1295     }
1296 
1297     SafeDelete(oldest->renderTarget);
1298     oldest->renderTarget = GetAs<RenderTarget9>(nullRenderTarget);
1299     oldest->lruCount     = ++mMaxNullColorbufferLRU;
1300     oldest->width        = size.width;
1301     oldest->height       = size.height;
1302 
1303     *outColorRenderTarget = oldest->renderTarget;
1304     return angle::Result::Continue;
1305 }
1306 
applyRenderTarget(const gl::Context * context,const RenderTarget9 * colorRenderTargetIn,const RenderTarget9 * depthStencilRenderTarget)1307 angle::Result Renderer9::applyRenderTarget(const gl::Context *context,
1308                                            const RenderTarget9 *colorRenderTargetIn,
1309                                            const RenderTarget9 *depthStencilRenderTarget)
1310 {
1311     // if there is no color attachment we must synthesize a NULL colorattachment
1312     // to keep the D3D runtime happy.  This should only be possible if depth texturing.
1313     const RenderTarget9 *colorRenderTarget = colorRenderTargetIn;
1314     if (colorRenderTarget == nullptr)
1315     {
1316         ANGLE_TRY(getNullColorRenderTarget(context, depthStencilRenderTarget, &colorRenderTarget));
1317     }
1318     ASSERT(colorRenderTarget != nullptr);
1319 
1320     size_t renderTargetWidth  = 0;
1321     size_t renderTargetHeight = 0;
1322 
1323     bool renderTargetChanged        = false;
1324     unsigned int renderTargetSerial = colorRenderTarget->getSerial();
1325     if (renderTargetSerial != mAppliedRenderTargetSerial)
1326     {
1327         // Apply the render target on the device
1328         IDirect3DSurface9 *renderTargetSurface = colorRenderTarget->getSurface();
1329         ASSERT(renderTargetSurface);
1330 
1331         mDevice->SetRenderTarget(0, renderTargetSurface);
1332         SafeRelease(renderTargetSurface);
1333 
1334         renderTargetWidth  = colorRenderTarget->getWidth();
1335         renderTargetHeight = colorRenderTarget->getHeight();
1336 
1337         mAppliedRenderTargetSerial = renderTargetSerial;
1338         renderTargetChanged        = true;
1339     }
1340 
1341     unsigned int depthStencilSerial = 0;
1342     if (depthStencilRenderTarget != nullptr)
1343     {
1344         depthStencilSerial = depthStencilRenderTarget->getSerial();
1345     }
1346 
1347     if (depthStencilSerial != mAppliedDepthStencilSerial || !mDepthStencilInitialized)
1348     {
1349         unsigned int depthSize   = 0;
1350         unsigned int stencilSize = 0;
1351 
1352         // Apply the depth stencil on the device
1353         if (depthStencilRenderTarget)
1354         {
1355             IDirect3DSurface9 *depthStencilSurface = depthStencilRenderTarget->getSurface();
1356             ASSERT(depthStencilSurface);
1357 
1358             mDevice->SetDepthStencilSurface(depthStencilSurface);
1359             SafeRelease(depthStencilSurface);
1360 
1361             const gl::InternalFormat &format =
1362                 gl::GetSizedInternalFormatInfo(depthStencilRenderTarget->getInternalFormat());
1363 
1364             depthSize   = format.depthBits;
1365             stencilSize = format.stencilBits;
1366         }
1367         else
1368         {
1369             mDevice->SetDepthStencilSurface(nullptr);
1370         }
1371 
1372         mStateManager.updateDepthSizeIfChanged(mDepthStencilInitialized, depthSize);
1373         mStateManager.updateStencilSizeIfChanged(mDepthStencilInitialized, stencilSize);
1374 
1375         mAppliedDepthStencilSerial = depthStencilSerial;
1376         mDepthStencilInitialized   = true;
1377     }
1378 
1379     if (renderTargetChanged || !mRenderTargetDescInitialized)
1380     {
1381         mStateManager.forceSetBlendState();
1382         mStateManager.forceSetScissorState();
1383         mStateManager.setRenderTargetBounds(renderTargetWidth, renderTargetHeight);
1384         mRenderTargetDescInitialized = true;
1385     }
1386 
1387     return angle::Result::Continue;
1388 }
1389 
applyVertexBuffer(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances,TranslatedIndexData *)1390 angle::Result Renderer9::applyVertexBuffer(const gl::Context *context,
1391                                            gl::PrimitiveMode mode,
1392                                            GLint first,
1393                                            GLsizei count,
1394                                            GLsizei instances,
1395                                            TranslatedIndexData * /*indexInfo*/)
1396 {
1397     const gl::State &state = context->getState();
1398     ANGLE_TRY(mVertexDataManager->prepareVertexData(context, first, count, &mTranslatedAttribCache,
1399                                                     instances));
1400 
1401     return mVertexDeclarationCache.applyDeclaration(context, mDevice, mTranslatedAttribCache,
1402                                                     state.getProgramExecutable(), first, instances,
1403                                                     &mRepeatDraw);
1404 }
1405 
1406 // Applies the indices and element array bindings to the Direct3D 9 device
applyIndexBuffer(const gl::Context * context,const void * indices,GLsizei count,gl::PrimitiveMode mode,gl::DrawElementsType type,TranslatedIndexData * indexInfo)1407 angle::Result Renderer9::applyIndexBuffer(const gl::Context *context,
1408                                           const void *indices,
1409                                           GLsizei count,
1410                                           gl::PrimitiveMode mode,
1411                                           gl::DrawElementsType type,
1412                                           TranslatedIndexData *indexInfo)
1413 {
1414     gl::VertexArray *vao           = context->getState().getVertexArray();
1415     gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1416 
1417     gl::DrawElementsType dstType = gl::DrawElementsType::InvalidEnum;
1418     ANGLE_TRY(GetIndexTranslationDestType(context, count, type, indices, false, &dstType));
1419 
1420     ANGLE_TRY(mIndexDataManager->prepareIndexData(context, type, dstType, count, elementArrayBuffer,
1421                                                   indices, indexInfo));
1422 
1423     // Directly binding the storage buffer is not supported for d3d9
1424     ASSERT(indexInfo->storage == nullptr);
1425 
1426     if (indexInfo->serial != mAppliedIBSerial)
1427     {
1428         IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(indexInfo->indexBuffer);
1429 
1430         mDevice->SetIndices(indexBuffer->getBuffer());
1431         mAppliedIBSerial = indexInfo->serial;
1432     }
1433 
1434     return angle::Result::Continue;
1435 }
1436 
drawArraysImpl(const gl::Context * context,gl::PrimitiveMode mode,GLint startVertex,GLsizei count,GLsizei instances)1437 angle::Result Renderer9::drawArraysImpl(const gl::Context *context,
1438                                         gl::PrimitiveMode mode,
1439                                         GLint startVertex,
1440                                         GLsizei count,
1441                                         GLsizei instances)
1442 {
1443     ASSERT(!context->getState().isTransformFeedbackActiveUnpaused());
1444 
1445     startScene();
1446 
1447     if (mode == gl::PrimitiveMode::LineLoop)
1448     {
1449         return drawLineLoop(context, count, gl::DrawElementsType::InvalidEnum, nullptr, 0, nullptr);
1450     }
1451 
1452     if (instances > 0)
1453     {
1454         StaticIndexBufferInterface *countingIB = nullptr;
1455         ANGLE_TRY(getCountingIB(context, count, &countingIB));
1456 
1457         if (mAppliedIBSerial != countingIB->getSerial())
1458         {
1459             IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(countingIB->getIndexBuffer());
1460 
1461             mDevice->SetIndices(indexBuffer->getBuffer());
1462             mAppliedIBSerial = countingIB->getSerial();
1463         }
1464 
1465         for (int i = 0; i < mRepeatDraw; i++)
1466         {
1467             mDevice->DrawIndexedPrimitive(mPrimitiveType, 0, 0, count, 0, mPrimitiveCount);
1468         }
1469 
1470         return angle::Result::Continue;
1471     }
1472 
1473     // Regular case
1474     mDevice->DrawPrimitive(mPrimitiveType, 0, mPrimitiveCount);
1475     return angle::Result::Continue;
1476 }
1477 
drawElementsImpl(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)1478 angle::Result Renderer9::drawElementsImpl(const gl::Context *context,
1479                                           gl::PrimitiveMode mode,
1480                                           GLsizei count,
1481                                           gl::DrawElementsType type,
1482                                           const void *indices,
1483                                           GLsizei instances)
1484 {
1485     TranslatedIndexData indexInfo;
1486 
1487     ANGLE_TRY(applyIndexBuffer(context, indices, count, mode, type, &indexInfo));
1488 
1489     gl::IndexRange indexRange;
1490     ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(context, type, count, indices,
1491                                                                   &indexRange));
1492 
1493     size_t vertexCount = indexRange.vertexCount();
1494     ANGLE_TRY(applyVertexBuffer(context, mode, static_cast<GLsizei>(indexRange.start),
1495                                 static_cast<GLsizei>(vertexCount), instances, &indexInfo));
1496 
1497     startScene();
1498 
1499     int minIndex = static_cast<int>(indexRange.start);
1500 
1501     gl::VertexArray *vao           = context->getState().getVertexArray();
1502     gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
1503 
1504     if (mode == gl::PrimitiveMode::Points)
1505     {
1506         return drawIndexedPoints(context, count, type, indices, minIndex, elementArrayBuffer);
1507     }
1508 
1509     if (mode == gl::PrimitiveMode::LineLoop)
1510     {
1511         return drawLineLoop(context, count, type, indices, minIndex, elementArrayBuffer);
1512     }
1513 
1514     for (int i = 0; i < mRepeatDraw; i++)
1515     {
1516         mDevice->DrawIndexedPrimitive(mPrimitiveType, -minIndex, minIndex,
1517                                       static_cast<UINT>(vertexCount), indexInfo.startIndex,
1518                                       mPrimitiveCount);
1519     }
1520     return angle::Result::Continue;
1521 }
1522 
drawLineLoop(const gl::Context * context,GLsizei count,gl::DrawElementsType type,const void * indices,int minIndex,gl::Buffer * elementArrayBuffer)1523 angle::Result Renderer9::drawLineLoop(const gl::Context *context,
1524                                       GLsizei count,
1525                                       gl::DrawElementsType type,
1526                                       const void *indices,
1527                                       int minIndex,
1528                                       gl::Buffer *elementArrayBuffer)
1529 {
1530     // Get the raw indices for an indexed draw
1531     if (type != gl::DrawElementsType::InvalidEnum && elementArrayBuffer)
1532     {
1533         BufferD3D *storage        = GetImplAs<BufferD3D>(elementArrayBuffer);
1534         intptr_t offset           = reinterpret_cast<intptr_t>(indices);
1535         const uint8_t *bufferData = nullptr;
1536         ANGLE_TRY(storage->getData(context, &bufferData));
1537         indices = bufferData + offset;
1538     }
1539 
1540     unsigned int startIndex = 0;
1541     Context9 *context9      = GetImplAs<Context9>(context);
1542 
1543     if (getNativeExtensions().elementIndexUintOES)
1544     {
1545         if (!mLineLoopIB)
1546         {
1547             mLineLoopIB = new StreamingIndexBufferInterface(this);
1548             ANGLE_TRY(mLineLoopIB->reserveBufferSpace(context, INITIAL_INDEX_BUFFER_SIZE,
1549                                                       gl::DrawElementsType::UnsignedInt));
1550         }
1551 
1552         // Checked by Renderer9::applyPrimitiveType
1553         ASSERT(count >= 0);
1554 
1555         ANGLE_CHECK(context9,
1556                     static_cast<unsigned int>(count) + 1 <=
1557                         (std::numeric_limits<unsigned int>::max() / sizeof(unsigned int)),
1558                     "Failed to create a 32-bit looping index buffer for "
1559                     "GL_LINE_LOOP, too many indices required.",
1560                     GL_OUT_OF_MEMORY);
1561 
1562         const unsigned int spaceNeeded =
1563             (static_cast<unsigned int>(count) + 1) * sizeof(unsigned int);
1564         ANGLE_TRY(mLineLoopIB->reserveBufferSpace(context, spaceNeeded,
1565                                                   gl::DrawElementsType::UnsignedInt));
1566 
1567         void *mappedMemory  = nullptr;
1568         unsigned int offset = 0;
1569         ANGLE_TRY(mLineLoopIB->mapBuffer(context, spaceNeeded, &mappedMemory, &offset));
1570 
1571         startIndex         = static_cast<unsigned int>(offset) / 4;
1572         unsigned int *data = static_cast<unsigned int *>(mappedMemory);
1573 
1574         switch (type)
1575         {
1576             case gl::DrawElementsType::InvalidEnum:  // Non-indexed draw
1577                 for (int i = 0; i < count; i++)
1578                 {
1579                     data[i] = i;
1580                 }
1581                 data[count] = 0;
1582                 break;
1583             case gl::DrawElementsType::UnsignedByte:
1584                 for (int i = 0; i < count; i++)
1585                 {
1586                     data[i] = static_cast<const GLubyte *>(indices)[i];
1587                 }
1588                 data[count] = static_cast<const GLubyte *>(indices)[0];
1589                 break;
1590             case gl::DrawElementsType::UnsignedShort:
1591                 for (int i = 0; i < count; i++)
1592                 {
1593                     data[i] = static_cast<const GLushort *>(indices)[i];
1594                 }
1595                 data[count] = static_cast<const GLushort *>(indices)[0];
1596                 break;
1597             case gl::DrawElementsType::UnsignedInt:
1598                 for (int i = 0; i < count; i++)
1599                 {
1600                     data[i] = static_cast<const GLuint *>(indices)[i];
1601                 }
1602                 data[count] = static_cast<const GLuint *>(indices)[0];
1603                 break;
1604             default:
1605                 UNREACHABLE();
1606         }
1607 
1608         ANGLE_TRY(mLineLoopIB->unmapBuffer(context));
1609     }
1610     else
1611     {
1612         if (!mLineLoopIB)
1613         {
1614             mLineLoopIB = new StreamingIndexBufferInterface(this);
1615             ANGLE_TRY(mLineLoopIB->reserveBufferSpace(context, INITIAL_INDEX_BUFFER_SIZE,
1616                                                       gl::DrawElementsType::UnsignedShort));
1617         }
1618 
1619         // Checked by Renderer9::applyPrimitiveType
1620         ASSERT(count >= 0);
1621 
1622         ANGLE_CHECK(context9,
1623                     static_cast<unsigned int>(count) + 1 <=
1624                         (std::numeric_limits<unsigned short>::max() / sizeof(unsigned short)),
1625                     "Failed to create a 16-bit looping index buffer for "
1626                     "GL_LINE_LOOP, too many indices required.",
1627                     GL_OUT_OF_MEMORY);
1628 
1629         const unsigned int spaceNeeded =
1630             (static_cast<unsigned int>(count) + 1) * sizeof(unsigned short);
1631         ANGLE_TRY(mLineLoopIB->reserveBufferSpace(context, spaceNeeded,
1632                                                   gl::DrawElementsType::UnsignedShort));
1633 
1634         void *mappedMemory = nullptr;
1635         unsigned int offset;
1636         ANGLE_TRY(mLineLoopIB->mapBuffer(context, spaceNeeded, &mappedMemory, &offset));
1637 
1638         startIndex           = static_cast<unsigned int>(offset) / 2;
1639         unsigned short *data = static_cast<unsigned short *>(mappedMemory);
1640 
1641         switch (type)
1642         {
1643             case gl::DrawElementsType::InvalidEnum:  // Non-indexed draw
1644                 for (int i = 0; i < count; i++)
1645                 {
1646                     data[i] = static_cast<unsigned short>(i);
1647                 }
1648                 data[count] = 0;
1649                 break;
1650             case gl::DrawElementsType::UnsignedByte:
1651                 for (int i = 0; i < count; i++)
1652                 {
1653                     data[i] = static_cast<const GLubyte *>(indices)[i];
1654                 }
1655                 data[count] = static_cast<const GLubyte *>(indices)[0];
1656                 break;
1657             case gl::DrawElementsType::UnsignedShort:
1658                 for (int i = 0; i < count; i++)
1659                 {
1660                     data[i] = static_cast<const GLushort *>(indices)[i];
1661                 }
1662                 data[count] = static_cast<const GLushort *>(indices)[0];
1663                 break;
1664             case gl::DrawElementsType::UnsignedInt:
1665                 for (int i = 0; i < count; i++)
1666                 {
1667                     data[i] = static_cast<unsigned short>(static_cast<const GLuint *>(indices)[i]);
1668                 }
1669                 data[count] = static_cast<unsigned short>(static_cast<const GLuint *>(indices)[0]);
1670                 break;
1671             default:
1672                 UNREACHABLE();
1673         }
1674 
1675         ANGLE_TRY(mLineLoopIB->unmapBuffer(context));
1676     }
1677 
1678     if (mAppliedIBSerial != mLineLoopIB->getSerial())
1679     {
1680         IndexBuffer9 *indexBuffer = GetAs<IndexBuffer9>(mLineLoopIB->getIndexBuffer());
1681 
1682         mDevice->SetIndices(indexBuffer->getBuffer());
1683         mAppliedIBSerial = mLineLoopIB->getSerial();
1684     }
1685 
1686     mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count);
1687 
1688     return angle::Result::Continue;
1689 }
1690 
drawIndexedPoints(const gl::Context * context,GLsizei count,gl::DrawElementsType type,const void * indices,int minIndex,gl::Buffer * elementArrayBuffer)1691 angle::Result Renderer9::drawIndexedPoints(const gl::Context *context,
1692                                            GLsizei count,
1693                                            gl::DrawElementsType type,
1694                                            const void *indices,
1695                                            int minIndex,
1696                                            gl::Buffer *elementArrayBuffer)
1697 {
1698     // Drawing index point lists is unsupported in d3d9, fall back to a regular DrawPrimitive call
1699     // for each individual point. This call is not expected to happen often.
1700 
1701     if (elementArrayBuffer)
1702     {
1703         BufferD3D *storage = GetImplAs<BufferD3D>(elementArrayBuffer);
1704         intptr_t offset    = reinterpret_cast<intptr_t>(indices);
1705 
1706         const uint8_t *bufferData = nullptr;
1707         ANGLE_TRY(storage->getData(context, &bufferData));
1708         indices = bufferData + offset;
1709     }
1710 
1711     switch (type)
1712     {
1713         case gl::DrawElementsType::UnsignedByte:
1714             DrawPoints<GLubyte>(mDevice, count, indices, minIndex);
1715             return angle::Result::Continue;
1716         case gl::DrawElementsType::UnsignedShort:
1717             DrawPoints<GLushort>(mDevice, count, indices, minIndex);
1718             return angle::Result::Continue;
1719         case gl::DrawElementsType::UnsignedInt:
1720             DrawPoints<GLuint>(mDevice, count, indices, minIndex);
1721             return angle::Result::Continue;
1722         default:
1723             ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
1724     }
1725 }
1726 
getCountingIB(const gl::Context * context,size_t count,StaticIndexBufferInterface ** outIB)1727 angle::Result Renderer9::getCountingIB(const gl::Context *context,
1728                                        size_t count,
1729                                        StaticIndexBufferInterface **outIB)
1730 {
1731     // Update the counting index buffer if it is not large enough or has not been created yet.
1732     if (count <= 65536)  // 16-bit indices
1733     {
1734         const unsigned int spaceNeeded = static_cast<unsigned int>(count) * sizeof(unsigned short);
1735 
1736         if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded)
1737         {
1738             SafeDelete(mCountingIB);
1739             mCountingIB = new StaticIndexBufferInterface(this);
1740             ANGLE_TRY(mCountingIB->reserveBufferSpace(context, spaceNeeded,
1741                                                       gl::DrawElementsType::UnsignedShort));
1742 
1743             void *mappedMemory = nullptr;
1744             ANGLE_TRY(mCountingIB->mapBuffer(context, spaceNeeded, &mappedMemory, nullptr));
1745 
1746             unsigned short *data = static_cast<unsigned short *>(mappedMemory);
1747             for (size_t i = 0; i < count; i++)
1748             {
1749                 data[i] = static_cast<unsigned short>(i);
1750             }
1751 
1752             ANGLE_TRY(mCountingIB->unmapBuffer(context));
1753         }
1754     }
1755     else if (getNativeExtensions().elementIndexUintOES)
1756     {
1757         const unsigned int spaceNeeded = static_cast<unsigned int>(count) * sizeof(unsigned int);
1758 
1759         if (!mCountingIB || mCountingIB->getBufferSize() < spaceNeeded)
1760         {
1761             SafeDelete(mCountingIB);
1762             mCountingIB = new StaticIndexBufferInterface(this);
1763             ANGLE_TRY(mCountingIB->reserveBufferSpace(context, spaceNeeded,
1764                                                       gl::DrawElementsType::UnsignedInt));
1765 
1766             void *mappedMemory = nullptr;
1767             ANGLE_TRY(mCountingIB->mapBuffer(context, spaceNeeded, &mappedMemory, nullptr));
1768 
1769             unsigned int *data = static_cast<unsigned int *>(mappedMemory);
1770             for (unsigned int i = 0; i < count; i++)
1771             {
1772                 data[i] = i;
1773             }
1774 
1775             ANGLE_TRY(mCountingIB->unmapBuffer(context));
1776         }
1777     }
1778     else
1779     {
1780         ANGLE_TRY_HR(GetImplAs<Context9>(context), E_OUTOFMEMORY,
1781                      "Could not create a counting index buffer for glDrawArraysInstanced.");
1782     }
1783 
1784     *outIB = mCountingIB;
1785     return angle::Result::Continue;
1786 }
1787 
applyShaders(const gl::Context * context,gl::PrimitiveMode drawMode)1788 angle::Result Renderer9::applyShaders(const gl::Context *context, gl::PrimitiveMode drawMode)
1789 {
1790     const gl::State &state = context->getState();
1791     Context9 *context9     = GetImplAs<Context9>(context);
1792     RendererD3D *renderer  = context9->getRenderer();
1793 
1794     // This method is called single-threaded.
1795     ANGLE_TRY(ensureHLSLCompilerInitialized(context9));
1796 
1797     ProgramExecutableD3D *executableD3D =
1798         GetImplAs<ProgramExecutableD3D>(state.getProgramExecutable());
1799     VertexArray9 *vao = GetImplAs<VertexArray9>(state.getVertexArray());
1800     executableD3D->updateCachedInputLayout(renderer, vao->getCurrentStateSerial(), state);
1801 
1802     ShaderExecutableD3D *vertexExe = nullptr;
1803     ANGLE_TRY(executableD3D->getVertexExecutableForCachedInputLayout(context9, renderer, &vertexExe,
1804                                                                      nullptr));
1805 
1806     const gl::Framebuffer *drawFramebuffer = state.getDrawFramebuffer();
1807     executableD3D->updateCachedOutputLayout(context, drawFramebuffer);
1808 
1809     ShaderExecutableD3D *pixelExe = nullptr;
1810     ANGLE_TRY(executableD3D->getPixelExecutableForCachedOutputLayout(context9, renderer, &pixelExe,
1811                                                                      nullptr));
1812 
1813     IDirect3DVertexShader9 *vertexShader =
1814         (vertexExe ? GetAs<ShaderExecutable9>(vertexExe)->getVertexShader() : nullptr);
1815     IDirect3DPixelShader9 *pixelShader =
1816         (pixelExe ? GetAs<ShaderExecutable9>(pixelExe)->getPixelShader() : nullptr);
1817 
1818     if (vertexShader != mAppliedVertexShader)
1819     {
1820         mDevice->SetVertexShader(vertexShader);
1821         mAppliedVertexShader = vertexShader;
1822     }
1823 
1824     if (pixelShader != mAppliedPixelShader)
1825     {
1826         mDevice->SetPixelShader(pixelShader);
1827         mAppliedPixelShader = pixelShader;
1828     }
1829 
1830     // D3D9 has a quirk where creating multiple shaders with the same content
1831     // can return the same shader pointer. Because GL programs store different data
1832     // per-program, checking the program serial guarantees we upload fresh
1833     // uniform data even if our shader pointers are the same.
1834     // https://code.google.com/p/angleproject/issues/detail?id=661
1835     unsigned int programSerial = executableD3D->getSerial();
1836     if (programSerial != mAppliedProgramSerial)
1837     {
1838         executableD3D->dirtyAllUniforms();
1839         mStateManager.forceSetDXUniformsState();
1840         mAppliedProgramSerial = programSerial;
1841     }
1842 
1843     applyUniforms(executableD3D);
1844 
1845     // Driver uniforms
1846     mStateManager.setShaderConstants();
1847 
1848     return angle::Result::Continue;
1849 }
1850 
applyUniforms(ProgramExecutableD3D * executableD3D)1851 void Renderer9::applyUniforms(ProgramExecutableD3D *executableD3D)
1852 {
1853     // Skip updates if we're not dirty. Note that D3D9 cannot have compute or geometry.
1854     if (!executableD3D->anyShaderUniformsDirty())
1855     {
1856         return;
1857     }
1858 
1859     const auto &uniformArray = executableD3D->getD3DUniforms();
1860 
1861     for (const D3DUniform *targetUniform : uniformArray)
1862     {
1863         // Built-in uniforms must be skipped.
1864         if (!targetUniform->isReferencedByShader(gl::ShaderType::Vertex) &&
1865             !targetUniform->isReferencedByShader(gl::ShaderType::Fragment))
1866             continue;
1867 
1868         const GLfloat *f = reinterpret_cast<const GLfloat *>(targetUniform->firstNonNullData());
1869         const GLint *i   = reinterpret_cast<const GLint *>(targetUniform->firstNonNullData());
1870 
1871         switch (targetUniform->typeInfo.type)
1872         {
1873             case GL_SAMPLER_2D:
1874             case GL_SAMPLER_CUBE:
1875             case GL_SAMPLER_EXTERNAL_OES:
1876             case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
1877                 break;
1878             case GL_BOOL:
1879             case GL_BOOL_VEC2:
1880             case GL_BOOL_VEC3:
1881             case GL_BOOL_VEC4:
1882                 applyUniformnbv(targetUniform, i);
1883                 break;
1884             case GL_FLOAT:
1885             case GL_FLOAT_VEC2:
1886             case GL_FLOAT_VEC3:
1887             case GL_FLOAT_VEC4:
1888             case GL_FLOAT_MAT2:
1889             case GL_FLOAT_MAT3:
1890             case GL_FLOAT_MAT4:
1891                 applyUniformnfv(targetUniform, f);
1892                 break;
1893             case GL_INT:
1894             case GL_INT_VEC2:
1895             case GL_INT_VEC3:
1896             case GL_INT_VEC4:
1897                 applyUniformniv(targetUniform, i);
1898                 break;
1899             default:
1900                 UNREACHABLE();
1901         }
1902     }
1903 
1904     executableD3D->markUniformsClean();
1905 }
1906 
applyUniformnfv(const D3DUniform * targetUniform,const GLfloat * v)1907 void Renderer9::applyUniformnfv(const D3DUniform *targetUniform, const GLfloat *v)
1908 {
1909     if (targetUniform->isReferencedByShader(gl::ShaderType::Fragment))
1910     {
1911         mDevice->SetPixelShaderConstantF(
1912             targetUniform->mShaderRegisterIndexes[gl::ShaderType::Fragment], v,
1913             targetUniform->registerCount);
1914     }
1915 
1916     if (targetUniform->isReferencedByShader(gl::ShaderType::Vertex))
1917     {
1918         mDevice->SetVertexShaderConstantF(
1919             targetUniform->mShaderRegisterIndexes[gl::ShaderType::Vertex], v,
1920             targetUniform->registerCount);
1921     }
1922 }
1923 
applyUniformniv(const D3DUniform * targetUniform,const GLint * v)1924 void Renderer9::applyUniformniv(const D3DUniform *targetUniform, const GLint *v)
1925 {
1926     ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
1927     GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
1928 
1929     for (unsigned int i = 0; i < targetUniform->registerCount; i++)
1930     {
1931         vector[i][0] = (GLfloat)v[4 * i + 0];
1932         vector[i][1] = (GLfloat)v[4 * i + 1];
1933         vector[i][2] = (GLfloat)v[4 * i + 2];
1934         vector[i][3] = (GLfloat)v[4 * i + 3];
1935     }
1936 
1937     applyUniformnfv(targetUniform, (GLfloat *)vector);
1938 }
1939 
applyUniformnbv(const D3DUniform * targetUniform,const GLint * v)1940 void Renderer9::applyUniformnbv(const D3DUniform *targetUniform, const GLint *v)
1941 {
1942     ASSERT(targetUniform->registerCount <= MAX_VERTEX_CONSTANT_VECTORS_D3D9);
1943     GLfloat vector[MAX_VERTEX_CONSTANT_VECTORS_D3D9][4];
1944 
1945     for (unsigned int i = 0; i < targetUniform->registerCount; i++)
1946     {
1947         vector[i][0] = (v[4 * i + 0] == GL_FALSE) ? 0.0f : 1.0f;
1948         vector[i][1] = (v[4 * i + 1] == GL_FALSE) ? 0.0f : 1.0f;
1949         vector[i][2] = (v[4 * i + 2] == GL_FALSE) ? 0.0f : 1.0f;
1950         vector[i][3] = (v[4 * i + 3] == GL_FALSE) ? 0.0f : 1.0f;
1951     }
1952 
1953     applyUniformnfv(targetUniform, (GLfloat *)vector);
1954 }
1955 
clear(const ClearParameters & clearParams,const RenderTarget9 * colorRenderTarget,const RenderTarget9 * depthStencilRenderTarget)1956 void Renderer9::clear(const ClearParameters &clearParams,
1957                       const RenderTarget9 *colorRenderTarget,
1958                       const RenderTarget9 *depthStencilRenderTarget)
1959 {
1960     // Clearing buffers with non-float values is not supported by Renderer9 and ES 2.0
1961     ASSERT(clearParams.colorType == GL_FLOAT);
1962 
1963     // Clearing individual buffers other than buffer zero is not supported by Renderer9 and ES 2.0
1964     bool clearColor = clearParams.clearColor[0];
1965     for (unsigned int i = 0; i < clearParams.clearColor.size(); i++)
1966     {
1967         ASSERT(clearParams.clearColor[i] == clearColor);
1968     }
1969 
1970     float depth   = gl::clamp01(clearParams.depthValue);
1971     DWORD stencil = clearParams.stencilValue & 0x000000FF;
1972 
1973     unsigned int stencilUnmasked = 0x0;
1974     if (clearParams.clearStencil && depthStencilRenderTarget)
1975     {
1976         const gl::InternalFormat &depthStencilFormat =
1977             gl::GetSizedInternalFormatInfo(depthStencilRenderTarget->getInternalFormat());
1978         if (depthStencilFormat.stencilBits > 0)
1979         {
1980             const d3d9::D3DFormat &d3dFormatInfo =
1981                 d3d9::GetD3DFormatInfo(depthStencilRenderTarget->getD3DFormat());
1982             stencilUnmasked = (0x1 << d3dFormatInfo.stencilBits) - 1;
1983         }
1984     }
1985 
1986     const bool needMaskedStencilClear =
1987         clearParams.clearStencil &&
1988         (clearParams.stencilWriteMask & stencilUnmasked) != stencilUnmasked;
1989 
1990     bool needMaskedColorClear = false;
1991     D3DCOLOR color            = D3DCOLOR_ARGB(255, 0, 0, 0);
1992     if (clearColor)
1993     {
1994         ASSERT(colorRenderTarget != nullptr);
1995 
1996         const gl::InternalFormat &formatInfo =
1997             gl::GetSizedInternalFormatInfo(colorRenderTarget->getInternalFormat());
1998         const d3d9::D3DFormat &d3dFormatInfo =
1999             d3d9::GetD3DFormatInfo(colorRenderTarget->getD3DFormat());
2000 
2001         color =
2002             D3DCOLOR_ARGB(gl::unorm<8>((formatInfo.alphaBits == 0 && d3dFormatInfo.alphaBits > 0)
2003                                            ? 1.0f
2004                                            : clearParams.colorF.alpha),
2005                           gl::unorm<8>((formatInfo.redBits == 0 && d3dFormatInfo.redBits > 0)
2006                                            ? 0.0f
2007                                            : clearParams.colorF.red),
2008                           gl::unorm<8>((formatInfo.greenBits == 0 && d3dFormatInfo.greenBits > 0)
2009                                            ? 0.0f
2010                                            : clearParams.colorF.green),
2011                           gl::unorm<8>((formatInfo.blueBits == 0 && d3dFormatInfo.blueBits > 0)
2012                                            ? 0.0f
2013                                            : clearParams.colorF.blue));
2014 
2015         const uint8_t colorMask =
2016             gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(0, clearParams.colorMask);
2017         bool r, g, b, a;
2018         gl::BlendStateExt::UnpackColorMask(colorMask, &r, &g, &b, &a);
2019         if ((formatInfo.redBits > 0 && !r) || (formatInfo.greenBits > 0 && !g) ||
2020             (formatInfo.blueBits > 0 && !b) || (formatInfo.alphaBits > 0 && !a))
2021         {
2022             needMaskedColorClear = true;
2023         }
2024     }
2025 
2026     if (needMaskedColorClear || needMaskedStencilClear)
2027     {
2028         // State which is altered in all paths from this point to the clear call is saved.
2029         // State which is altered in only some paths will be flagged dirty in the case that
2030         //  that path is taken.
2031         HRESULT hr;
2032         if (mMaskedClearSavedState == nullptr)
2033         {
2034             hr = mDevice->BeginStateBlock();
2035             ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
2036 
2037             mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
2038             mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
2039             mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
2040             mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
2041             mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
2042             mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
2043             mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
2044             mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
2045             mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
2046             mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
2047             mDevice->SetPixelShader(nullptr);
2048             mDevice->SetVertexShader(nullptr);
2049             mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
2050             mDevice->SetStreamSource(0, nullptr, 0, 0);
2051             mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
2052             mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
2053             mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
2054             mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
2055             mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
2056             mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
2057             mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
2058 
2059             for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
2060             {
2061                 mDevice->SetStreamSourceFreq(i, 1);
2062             }
2063 
2064             hr = mDevice->EndStateBlock(&mMaskedClearSavedState);
2065             ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
2066         }
2067 
2068         ASSERT(mMaskedClearSavedState != nullptr);
2069 
2070         if (mMaskedClearSavedState != nullptr)
2071         {
2072             hr = mMaskedClearSavedState->Capture();
2073             ASSERT(SUCCEEDED(hr));
2074         }
2075 
2076         mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
2077         mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
2078         mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
2079         mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
2080         mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
2081         mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
2082         mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
2083         mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
2084 
2085         if (clearColor)
2086         {
2087             // clearParams.colorMask follows the same packing scheme as
2088             // D3DCOLORWRITEENABLE_RED/GREEN/BLUE/ALPHA
2089             mDevice->SetRenderState(
2090                 D3DRS_COLORWRITEENABLE,
2091                 gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(0, clearParams.colorMask));
2092         }
2093         else
2094         {
2095             mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
2096         }
2097 
2098         if (stencilUnmasked != 0x0 && clearParams.clearStencil)
2099         {
2100             mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
2101             mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
2102             mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
2103             mDevice->SetRenderState(D3DRS_STENCILREF, stencil);
2104             mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, clearParams.stencilWriteMask);
2105             mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
2106             mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
2107             mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
2108         }
2109         else
2110         {
2111             mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
2112         }
2113 
2114         mDevice->SetPixelShader(nullptr);
2115         mDevice->SetVertexShader(nullptr);
2116         mDevice->SetFVF(D3DFVF_XYZRHW);
2117         mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
2118         mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
2119         mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
2120         mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
2121         mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
2122         mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
2123         mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
2124 
2125         for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
2126         {
2127             mDevice->SetStreamSourceFreq(i, 1);
2128         }
2129 
2130         int renderTargetWidth  = mStateManager.getRenderTargetWidth();
2131         int renderTargetHeight = mStateManager.getRenderTargetHeight();
2132 
2133         float quad[4][4];  // A quadrilateral covering the target, aligned to match the edges
2134         quad[0][0] = -0.5f;
2135         quad[0][1] = renderTargetHeight - 0.5f;
2136         quad[0][2] = 0.0f;
2137         quad[0][3] = 1.0f;
2138 
2139         quad[1][0] = renderTargetWidth - 0.5f;
2140         quad[1][1] = renderTargetHeight - 0.5f;
2141         quad[1][2] = 0.0f;
2142         quad[1][3] = 1.0f;
2143 
2144         quad[2][0] = -0.5f;
2145         quad[2][1] = -0.5f;
2146         quad[2][2] = 0.0f;
2147         quad[2][3] = 1.0f;
2148 
2149         quad[3][0] = renderTargetWidth - 0.5f;
2150         quad[3][1] = -0.5f;
2151         quad[3][2] = 0.0f;
2152         quad[3][3] = 1.0f;
2153 
2154         startScene();
2155         mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
2156 
2157         if (clearParams.clearDepth)
2158         {
2159             mDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
2160             mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
2161             mDevice->Clear(0, nullptr, D3DCLEAR_ZBUFFER, color, depth, stencil);
2162         }
2163 
2164         if (mMaskedClearSavedState != nullptr)
2165         {
2166             mMaskedClearSavedState->Apply();
2167         }
2168     }
2169     else if (clearColor || clearParams.clearDepth || clearParams.clearStencil)
2170     {
2171         DWORD dxClearFlags = 0;
2172         if (clearColor)
2173         {
2174             dxClearFlags |= D3DCLEAR_TARGET;
2175         }
2176         if (clearParams.clearDepth)
2177         {
2178             dxClearFlags |= D3DCLEAR_ZBUFFER;
2179         }
2180         if (clearParams.clearStencil)
2181         {
2182             dxClearFlags |= D3DCLEAR_STENCIL;
2183         }
2184 
2185         mDevice->Clear(0, nullptr, dxClearFlags, color, depth, stencil);
2186     }
2187 }
2188 
markAllStateDirty()2189 void Renderer9::markAllStateDirty()
2190 {
2191     mAppliedRenderTargetSerial   = 0;
2192     mAppliedDepthStencilSerial   = 0;
2193     mDepthStencilInitialized     = false;
2194     mRenderTargetDescInitialized = false;
2195 
2196     mStateManager.forceSetRasterState();
2197     mStateManager.forceSetDepthStencilState();
2198     mStateManager.forceSetBlendState();
2199     mStateManager.forceSetScissorState();
2200     mStateManager.forceSetViewportState();
2201 
2202     ASSERT(mCurVertexSamplerStates.size() == mCurVertexTextures.size());
2203     for (unsigned int i = 0; i < mCurVertexTextures.size(); i++)
2204     {
2205         mCurVertexSamplerStates[i].forceSet = true;
2206         mCurVertexTextures[i]               = angle::DirtyPointer;
2207     }
2208 
2209     ASSERT(mCurPixelSamplerStates.size() == mCurPixelTextures.size());
2210     for (unsigned int i = 0; i < mCurPixelSamplerStates.size(); i++)
2211     {
2212         mCurPixelSamplerStates[i].forceSet = true;
2213         mCurPixelTextures[i]               = angle::DirtyPointer;
2214     }
2215 
2216     mAppliedIBSerial      = 0;
2217     mAppliedVertexShader  = nullptr;
2218     mAppliedPixelShader   = nullptr;
2219     mAppliedProgramSerial = 0;
2220     mStateManager.forceSetDXUniformsState();
2221 
2222     mVertexDeclarationCache.markStateDirty();
2223 }
2224 
releaseDeviceResources()2225 void Renderer9::releaseDeviceResources()
2226 {
2227     for (size_t i = 0; i < mEventQueryPool.size(); i++)
2228     {
2229         SafeRelease(mEventQueryPool[i]);
2230     }
2231     mEventQueryPool.clear();
2232 
2233     SafeRelease(mMaskedClearSavedState);
2234 
2235     mVertexShaderCache.clear();
2236     mPixelShaderCache.clear();
2237 
2238     SafeDelete(mBlit);
2239     SafeDelete(mVertexDataManager);
2240     SafeDelete(mIndexDataManager);
2241     SafeDelete(mLineLoopIB);
2242     SafeDelete(mCountingIB);
2243 
2244     for (int i = 0; i < NUM_NULL_COLORBUFFER_CACHE_ENTRIES; i++)
2245     {
2246         SafeDelete(mNullRenderTargetCache[i].renderTarget);
2247     }
2248 }
2249 
2250 // set notify to true to broadcast a message to all contexts of the device loss
testDeviceLost()2251 bool Renderer9::testDeviceLost()
2252 {
2253     HRESULT status = getDeviceStatusCode();
2254     return FAILED(status);
2255 }
2256 
getDeviceStatusCode()2257 HRESULT Renderer9::getDeviceStatusCode()
2258 {
2259     HRESULT status = D3D_OK;
2260 
2261     if (mDeviceEx)
2262     {
2263         status = mDeviceEx->CheckDeviceState(nullptr);
2264     }
2265     else if (mDevice)
2266     {
2267         status = mDevice->TestCooperativeLevel();
2268     }
2269 
2270     return status;
2271 }
2272 
testDeviceResettable()2273 bool Renderer9::testDeviceResettable()
2274 {
2275     // On D3D9Ex, DEVICELOST represents a hung device that needs to be restarted
2276     // DEVICEREMOVED indicates the device has been stopped and must be recreated
2277     switch (getDeviceStatusCode())
2278     {
2279         case D3DERR_DEVICENOTRESET:
2280         case D3DERR_DEVICEHUNG:
2281             return true;
2282         case D3DERR_DEVICELOST:
2283             return (mDeviceEx != nullptr);
2284         case D3DERR_DEVICEREMOVED:
2285             ASSERT(mDeviceEx != nullptr);
2286             return isRemovedDeviceResettable();
2287         default:
2288             return false;
2289     }
2290 }
2291 
resetDevice()2292 bool Renderer9::resetDevice()
2293 {
2294     releaseDeviceResources();
2295 
2296     D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
2297 
2298     HRESULT result     = D3D_OK;
2299     bool lost          = testDeviceLost();
2300     bool removedDevice = (getDeviceStatusCode() == D3DERR_DEVICEREMOVED);
2301 
2302     // Device Removed is a feature which is only present with D3D9Ex
2303     ASSERT(mDeviceEx != nullptr || !removedDevice);
2304 
2305     for (int attempts = 3; lost && attempts > 0; attempts--)
2306     {
2307         if (removedDevice)
2308         {
2309             // Device removed, which may trigger on driver reinstallation,
2310             // may cause a longer wait other reset attempts before the
2311             // system is ready to handle creating a new device.
2312             Sleep(800);
2313             lost = !resetRemovedDevice();
2314         }
2315         else if (mDeviceEx)
2316         {
2317             Sleep(500);  // Give the graphics driver some CPU time
2318             result = mDeviceEx->ResetEx(&presentParameters, nullptr);
2319             lost   = testDeviceLost();
2320         }
2321         else
2322         {
2323             result = mDevice->TestCooperativeLevel();
2324             while (result == D3DERR_DEVICELOST)
2325             {
2326                 Sleep(100);  // Give the graphics driver some CPU time
2327                 result = mDevice->TestCooperativeLevel();
2328             }
2329 
2330             if (result == D3DERR_DEVICENOTRESET)
2331             {
2332                 result = mDevice->Reset(&presentParameters);
2333             }
2334             lost = testDeviceLost();
2335         }
2336     }
2337 
2338     if (FAILED(result))
2339     {
2340         ERR() << "Reset/ResetEx failed multiple times, " << gl::FmtHR(result);
2341         return false;
2342     }
2343 
2344     if (removedDevice && lost)
2345     {
2346         ERR() << "Device lost reset failed multiple times";
2347         return false;
2348     }
2349 
2350     // If the device was removed, we already finished re-initialization in resetRemovedDevice
2351     if (!removedDevice)
2352     {
2353         // reset device defaults
2354         if (initializeDevice().isError())
2355         {
2356             return false;
2357         }
2358     }
2359 
2360     return true;
2361 }
2362 
isRemovedDeviceResettable() const2363 bool Renderer9::isRemovedDeviceResettable() const
2364 {
2365     bool success = false;
2366 
2367 #if ANGLE_D3D9EX
2368     IDirect3D9Ex *d3d9Ex = nullptr;
2369     typedef HRESULT(WINAPI * Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex **);
2370     Direct3DCreate9ExFunc Direct3DCreate9ExPtr =
2371         reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
2372 
2373     if (Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &d3d9Ex)))
2374     {
2375         D3DCAPS9 deviceCaps;
2376         HRESULT result = d3d9Ex->GetDeviceCaps(mAdapter, mDeviceType, &deviceCaps);
2377         success        = SUCCEEDED(result);
2378     }
2379 
2380     SafeRelease(d3d9Ex);
2381 #else
2382     UNREACHABLE();
2383 #endif
2384 
2385     return success;
2386 }
2387 
resetRemovedDevice()2388 bool Renderer9::resetRemovedDevice()
2389 {
2390     // From http://msdn.microsoft.com/en-us/library/windows/desktop/bb172554(v=vs.85).aspx:
2391     // The hardware adapter has been removed. Application must destroy the device, do enumeration of
2392     // adapters and create another Direct3D device. If application continues rendering without
2393     // calling Reset, the rendering calls will succeed. Applies to Direct3D 9Ex only.
2394     release();
2395     return !initialize().isError();
2396 }
2397 
getVendorId() const2398 VendorID Renderer9::getVendorId() const
2399 {
2400     return static_cast<VendorID>(mAdapterIdentifier.VendorId);
2401 }
2402 
getRendererDescription() const2403 std::string Renderer9::getRendererDescription() const
2404 {
2405     std::ostringstream rendererString;
2406 
2407     rendererString << mAdapterIdentifier.Description;
2408     if (getShareHandleSupport())
2409     {
2410         rendererString << " Direct3D9Ex";
2411     }
2412     else
2413     {
2414         rendererString << " Direct3D9";
2415     }
2416 
2417     rendererString << " vs_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.VertexShaderVersion) << "_"
2418                    << D3DSHADER_VERSION_MINOR(mDeviceCaps.VertexShaderVersion);
2419     rendererString << " ps_" << D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion) << "_"
2420                    << D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion);
2421 
2422     return rendererString.str();
2423 }
2424 
getAdapterIdentifier() const2425 DeviceIdentifier Renderer9::getAdapterIdentifier() const
2426 {
2427     DeviceIdentifier deviceIdentifier = {};
2428     deviceIdentifier.VendorId         = static_cast<UINT>(mAdapterIdentifier.VendorId);
2429     deviceIdentifier.DeviceId         = static_cast<UINT>(mAdapterIdentifier.DeviceId);
2430     deviceIdentifier.SubSysId         = static_cast<UINT>(mAdapterIdentifier.SubSysId);
2431     deviceIdentifier.Revision         = static_cast<UINT>(mAdapterIdentifier.Revision);
2432     deviceIdentifier.FeatureLevel     = 0;
2433 
2434     return deviceIdentifier;
2435 }
2436 
getReservedVertexUniformVectors() const2437 unsigned int Renderer9::getReservedVertexUniformVectors() const
2438 {
2439     return d3d9_gl::GetReservedVertexUniformVectors();
2440 }
2441 
getReservedFragmentUniformVectors() const2442 unsigned int Renderer9::getReservedFragmentUniformVectors() const
2443 {
2444     return d3d9_gl::GetReservedFragmentUniformVectors();
2445 }
2446 
getShareHandleSupport() const2447 bool Renderer9::getShareHandleSupport() const
2448 {
2449     // PIX doesn't seem to support using share handles, so disable them.
2450     return (mD3d9Ex != nullptr) && !gl::DebugAnnotationsActive(/*context=*/nullptr);
2451 }
2452 
getMajorShaderModel() const2453 int Renderer9::getMajorShaderModel() const
2454 {
2455     return D3DSHADER_VERSION_MAJOR(mDeviceCaps.PixelShaderVersion);
2456 }
2457 
getMinorShaderModel() const2458 int Renderer9::getMinorShaderModel() const
2459 {
2460     return D3DSHADER_VERSION_MINOR(mDeviceCaps.PixelShaderVersion);
2461 }
2462 
getShaderModelSuffix() const2463 std::string Renderer9::getShaderModelSuffix() const
2464 {
2465     return "";
2466 }
2467 
getCapsDeclTypes() const2468 DWORD Renderer9::getCapsDeclTypes() const
2469 {
2470     return mDeviceCaps.DeclTypes;
2471 }
2472 
getBufferPool(DWORD usage) const2473 D3DPOOL Renderer9::getBufferPool(DWORD usage) const
2474 {
2475     if (mD3d9Ex != nullptr)
2476     {
2477         return D3DPOOL_DEFAULT;
2478     }
2479     else
2480     {
2481         if (!(usage & D3DUSAGE_DYNAMIC))
2482         {
2483             return D3DPOOL_MANAGED;
2484         }
2485     }
2486 
2487     return D3DPOOL_DEFAULT;
2488 }
2489 
copyImage2D(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLint level)2490 angle::Result Renderer9::copyImage2D(const gl::Context *context,
2491                                      const gl::Framebuffer *framebuffer,
2492                                      const gl::Rectangle &sourceRect,
2493                                      GLenum destFormat,
2494                                      const gl::Offset &destOffset,
2495                                      TextureStorage *storage,
2496                                      GLint level)
2497 {
2498     RECT rect;
2499     rect.left   = sourceRect.x;
2500     rect.top    = sourceRect.y;
2501     rect.right  = sourceRect.x + sourceRect.width;
2502     rect.bottom = sourceRect.y + sourceRect.height;
2503 
2504     return mBlit->copy2D(context, framebuffer, rect, destFormat, destOffset, storage, level);
2505 }
2506 
copyImageCube(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,gl::TextureTarget target,GLint level)2507 angle::Result Renderer9::copyImageCube(const gl::Context *context,
2508                                        const gl::Framebuffer *framebuffer,
2509                                        const gl::Rectangle &sourceRect,
2510                                        GLenum destFormat,
2511                                        const gl::Offset &destOffset,
2512                                        TextureStorage *storage,
2513                                        gl::TextureTarget target,
2514                                        GLint level)
2515 {
2516     RECT rect;
2517     rect.left   = sourceRect.x;
2518     rect.top    = sourceRect.y;
2519     rect.right  = sourceRect.x + sourceRect.width;
2520     rect.bottom = sourceRect.y + sourceRect.height;
2521 
2522     return mBlit->copyCube(context, framebuffer, rect, destFormat, destOffset, storage, target,
2523                            level);
2524 }
2525 
copyImage3D(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLint level)2526 angle::Result Renderer9::copyImage3D(const gl::Context *context,
2527                                      const gl::Framebuffer *framebuffer,
2528                                      const gl::Rectangle &sourceRect,
2529                                      GLenum destFormat,
2530                                      const gl::Offset &destOffset,
2531                                      TextureStorage *storage,
2532                                      GLint level)
2533 {
2534     // 3D textures are not available in the D3D9 backend.
2535     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
2536     return angle::Result::Stop;
2537 }
2538 
copyImage2DArray(const gl::Context * context,const gl::Framebuffer * framebuffer,const gl::Rectangle & sourceRect,GLenum destFormat,const gl::Offset & destOffset,TextureStorage * storage,GLint level)2539 angle::Result Renderer9::copyImage2DArray(const gl::Context *context,
2540                                           const gl::Framebuffer *framebuffer,
2541                                           const gl::Rectangle &sourceRect,
2542                                           GLenum destFormat,
2543                                           const gl::Offset &destOffset,
2544                                           TextureStorage *storage,
2545                                           GLint level)
2546 {
2547     // 2D array textures are not available in the D3D9 backend.
2548     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
2549     return angle::Result::Stop;
2550 }
2551 
copyTexture(const gl::Context * context,const gl::Texture * source,GLint sourceLevel,gl::TextureTarget srcTarget,const gl::Box & sourceBox,GLenum destFormat,GLenum destType,const gl::Offset & destOffset,TextureStorage * storage,gl::TextureTarget destTarget,GLint destLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha)2552 angle::Result Renderer9::copyTexture(const gl::Context *context,
2553                                      const gl::Texture *source,
2554                                      GLint sourceLevel,
2555                                      gl::TextureTarget srcTarget,
2556                                      const gl::Box &sourceBox,
2557                                      GLenum destFormat,
2558                                      GLenum destType,
2559                                      const gl::Offset &destOffset,
2560                                      TextureStorage *storage,
2561                                      gl::TextureTarget destTarget,
2562                                      GLint destLevel,
2563                                      bool unpackFlipY,
2564                                      bool unpackPremultiplyAlpha,
2565                                      bool unpackUnmultiplyAlpha)
2566 {
2567     RECT rect;
2568     rect.left   = sourceBox.x;
2569     rect.top    = sourceBox.y;
2570     rect.right  = sourceBox.x + sourceBox.width;
2571     rect.bottom = sourceBox.y + sourceBox.height;
2572 
2573     return mBlit->copyTexture(context, source, sourceLevel, rect, destFormat, destOffset, storage,
2574                               destTarget, destLevel, unpackFlipY, unpackPremultiplyAlpha,
2575                               unpackUnmultiplyAlpha);
2576 }
2577 
copyCompressedTexture(const gl::Context * context,const gl::Texture * source,GLint sourceLevel,TextureStorage * storage,GLint destLevel)2578 angle::Result Renderer9::copyCompressedTexture(const gl::Context *context,
2579                                                const gl::Texture *source,
2580                                                GLint sourceLevel,
2581                                                TextureStorage *storage,
2582                                                GLint destLevel)
2583 {
2584     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
2585     return angle::Result::Stop;
2586 }
2587 
createRenderTarget(const gl::Context * context,int width,int height,GLenum format,GLsizei samples,RenderTargetD3D ** outRT)2588 angle::Result Renderer9::createRenderTarget(const gl::Context *context,
2589                                             int width,
2590                                             int height,
2591                                             GLenum format,
2592                                             GLsizei samples,
2593                                             RenderTargetD3D **outRT)
2594 {
2595     const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(format);
2596 
2597     const gl::TextureCaps &textureCaps = getNativeTextureCaps().get(format);
2598     GLuint supportedSamples            = textureCaps.getNearestSamples(samples);
2599 
2600     IDirect3DTexture9 *texture      = nullptr;
2601     IDirect3DSurface9 *renderTarget = nullptr;
2602     if (width > 0 && height > 0)
2603     {
2604         bool requiresInitialization = false;
2605         HRESULT result              = D3DERR_INVALIDCALL;
2606 
2607         const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format);
2608         if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
2609         {
2610             result = mDevice->CreateDepthStencilSurface(
2611                 width, height, d3d9FormatInfo.renderFormat,
2612                 gl_d3d9::GetMultisampleType(supportedSamples), 0, FALSE, &renderTarget, nullptr);
2613         }
2614         else
2615         {
2616             requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != nullptr);
2617             if (supportedSamples > 0)
2618             {
2619                 result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat,
2620                                                      gl_d3d9::GetMultisampleType(supportedSamples),
2621                                                      0, FALSE, &renderTarget, nullptr);
2622             }
2623             else
2624             {
2625                 result = mDevice->CreateTexture(
2626                     width, height, 1, D3DUSAGE_RENDERTARGET, d3d9FormatInfo.texFormat,
2627                     getTexturePool(D3DUSAGE_RENDERTARGET), &texture, nullptr);
2628                 if (!FAILED(result))
2629                 {
2630                     result = texture->GetSurfaceLevel(0, &renderTarget);
2631                 }
2632             }
2633         }
2634 
2635         ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to create render target");
2636 
2637         if (requiresInitialization)
2638         {
2639             // This format requires that the data be initialized before the render target can be
2640             // used Unfortunately this requires a Get call on the d3d device but it is far better
2641             // than having to mark the render target as lockable and copy data to the gpu.
2642             IDirect3DSurface9 *prevRenderTarget = nullptr;
2643             mDevice->GetRenderTarget(0, &prevRenderTarget);
2644             mDevice->SetRenderTarget(0, renderTarget);
2645             mDevice->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0);
2646             mDevice->SetRenderTarget(0, prevRenderTarget);
2647         }
2648     }
2649 
2650     *outRT = new TextureRenderTarget9(texture, 0, renderTarget, format, width, height, 1,
2651                                       supportedSamples);
2652     return angle::Result::Continue;
2653 }
2654 
createRenderTargetCopy(const gl::Context * context,RenderTargetD3D * source,RenderTargetD3D ** outRT)2655 angle::Result Renderer9::createRenderTargetCopy(const gl::Context *context,
2656                                                 RenderTargetD3D *source,
2657                                                 RenderTargetD3D **outRT)
2658 {
2659     ASSERT(source != nullptr);
2660 
2661     RenderTargetD3D *newRT = nullptr;
2662     ANGLE_TRY(createRenderTarget(context, source->getWidth(), source->getHeight(),
2663                                  source->getInternalFormat(), source->getSamples(), &newRT));
2664 
2665     RenderTarget9 *source9 = GetAs<RenderTarget9>(source);
2666     RenderTarget9 *dest9   = GetAs<RenderTarget9>(newRT);
2667 
2668     HRESULT result = mDevice->StretchRect(source9->getSurface(), nullptr, dest9->getSurface(),
2669                                           nullptr, D3DTEXF_NONE);
2670     ANGLE_TRY_HR(GetImplAs<Context9>(context), result, "Failed to copy render target");
2671 
2672     *outRT = newRT;
2673     return angle::Result::Continue;
2674 }
2675 
loadExecutable(d3d::Context * context,const uint8_t * function,size_t length,gl::ShaderType type,const std::vector<D3DVarying> & streamOutVaryings,bool separatedOutputBuffers,ShaderExecutableD3D ** outExecutable)2676 angle::Result Renderer9::loadExecutable(d3d::Context *context,
2677                                         const uint8_t *function,
2678                                         size_t length,
2679                                         gl::ShaderType type,
2680                                         const std::vector<D3DVarying> &streamOutVaryings,
2681                                         bool separatedOutputBuffers,
2682                                         ShaderExecutableD3D **outExecutable)
2683 {
2684     // Transform feedback is not supported in ES2 or D3D9
2685     ASSERT(streamOutVaryings.empty());
2686 
2687     switch (type)
2688     {
2689         case gl::ShaderType::Vertex:
2690         {
2691             IDirect3DVertexShader9 *vshader = nullptr;
2692             ANGLE_TRY(createVertexShader(context, (DWORD *)function, length, &vshader));
2693             *outExecutable = new ShaderExecutable9(function, length, vshader);
2694         }
2695         break;
2696         case gl::ShaderType::Fragment:
2697         {
2698             IDirect3DPixelShader9 *pshader = nullptr;
2699             ANGLE_TRY(createPixelShader(context, (DWORD *)function, length, &pshader));
2700             *outExecutable = new ShaderExecutable9(function, length, pshader);
2701         }
2702         break;
2703         default:
2704             ANGLE_HR_UNREACHABLE(context);
2705     }
2706 
2707     return angle::Result::Continue;
2708 }
2709 
compileToExecutable(d3d::Context * context,gl::InfoLog & infoLog,const std::string & shaderHLSL,gl::ShaderType type,const std::vector<D3DVarying> & streamOutVaryings,bool separatedOutputBuffers,const CompilerWorkaroundsD3D & workarounds,ShaderExecutableD3D ** outExectuable)2710 angle::Result Renderer9::compileToExecutable(d3d::Context *context,
2711                                              gl::InfoLog &infoLog,
2712                                              const std::string &shaderHLSL,
2713                                              gl::ShaderType type,
2714                                              const std::vector<D3DVarying> &streamOutVaryings,
2715                                              bool separatedOutputBuffers,
2716                                              const CompilerWorkaroundsD3D &workarounds,
2717                                              ShaderExecutableD3D **outExectuable)
2718 {
2719     // Transform feedback is not supported in ES2 or D3D9
2720     ASSERT(streamOutVaryings.empty());
2721 
2722     std::stringstream profileStream;
2723 
2724     switch (type)
2725     {
2726         case gl::ShaderType::Vertex:
2727             profileStream << "vs";
2728             break;
2729         case gl::ShaderType::Fragment:
2730             profileStream << "ps";
2731             break;
2732         default:
2733             ANGLE_HR_UNREACHABLE(context);
2734     }
2735 
2736     profileStream << "_" << ((getMajorShaderModel() >= 3) ? 3 : 2);
2737     profileStream << "_" << "0";
2738 
2739     std::string profile = profileStream.str();
2740 
2741     UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL;
2742 
2743     if (workarounds.skipOptimization)
2744     {
2745         flags = D3DCOMPILE_SKIP_OPTIMIZATION;
2746     }
2747     else if (workarounds.useMaxOptimization)
2748     {
2749         flags = D3DCOMPILE_OPTIMIZATION_LEVEL3;
2750     }
2751 
2752     if (gl::DebugAnnotationsActive(/*context=*/nullptr))
2753     {
2754 #ifndef NDEBUG
2755         flags = D3DCOMPILE_SKIP_OPTIMIZATION;
2756 #endif
2757 
2758         flags |= D3DCOMPILE_DEBUG;
2759     }
2760 
2761     // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders
2762     // when it would otherwise pass with alternative options. Try the default flags first and if
2763     // compilation fails, try some alternatives.
2764     std::vector<CompileConfig> configs;
2765     configs.push_back(CompileConfig(flags, "default"));
2766     configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control"));
2767     configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control"));
2768 
2769     ID3DBlob *binary = nullptr;
2770     std::string debugInfo;
2771     angle::Result error = mCompiler.compileToBinary(context, infoLog, shaderHLSL, profile, configs,
2772                                                     nullptr, &binary, &debugInfo);
2773     ANGLE_TRY(error);
2774 
2775     // It's possible that binary is NULL if the compiler failed in all configurations.  Set the
2776     // executable to NULL and return GL_NO_ERROR to signify that there was a link error but the
2777     // internal state is still OK.
2778     if (!binary)
2779     {
2780         *outExectuable = nullptr;
2781         return angle::Result::Continue;
2782     }
2783 
2784     error = loadExecutable(context, reinterpret_cast<const uint8_t *>(binary->GetBufferPointer()),
2785                            binary->GetBufferSize(), type, streamOutVaryings, separatedOutputBuffers,
2786                            outExectuable);
2787 
2788     SafeRelease(binary);
2789     ANGLE_TRY(error);
2790 
2791     if (!debugInfo.empty())
2792     {
2793         (*outExectuable)->appendDebugInfo(debugInfo);
2794     }
2795 
2796     return angle::Result::Continue;
2797 }
2798 
ensureHLSLCompilerInitialized(d3d::Context * context)2799 angle::Result Renderer9::ensureHLSLCompilerInitialized(d3d::Context *context)
2800 {
2801     return mCompiler.ensureInitialized(context);
2802 }
2803 
createUniformStorage(size_t storageSize)2804 UniformStorageD3D *Renderer9::createUniformStorage(size_t storageSize)
2805 {
2806     return new UniformStorageD3D(storageSize);
2807 }
2808 
boxFilter(Context9 * context9,IDirect3DSurface9 * source,IDirect3DSurface9 * dest)2809 angle::Result Renderer9::boxFilter(Context9 *context9,
2810                                    IDirect3DSurface9 *source,
2811                                    IDirect3DSurface9 *dest)
2812 {
2813     return mBlit->boxFilter(context9, source, dest);
2814 }
2815 
getTexturePool(DWORD usage) const2816 D3DPOOL Renderer9::getTexturePool(DWORD usage) const
2817 {
2818     if (mD3d9Ex != nullptr)
2819     {
2820         return D3DPOOL_DEFAULT;
2821     }
2822     else
2823     {
2824         if (!(usage & (D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_RENDERTARGET)))
2825         {
2826             return D3DPOOL_MANAGED;
2827         }
2828     }
2829 
2830     return D3DPOOL_DEFAULT;
2831 }
2832 
copyToRenderTarget(const gl::Context * context,IDirect3DSurface9 * dest,IDirect3DSurface9 * source,bool fromManaged)2833 angle::Result Renderer9::copyToRenderTarget(const gl::Context *context,
2834                                             IDirect3DSurface9 *dest,
2835                                             IDirect3DSurface9 *source,
2836                                             bool fromManaged)
2837 {
2838     ASSERT(source && dest);
2839 
2840     Context9 *context9 = GetImplAs<Context9>(context);
2841 
2842     HRESULT result = D3DERR_OUTOFVIDEOMEMORY;
2843 
2844     if (fromManaged)
2845     {
2846         D3DSURFACE_DESC desc;
2847         source->GetDesc(&desc);
2848 
2849         IDirect3DSurface9 *surf = 0;
2850         result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
2851                                                       D3DPOOL_SYSTEMMEM, &surf, nullptr);
2852 
2853         if (SUCCEEDED(result))
2854         {
2855             ANGLE_TRY(Image9::CopyLockableSurfaces(context9, surf, source));
2856             result = mDevice->UpdateSurface(surf, nullptr, dest, nullptr);
2857             SafeRelease(surf);
2858         }
2859     }
2860     else
2861     {
2862         endScene();
2863         result = mDevice->StretchRect(source, nullptr, dest, nullptr, D3DTEXF_NONE);
2864     }
2865 
2866     ANGLE_TRY_HR(context9, result, "Failed to blit internal texture");
2867     return angle::Result::Continue;
2868 }
2869 
getRendererClass() const2870 RendererClass Renderer9::getRendererClass() const
2871 {
2872     return RENDERER_D3D9;
2873 }
2874 
createImage()2875 ImageD3D *Renderer9::createImage()
2876 {
2877     return new Image9(this);
2878 }
2879 
createExternalImageSibling(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const egl::AttributeMap & attribs)2880 ExternalImageSiblingImpl *Renderer9::createExternalImageSibling(const gl::Context *context,
2881                                                                 EGLenum target,
2882                                                                 EGLClientBuffer buffer,
2883                                                                 const egl::AttributeMap &attribs)
2884 {
2885     UNREACHABLE();
2886     return nullptr;
2887 }
2888 
generateMipmap(const gl::Context * context,ImageD3D * dest,ImageD3D * src)2889 angle::Result Renderer9::generateMipmap(const gl::Context *context, ImageD3D *dest, ImageD3D *src)
2890 {
2891     Image9 *src9 = GetAs<Image9>(src);
2892     Image9 *dst9 = GetAs<Image9>(dest);
2893     return Image9::GenerateMipmap(GetImplAs<Context9>(context), dst9, src9);
2894 }
2895 
generateMipmapUsingD3D(const gl::Context * context,TextureStorage * storage,const gl::TextureState & textureState)2896 angle::Result Renderer9::generateMipmapUsingD3D(const gl::Context *context,
2897                                                 TextureStorage *storage,
2898                                                 const gl::TextureState &textureState)
2899 {
2900     ANGLE_HR_UNREACHABLE(GetImplAs<Context9>(context));
2901     return angle::Result::Stop;
2902 }
2903 
copyImage(const gl::Context * context,ImageD3D * dest,ImageD3D * source,const gl::Box & sourceBox,const gl::Offset & destOffset,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha)2904 angle::Result Renderer9::copyImage(const gl::Context *context,
2905                                    ImageD3D *dest,
2906                                    ImageD3D *source,
2907                                    const gl::Box &sourceBox,
2908                                    const gl::Offset &destOffset,
2909                                    bool unpackFlipY,
2910                                    bool unpackPremultiplyAlpha,
2911                                    bool unpackUnmultiplyAlpha)
2912 {
2913     Image9 *dest9 = GetAs<Image9>(dest);
2914     Image9 *src9  = GetAs<Image9>(source);
2915     return Image9::CopyImage(context, dest9, src9, sourceBox.toRect(), destOffset, unpackFlipY,
2916                              unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
2917 }
2918 
createTextureStorage2D(SwapChainD3D * swapChain,const std::string & label)2919 TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain, const std::string &label)
2920 {
2921     SwapChain9 *swapChain9 = GetAs<SwapChain9>(swapChain);
2922     return new TextureStorage9_2D(this, swapChain9, label);
2923 }
2924 
createTextureStorageEGLImage(EGLImageD3D * eglImage,RenderTargetD3D * renderTargetD3D,const std::string & label)2925 TextureStorage *Renderer9::createTextureStorageEGLImage(EGLImageD3D *eglImage,
2926                                                         RenderTargetD3D *renderTargetD3D,
2927                                                         const std::string &label)
2928 {
2929     return new TextureStorage9_EGLImage(this, eglImage, GetAs<RenderTarget9>(renderTargetD3D),
2930                                         label);
2931 }
2932 
createTextureStorageBuffer(const gl::OffsetBindingPointer<gl::Buffer> & buffer,GLenum internalFormat,const std::string & label)2933 TextureStorage *Renderer9::createTextureStorageBuffer(
2934     const gl::OffsetBindingPointer<gl::Buffer> &buffer,
2935     GLenum internalFormat,
2936     const std::string &label)
2937 {
2938     UNREACHABLE();
2939     return nullptr;
2940 }
2941 
createTextureStorageExternal(egl::Stream * stream,const egl::Stream::GLTextureDescription & desc,const std::string & label)2942 TextureStorage *Renderer9::createTextureStorageExternal(
2943     egl::Stream *stream,
2944     const egl::Stream::GLTextureDescription &desc,
2945     const std::string &label)
2946 {
2947     UNIMPLEMENTED();
2948     return nullptr;
2949 }
2950 
createTextureStorage2D(GLenum internalformat,BindFlags bindFlags,GLsizei width,GLsizei height,int levels,const std::string & label,bool hintLevelZeroOnly)2951 TextureStorage *Renderer9::createTextureStorage2D(GLenum internalformat,
2952                                                   BindFlags bindFlags,
2953                                                   GLsizei width,
2954                                                   GLsizei height,
2955                                                   int levels,
2956                                                   const std::string &label,
2957                                                   bool hintLevelZeroOnly)
2958 {
2959     return new TextureStorage9_2D(this, internalformat, bindFlags.renderTarget, width, height,
2960                                   levels, label);
2961 }
2962 
createTextureStorageCube(GLenum internalformat,BindFlags bindFlags,int size,int levels,bool hintLevelZeroOnly,const std::string & label)2963 TextureStorage *Renderer9::createTextureStorageCube(GLenum internalformat,
2964                                                     BindFlags bindFlags,
2965                                                     int size,
2966                                                     int levels,
2967                                                     bool hintLevelZeroOnly,
2968                                                     const std::string &label)
2969 {
2970     return new TextureStorage9_Cube(this, internalformat, bindFlags.renderTarget, size, levels,
2971                                     hintLevelZeroOnly, label);
2972 }
2973 
createTextureStorage3D(GLenum internalformat,BindFlags bindFlags,GLsizei width,GLsizei height,GLsizei depth,int levels,const std::string & label)2974 TextureStorage *Renderer9::createTextureStorage3D(GLenum internalformat,
2975                                                   BindFlags bindFlags,
2976                                                   GLsizei width,
2977                                                   GLsizei height,
2978                                                   GLsizei depth,
2979                                                   int levels,
2980                                                   const std::string &label)
2981 {
2982     // 3D textures are not supported by the D3D9 backend.
2983     UNREACHABLE();
2984 
2985     return nullptr;
2986 }
2987 
createTextureStorage2DArray(GLenum internalformat,BindFlags bindFlags,GLsizei width,GLsizei height,GLsizei depth,int levels,const std::string & label)2988 TextureStorage *Renderer9::createTextureStorage2DArray(GLenum internalformat,
2989                                                        BindFlags bindFlags,
2990                                                        GLsizei width,
2991                                                        GLsizei height,
2992                                                        GLsizei depth,
2993                                                        int levels,
2994                                                        const std::string &label)
2995 {
2996     // 2D array textures are not supported by the D3D9 backend.
2997     UNREACHABLE();
2998 
2999     return nullptr;
3000 }
3001 
createTextureStorage2DMultisample(GLenum internalformat,GLsizei width,GLsizei height,int levels,int samples,bool fixedSampleLocations,const std::string & label)3002 TextureStorage *Renderer9::createTextureStorage2DMultisample(GLenum internalformat,
3003                                                              GLsizei width,
3004                                                              GLsizei height,
3005                                                              int levels,
3006                                                              int samples,
3007                                                              bool fixedSampleLocations,
3008                                                              const std::string &label)
3009 {
3010     // 2D multisampled textures are not supported by the D3D9 backend.
3011     UNREACHABLE();
3012 
3013     return nullptr;
3014 }
3015 
createTextureStorage2DMultisampleArray(GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth,int levels,int samples,bool fixedSampleLocations,const std::string & label)3016 TextureStorage *Renderer9::createTextureStorage2DMultisampleArray(GLenum internalformat,
3017                                                                   GLsizei width,
3018                                                                   GLsizei height,
3019                                                                   GLsizei depth,
3020                                                                   int levels,
3021                                                                   int samples,
3022                                                                   bool fixedSampleLocations,
3023                                                                   const std::string &label)
3024 {
3025     // 2D multisampled textures are not supported by the D3D9 backend.
3026     UNREACHABLE();
3027 
3028     return nullptr;
3029 }
3030 
getLUID(LUID * adapterLuid) const3031 bool Renderer9::getLUID(LUID *adapterLuid) const
3032 {
3033     adapterLuid->HighPart = 0;
3034     adapterLuid->LowPart  = 0;
3035 
3036     if (mD3d9Ex)
3037     {
3038         mD3d9Ex->GetAdapterLUID(mAdapter, adapterLuid);
3039         return true;
3040     }
3041 
3042     return false;
3043 }
3044 
getVertexConversionType(angle::FormatID vertexFormatID) const3045 VertexConversionType Renderer9::getVertexConversionType(angle::FormatID vertexFormatID) const
3046 {
3047     return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatID).conversionType;
3048 }
3049 
getVertexComponentType(angle::FormatID vertexFormatID) const3050 GLenum Renderer9::getVertexComponentType(angle::FormatID vertexFormatID) const
3051 {
3052     return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatID).componentType;
3053 }
3054 
getVertexSpaceRequired(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,size_t count,GLsizei instances,GLuint baseInstance,unsigned int * bytesRequiredOut) const3055 angle::Result Renderer9::getVertexSpaceRequired(const gl::Context *context,
3056                                                 const gl::VertexAttribute &attrib,
3057                                                 const gl::VertexBinding &binding,
3058                                                 size_t count,
3059                                                 GLsizei instances,
3060                                                 GLuint baseInstance,
3061                                                 unsigned int *bytesRequiredOut) const
3062 {
3063     if (!attrib.enabled)
3064     {
3065         *bytesRequiredOut = 16u;
3066         return angle::Result::Continue;
3067     }
3068 
3069     angle::FormatID vertexFormatID = gl::GetVertexFormatID(attrib, gl::VertexAttribType::Float);
3070     const d3d9::VertexFormat &d3d9VertexInfo =
3071         d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormatID);
3072 
3073     unsigned int elementCount  = 0;
3074     const unsigned int divisor = binding.getDivisor();
3075     if (instances == 0 || divisor == 0)
3076     {
3077         elementCount = static_cast<unsigned int>(count);
3078     }
3079     else
3080     {
3081         // Round up to divisor, if possible
3082         elementCount = UnsignedCeilDivide(static_cast<unsigned int>(instances), divisor);
3083     }
3084 
3085     bool check = (d3d9VertexInfo.outputElementSize >
3086                   std::numeric_limits<unsigned int>::max() / elementCount);
3087     ANGLE_CHECK(GetImplAs<Context9>(context), !check,
3088                 "New vertex buffer size would result in an overflow.", GL_OUT_OF_MEMORY);
3089 
3090     *bytesRequiredOut = static_cast<unsigned int>(d3d9VertexInfo.outputElementSize) * elementCount;
3091     return angle::Result::Continue;
3092 }
3093 
generateCaps(gl::Caps * outCaps,gl::TextureCapsMap * outTextureCaps,gl::Extensions * outExtensions,gl::Limitations * outLimitations,ShPixelLocalStorageOptions * outPLSOptions) const3094 void Renderer9::generateCaps(gl::Caps *outCaps,
3095                              gl::TextureCapsMap *outTextureCaps,
3096                              gl::Extensions *outExtensions,
3097                              gl::Limitations *outLimitations,
3098                              ShPixelLocalStorageOptions *outPLSOptions) const
3099 {
3100     d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps,
3101                           outExtensions, outLimitations);
3102 }
3103 
initializeFeatures(angle::FeaturesD3D * features) const3104 void Renderer9::initializeFeatures(angle::FeaturesD3D *features) const
3105 {
3106     ApplyFeatureOverrides(features, mDisplay->getState().featureOverrides);
3107     if (!mDisplay->getState().featureOverrides.allDisabled)
3108     {
3109         d3d9::InitializeFeatures(features, mAdapterIdentifier.VendorId);
3110     }
3111 }
3112 
initializeFrontendFeatures(angle::FrontendFeatures * features) const3113 void Renderer9::initializeFrontendFeatures(angle::FrontendFeatures *features) const
3114 {
3115     ApplyFeatureOverrides(features, mDisplay->getState().featureOverrides);
3116     if (!mDisplay->getState().featureOverrides.allDisabled)
3117     {
3118         d3d9::InitializeFrontendFeatures(features, mAdapterIdentifier.VendorId);
3119     }
3120 }
3121 
createEGLDevice()3122 DeviceImpl *Renderer9::createEGLDevice()
3123 {
3124     return new Device9(mDevice);
3125 }
3126 
CurSamplerState()3127 Renderer9::CurSamplerState::CurSamplerState()
3128     : forceSet(true), baseLevel(std::numeric_limits<size_t>::max()), samplerState()
3129 {}
3130 
genericDrawElements(const gl::Context * context,gl::PrimitiveMode mode,GLsizei count,gl::DrawElementsType type,const void * indices,GLsizei instances)3131 angle::Result Renderer9::genericDrawElements(const gl::Context *context,
3132                                              gl::PrimitiveMode mode,
3133                                              GLsizei count,
3134                                              gl::DrawElementsType type,
3135                                              const void *indices,
3136                                              GLsizei instances)
3137 {
3138     const gl::State &state = context->getState();
3139     ProgramExecutableD3D *executableD3D =
3140         GetImplAs<ProgramExecutableD3D>(state.getProgramExecutable());
3141     ASSERT(executableD3D != nullptr);
3142     bool usesPointSize = executableD3D->usesPointSize();
3143 
3144     if (executableD3D->isSamplerMappingDirty())
3145     {
3146         executableD3D->updateSamplerMapping();
3147     }
3148 
3149     if (!applyPrimitiveType(mode, count, usesPointSize))
3150     {
3151         return angle::Result::Continue;
3152     }
3153 
3154     ANGLE_TRY(updateState(context, mode));
3155     ANGLE_TRY(applyTextures(context));
3156     ANGLE_TRY(applyShaders(context, mode));
3157 
3158     if (!skipDraw(state, mode))
3159     {
3160         ANGLE_TRY(drawElementsImpl(context, mode, count, type, indices, instances));
3161     }
3162 
3163     return angle::Result::Continue;
3164 }
3165 
genericDrawArrays(const gl::Context * context,gl::PrimitiveMode mode,GLint first,GLsizei count,GLsizei instances)3166 angle::Result Renderer9::genericDrawArrays(const gl::Context *context,
3167                                            gl::PrimitiveMode mode,
3168                                            GLint first,
3169                                            GLsizei count,
3170                                            GLsizei instances)
3171 {
3172     const gl::State &state = context->getState();
3173     ProgramExecutableD3D *executableD3D =
3174         GetImplAs<ProgramExecutableD3D>(state.getProgramExecutable());
3175     ASSERT(executableD3D != nullptr);
3176     bool usesPointSize = executableD3D->usesPointSize();
3177 
3178     if (executableD3D->isSamplerMappingDirty())
3179     {
3180         executableD3D->updateSamplerMapping();
3181     }
3182 
3183     if (!applyPrimitiveType(mode, count, usesPointSize))
3184     {
3185         return angle::Result::Continue;
3186     }
3187 
3188     ANGLE_TRY(updateState(context, mode));
3189     ANGLE_TRY(applyVertexBuffer(context, mode, first, count, instances, nullptr));
3190     ANGLE_TRY(applyTextures(context));
3191     ANGLE_TRY(applyShaders(context, mode));
3192 
3193     if (!skipDraw(context->getState(), mode))
3194     {
3195         ANGLE_TRY(drawArraysImpl(context, mode, first, count, instances));
3196     }
3197 
3198     return angle::Result::Continue;
3199 }
3200 
createDefaultFramebuffer(const gl::FramebufferState & state)3201 FramebufferImpl *Renderer9::createDefaultFramebuffer(const gl::FramebufferState &state)
3202 {
3203     return new Framebuffer9(state, this);
3204 }
3205 
getMaxSupportedESVersion() const3206 gl::Version Renderer9::getMaxSupportedESVersion() const
3207 {
3208     return gl::Version(2, 0);
3209 }
3210 
getMaxConformantESVersion() const3211 gl::Version Renderer9::getMaxConformantESVersion() const
3212 {
3213     return gl::Version(2, 0);
3214 }
3215 
clearRenderTarget(const gl::Context * context,RenderTargetD3D * renderTarget,const gl::ColorF & clearColorValue,const float clearDepthValue,const unsigned int clearStencilValue)3216 angle::Result Renderer9::clearRenderTarget(const gl::Context *context,
3217                                            RenderTargetD3D *renderTarget,
3218                                            const gl::ColorF &clearColorValue,
3219                                            const float clearDepthValue,
3220                                            const unsigned int clearStencilValue)
3221 {
3222     D3DCOLOR color =
3223         D3DCOLOR_ARGB(gl::unorm<8>(clearColorValue.alpha), gl::unorm<8>(clearColorValue.red),
3224                       gl::unorm<8>(clearColorValue.green), gl::unorm<8>(clearColorValue.blue));
3225     float depth   = clearDepthValue;
3226     DWORD stencil = clearStencilValue & 0x000000FF;
3227 
3228     unsigned int renderTargetSerial        = renderTarget->getSerial();
3229     RenderTarget9 *renderTarget9           = GetAs<RenderTarget9>(renderTarget);
3230     IDirect3DSurface9 *renderTargetSurface = renderTarget9->getSurface();
3231     ASSERT(renderTargetSurface);
3232 
3233     DWORD dxClearFlags = 0;
3234 
3235     const gl::InternalFormat &internalFormatInfo =
3236         gl::GetSizedInternalFormatInfo(renderTarget->getInternalFormat());
3237     if (internalFormatInfo.depthBits > 0 || internalFormatInfo.stencilBits > 0)
3238     {
3239         dxClearFlags = D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL;
3240         if (mAppliedDepthStencilSerial != renderTargetSerial)
3241         {
3242             mDevice->SetDepthStencilSurface(renderTargetSurface);
3243         }
3244     }
3245     else
3246     {
3247         dxClearFlags = D3DCLEAR_TARGET;
3248         if (mAppliedRenderTargetSerial != renderTargetSerial)
3249         {
3250             mDevice->SetRenderTarget(0, renderTargetSurface);
3251         }
3252     }
3253     SafeRelease(renderTargetSurface);
3254 
3255     D3DVIEWPORT9 viewport;
3256     viewport.X      = 0;
3257     viewport.Y      = 0;
3258     viewport.Width  = renderTarget->getWidth();
3259     viewport.Height = renderTarget->getHeight();
3260     mDevice->SetViewport(&viewport);
3261 
3262     mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
3263 
3264     mDevice->Clear(0, nullptr, dxClearFlags, color, depth, stencil);
3265 
3266     markAllStateDirty();
3267 
3268     return angle::Result::Continue;
3269 }
3270 
canSelectViewInVertexShader() const3271 bool Renderer9::canSelectViewInVertexShader() const
3272 {
3273     return false;
3274 }
3275 
3276 // For each Direct3D sampler of either the pixel or vertex stage,
3277 // looks up the corresponding OpenGL texture image unit and texture type,
3278 // and sets the texture and its addressing/filtering state (or NULL when inactive).
3279 // Sampler mapping needs to be up-to-date on the program object before this is called.
applyTextures(const gl::Context * context,gl::ShaderType shaderType)3280 angle::Result Renderer9::applyTextures(const gl::Context *context, gl::ShaderType shaderType)
3281 {
3282     const auto &glState = context->getState();
3283     const auto &caps    = context->getCaps();
3284     ProgramExecutableD3D *executableD3D =
3285         GetImplAs<ProgramExecutableD3D>(glState.getProgramExecutable());
3286 
3287     ASSERT(!executableD3D->isSamplerMappingDirty());
3288 
3289     // TODO(jmadill): Use the Program's sampler bindings.
3290     const gl::ActiveTexturesCache &activeTextures = glState.getActiveTexturesCache();
3291 
3292     const gl::RangeUI samplerRange = executableD3D->getUsedSamplerRange(shaderType);
3293     for (unsigned int samplerIndex = samplerRange.low(); samplerIndex < samplerRange.high();
3294          samplerIndex++)
3295     {
3296         GLint textureUnit = executableD3D->getSamplerMapping(shaderType, samplerIndex, caps);
3297         ASSERT(textureUnit != -1);
3298         gl::Texture *texture = activeTextures[textureUnit];
3299 
3300         // A nullptr texture indicates incomplete.
3301         if (texture)
3302         {
3303             gl::Sampler *samplerObject = glState.getSampler(textureUnit);
3304 
3305             const gl::SamplerState &samplerState =
3306                 samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState();
3307 
3308             ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, texture, samplerState));
3309             ANGLE_TRY(setTexture(context, shaderType, samplerIndex, texture));
3310         }
3311         else
3312         {
3313             gl::TextureType textureType =
3314                 executableD3D->getSamplerTextureType(shaderType, samplerIndex);
3315 
3316             // Texture is not sampler complete or it is in use by the framebuffer.  Bind the
3317             // incomplete texture.
3318             gl::Texture *incompleteTexture = nullptr;
3319             ANGLE_TRY(getIncompleteTexture(context, textureType, &incompleteTexture));
3320             ANGLE_TRY(setSamplerState(context, shaderType, samplerIndex, incompleteTexture,
3321                                       incompleteTexture->getSamplerState()));
3322             ANGLE_TRY(setTexture(context, shaderType, samplerIndex, incompleteTexture));
3323         }
3324     }
3325 
3326     // Set all the remaining textures to NULL
3327     int samplerCount = (shaderType == gl::ShaderType::Fragment)
3328                            ? caps.maxShaderTextureImageUnits[gl::ShaderType::Fragment]
3329                            : caps.maxShaderTextureImageUnits[gl::ShaderType::Vertex];
3330 
3331     // TODO(jmadill): faster way?
3332     for (int samplerIndex = samplerRange.high(); samplerIndex < samplerCount; samplerIndex++)
3333     {
3334         ANGLE_TRY(setTexture(context, shaderType, samplerIndex, nullptr));
3335     }
3336 
3337     return angle::Result::Continue;
3338 }
3339 
applyTextures(const gl::Context * context)3340 angle::Result Renderer9::applyTextures(const gl::Context *context)
3341 {
3342     ANGLE_TRY(applyTextures(context, gl::ShaderType::Vertex));
3343     ANGLE_TRY(applyTextures(context, gl::ShaderType::Fragment));
3344     return angle::Result::Continue;
3345 }
3346 
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::Texture ** textureOut)3347 angle::Result Renderer9::getIncompleteTexture(const gl::Context *context,
3348                                               gl::TextureType type,
3349                                               gl::Texture **textureOut)
3350 {
3351     return GetImplAs<Context9>(context)->getIncompleteTexture(context, type, textureOut);
3352 }
3353 
ensureVertexDataManagerInitialized(const gl::Context * context)3354 angle::Result Renderer9::ensureVertexDataManagerInitialized(const gl::Context *context)
3355 {
3356     if (!mVertexDataManager)
3357     {
3358         mVertexDataManager = new VertexDataManager(this);
3359         ANGLE_TRY(mVertexDataManager->initialize(context));
3360     }
3361 
3362     return angle::Result::Continue;
3363 }
3364 
getVendorString() const3365 std::string Renderer9::getVendorString() const
3366 {
3367     return GetVendorString(getVendorId());
3368 }
3369 
getVersionString(bool includeFullVersion) const3370 std::string Renderer9::getVersionString(bool includeFullVersion) const
3371 {
3372     std::ostringstream versionString;
3373     std::string driverName(mAdapterIdentifier.Driver);
3374     if (!driverName.empty())
3375     {
3376         versionString << mAdapterIdentifier.Driver;
3377     }
3378     else
3379     {
3380         versionString << "D3D9";
3381     }
3382 
3383     if (includeFullVersion)
3384     {
3385         versionString << " -";
3386         versionString << GetDriverVersionString(mAdapterIdentifier.DriverVersion);
3387     }
3388 
3389     return versionString.str();
3390 }
3391 
CreateRenderer9(egl::Display * display)3392 RendererD3D *CreateRenderer9(egl::Display *display)
3393 {
3394     return new Renderer9(display);
3395 }
3396 
3397 }  // namespace rx
3398