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