1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22
23 #include "../../Precompiled.h"
24
25 #include "../../Core/Context.h"
26 #include "../../Core/ProcessUtils.h"
27 #include "../../Core/Profiler.h"
28 #include "../../Graphics/ConstantBuffer.h"
29 #include "../../Graphics/Geometry.h"
30 #include "../../Graphics/Graphics.h"
31 #include "../../Graphics/GraphicsEvents.h"
32 #include "../../Graphics/GraphicsImpl.h"
33 #include "../../Graphics/IndexBuffer.h"
34 #include "../../Graphics/Renderer.h"
35 #include "../../Graphics/Shader.h"
36 #include "../../Graphics/ShaderPrecache.h"
37 #include "../../Graphics/ShaderProgram.h"
38 #include "../../Graphics/Texture2D.h"
39 #include "../../Graphics/TextureCube.h"
40 #include "../../Graphics/VertexBuffer.h"
41 #include "../../IO/File.h"
42 #include "../../IO/Log.h"
43 #include "../../Resource/ResourceCache.h"
44
45 #include <SDL/SDL.h>
46 #include <SDL/SDL_syswm.h>
47
48 #include "../../DebugNew.h"
49
50 #ifdef _MSC_VER
51 #pragma warning(disable:4355)
52 #endif
53
54 // Prefer the high-performance GPU on switchable GPU systems
55 extern "C"
56 {
57 __declspec(dllexport) DWORD NvOptimusEnablement = 1;
58 __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
59 }
60
61 namespace Urho3D
62 {
63
64 static const D3D11_COMPARISON_FUNC d3dCmpFunc[] =
65 {
66 D3D11_COMPARISON_ALWAYS,
67 D3D11_COMPARISON_EQUAL,
68 D3D11_COMPARISON_NOT_EQUAL,
69 D3D11_COMPARISON_LESS,
70 D3D11_COMPARISON_LESS_EQUAL,
71 D3D11_COMPARISON_GREATER,
72 D3D11_COMPARISON_GREATER_EQUAL
73 };
74
75 static const DWORD d3dBlendEnable[] =
76 {
77 FALSE,
78 TRUE,
79 TRUE,
80 TRUE,
81 TRUE,
82 TRUE,
83 TRUE,
84 TRUE
85 };
86
87 static const D3D11_BLEND d3dSrcBlend[] =
88 {
89 D3D11_BLEND_ONE,
90 D3D11_BLEND_ONE,
91 D3D11_BLEND_DEST_COLOR,
92 D3D11_BLEND_SRC_ALPHA,
93 D3D11_BLEND_SRC_ALPHA,
94 D3D11_BLEND_ONE,
95 D3D11_BLEND_INV_DEST_ALPHA,
96 D3D11_BLEND_ONE,
97 D3D11_BLEND_SRC_ALPHA,
98 };
99
100 static const D3D11_BLEND d3dDestBlend[] =
101 {
102 D3D11_BLEND_ZERO,
103 D3D11_BLEND_ONE,
104 D3D11_BLEND_ZERO,
105 D3D11_BLEND_INV_SRC_ALPHA,
106 D3D11_BLEND_ONE,
107 D3D11_BLEND_INV_SRC_ALPHA,
108 D3D11_BLEND_DEST_ALPHA,
109 D3D11_BLEND_ONE,
110 D3D11_BLEND_ONE
111 };
112
113 static const D3D11_BLEND_OP d3dBlendOp[] =
114 {
115 D3D11_BLEND_OP_ADD,
116 D3D11_BLEND_OP_ADD,
117 D3D11_BLEND_OP_ADD,
118 D3D11_BLEND_OP_ADD,
119 D3D11_BLEND_OP_ADD,
120 D3D11_BLEND_OP_ADD,
121 D3D11_BLEND_OP_ADD,
122 D3D11_BLEND_OP_REV_SUBTRACT,
123 D3D11_BLEND_OP_REV_SUBTRACT
124 };
125
126 static const D3D11_STENCIL_OP d3dStencilOp[] =
127 {
128 D3D11_STENCIL_OP_KEEP,
129 D3D11_STENCIL_OP_ZERO,
130 D3D11_STENCIL_OP_REPLACE,
131 D3D11_STENCIL_OP_INCR,
132 D3D11_STENCIL_OP_DECR
133 };
134
135 static const D3D11_CULL_MODE d3dCullMode[] =
136 {
137 D3D11_CULL_NONE,
138 D3D11_CULL_BACK,
139 D3D11_CULL_FRONT
140 };
141
142 static const D3D11_FILL_MODE d3dFillMode[] =
143 {
144 D3D11_FILL_SOLID,
145 D3D11_FILL_WIREFRAME,
146 D3D11_FILL_WIREFRAME // Point fill mode not supported
147 };
148
GetD3DPrimitiveType(unsigned elementCount,PrimitiveType type,unsigned & primitiveCount,D3D_PRIMITIVE_TOPOLOGY & d3dPrimitiveType)149 static void GetD3DPrimitiveType(unsigned elementCount, PrimitiveType type, unsigned& primitiveCount,
150 D3D_PRIMITIVE_TOPOLOGY& d3dPrimitiveType)
151 {
152 switch (type)
153 {
154 case TRIANGLE_LIST:
155 primitiveCount = elementCount / 3;
156 d3dPrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
157 break;
158
159 case LINE_LIST:
160 primitiveCount = elementCount / 2;
161 d3dPrimitiveType = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
162 break;
163
164 case POINT_LIST:
165 primitiveCount = elementCount;
166 d3dPrimitiveType = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
167 break;
168
169 case TRIANGLE_STRIP:
170 primitiveCount = elementCount - 2;
171 d3dPrimitiveType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
172 break;
173
174 case LINE_STRIP:
175 primitiveCount = elementCount - 1;
176 d3dPrimitiveType = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
177 break;
178
179 case TRIANGLE_FAN:
180 // Triangle fan is not supported on D3D11
181 primitiveCount = 0;
182 d3dPrimitiveType = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
183 break;
184 }
185 }
186
GetWindowHandle(SDL_Window * window)187 static HWND GetWindowHandle(SDL_Window* window)
188 {
189 SDL_SysWMinfo sysInfo;
190
191 SDL_VERSION(&sysInfo.version);
192 SDL_GetWindowWMInfo(window, &sysInfo);
193 return sysInfo.info.win.window;
194 }
195
196 const Vector2 Graphics::pixelUVOffset(0.0f, 0.0f);
197 bool Graphics::gl3Support = false;
198
Graphics(Context * context)199 Graphics::Graphics(Context* context) :
200 Object(context),
201 impl_(new GraphicsImpl()),
202 window_(0),
203 externalWindow_(0),
204 width_(0),
205 height_(0),
206 position_(SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED),
207 multiSample_(1),
208 fullscreen_(false),
209 borderless_(false),
210 resizable_(false),
211 highDPI_(false),
212 vsync_(false),
213 monitor_(0),
214 refreshRate_(0),
215 tripleBuffer_(false),
216 flushGPU_(false),
217 forceGL2_(false),
218 sRGB_(false),
219 anisotropySupport_(false),
220 dxtTextureSupport_(false),
221 etcTextureSupport_(false),
222 pvrtcTextureSupport_(false),
223 hardwareShadowSupport_(false),
224 lightPrepassSupport_(false),
225 deferredSupport_(false),
226 instancingSupport_(false),
227 sRGBSupport_(false),
228 sRGBWriteSupport_(false),
229 numPrimitives_(0),
230 numBatches_(0),
231 maxScratchBufferRequest_(0),
232 defaultTextureFilterMode_(FILTER_TRILINEAR),
233 defaultTextureAnisotropy_(4),
234 shaderPath_("Shaders/HLSL/"),
235 shaderExtension_(".hlsl"),
236 orientations_("LandscapeLeft LandscapeRight"),
237 apiName_("D3D11")
238 {
239 SetTextureUnitMappings();
240 ResetCachedState();
241
242 context_->RequireSDL(SDL_INIT_VIDEO);
243
244 // Register Graphics library object factories
245 RegisterGraphicsLibrary(context_);
246 }
247
~Graphics()248 Graphics::~Graphics()
249 {
250 {
251 MutexLock lock(gpuObjectMutex_);
252
253 // Release all GPU objects that still exist
254 for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
255 (*i)->Release();
256 gpuObjects_.Clear();
257 }
258
259 impl_->vertexDeclarations_.Clear();
260 impl_->allConstantBuffers_.Clear();
261
262 for (HashMap<unsigned, ID3D11BlendState*>::Iterator i = impl_->blendStates_.Begin(); i != impl_->blendStates_.End(); ++i)
263 {
264 URHO3D_SAFE_RELEASE(i->second_);
265 }
266 impl_->blendStates_.Clear();
267
268 for (HashMap<unsigned, ID3D11DepthStencilState*>::Iterator i = impl_->depthStates_.Begin(); i != impl_->depthStates_.End(); ++i)
269 {
270 URHO3D_SAFE_RELEASE(i->second_);
271 }
272 impl_->depthStates_.Clear();
273
274 for (HashMap<unsigned, ID3D11RasterizerState*>::Iterator i = impl_->rasterizerStates_.Begin();
275 i != impl_->rasterizerStates_.End(); ++i)
276 {
277 URHO3D_SAFE_RELEASE(i->second_);
278 }
279 impl_->rasterizerStates_.Clear();
280
281 URHO3D_SAFE_RELEASE(impl_->defaultRenderTargetView_);
282 URHO3D_SAFE_RELEASE(impl_->defaultDepthStencilView_);
283 URHO3D_SAFE_RELEASE(impl_->defaultDepthTexture_);
284 URHO3D_SAFE_RELEASE(impl_->resolveTexture_);
285 URHO3D_SAFE_RELEASE(impl_->swapChain_);
286 URHO3D_SAFE_RELEASE(impl_->deviceContext_);
287 URHO3D_SAFE_RELEASE(impl_->device_);
288
289 if (window_)
290 {
291 SDL_ShowCursor(SDL_TRUE);
292 SDL_DestroyWindow(window_);
293 window_ = 0;
294 }
295
296 delete impl_;
297 impl_ = 0;
298
299 context_->ReleaseSDL();
300 }
301
SetMode(int width,int height,bool fullscreen,bool borderless,bool resizable,bool highDPI,bool vsync,bool tripleBuffer,int multiSample,int monitor,int refreshRate)302 bool Graphics::SetMode(int width, int height, bool fullscreen, bool borderless, bool resizable, bool highDPI, bool vsync, bool tripleBuffer,
303 int multiSample, int monitor, int refreshRate)
304 {
305 URHO3D_PROFILE(SetScreenMode);
306
307 highDPI = false; // SDL does not support High DPI mode on Windows platform yet, so always disable it for now
308
309 bool maximize = false;
310
311 // Make sure monitor index is not bigger than the currently detected monitors
312 int monitors = SDL_GetNumVideoDisplays();
313 if (monitor >= monitors || monitor < 0)
314 monitor = 0; // this monitor is not present, use first monitor
315
316 // Find out the full screen mode display format (match desktop color depth)
317 SDL_DisplayMode mode;
318 SDL_GetDesktopDisplayMode(monitor, &mode);
319 DXGI_FORMAT fullscreenFormat = SDL_BITSPERPIXEL(mode.format) == 16 ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM;
320
321 // If zero dimensions in windowed mode, set windowed mode to maximize and set a predefined default restored window size. If zero in fullscreen, use desktop mode
322 if (!width || !height)
323 {
324 if (fullscreen || borderless)
325 {
326 width = mode.w;
327 height = mode.h;
328 }
329 else
330 {
331 maximize = resizable;
332 width = 1024;
333 height = 768;
334 }
335 }
336
337 // Fullscreen or Borderless can not be resizable
338 if (fullscreen || borderless)
339 resizable = false;
340
341 // Borderless cannot be fullscreen, they are mutually exclusive
342 if (borderless)
343 fullscreen = false;
344
345 // If nothing changes, do not reset the device
346 if (width == width_ && height == height_ && fullscreen == fullscreen_ && borderless == borderless_ && resizable == resizable_ &&
347 vsync == vsync_ && tripleBuffer == tripleBuffer_ && multiSample == multiSample_)
348 return true;
349
350 SDL_SetHint(SDL_HINT_ORIENTATIONS, orientations_.CString());
351
352 if (!window_)
353 {
354 if (!OpenWindow(width, height, resizable, borderless))
355 return false;
356 }
357
358 // Check fullscreen mode validity. Use a closest match if not found
359 if (fullscreen)
360 {
361 PODVector<IntVector3> resolutions = GetResolutions(monitor);
362 if (resolutions.Size())
363 {
364 unsigned best = 0;
365 unsigned bestError = M_MAX_UNSIGNED;
366
367 for (unsigned i = 0; i < resolutions.Size(); ++i)
368 {
369 unsigned error = (unsigned)(Abs(resolutions[i].x_ - width) + Abs(resolutions[i].y_ - height));
370 if (error < bestError)
371 {
372 best = i;
373 bestError = error;
374 }
375 }
376
377 width = resolutions[best].x_;
378 height = resolutions[best].y_;
379 refreshRate = resolutions[best].z_;
380 }
381 }
382
383 AdjustWindow(width, height, fullscreen, borderless, monitor);
384 monitor_ = monitor;
385 refreshRate_ = refreshRate;
386
387 if (maximize)
388 {
389 Maximize();
390 SDL_GetWindowSize(window_, &width, &height);
391 }
392
393 if (!impl_->device_ || multiSample_ != multiSample)
394 CreateDevice(width, height, multiSample);
395 UpdateSwapChain(width, height);
396
397 fullscreen_ = fullscreen;
398 borderless_ = borderless;
399 resizable_ = resizable;
400 highDPI_ = highDPI;
401 vsync_ = vsync;
402 tripleBuffer_ = tripleBuffer;
403
404 // Clear the initial window contents to black
405 Clear(CLEAR_COLOR);
406 impl_->swapChain_->Present(0, 0);
407
408 #ifdef URHO3D_LOGGING
409 String msg;
410 msg.AppendWithFormat("Set screen mode %dx%d %s monitor %d", width_, height_, (fullscreen_ ? "fullscreen" : "windowed"), monitor_);
411 if (borderless_)
412 msg.Append(" borderless");
413 if (resizable_)
414 msg.Append(" resizable");
415 if (multiSample > 1)
416 msg.AppendWithFormat(" multisample %d", multiSample);
417 URHO3D_LOGINFO(msg);
418 #endif
419
420 using namespace ScreenMode;
421
422 VariantMap& eventData = GetEventDataMap();
423 eventData[P_WIDTH] = width_;
424 eventData[P_HEIGHT] = height_;
425 eventData[P_FULLSCREEN] = fullscreen_;
426 eventData[P_BORDERLESS] = borderless_;
427 eventData[P_RESIZABLE] = resizable_;
428 eventData[P_HIGHDPI] = highDPI_;
429 eventData[P_MONITOR] = monitor_;
430 eventData[P_REFRESHRATE] = refreshRate_;
431 SendEvent(E_SCREENMODE, eventData);
432
433 return true;
434 }
435
SetMode(int width,int height)436 bool Graphics::SetMode(int width, int height)
437 {
438 return SetMode(width, height, fullscreen_, borderless_, resizable_, highDPI_, vsync_, tripleBuffer_, multiSample_, monitor_, refreshRate_);
439 }
440
SetSRGB(bool enable)441 void Graphics::SetSRGB(bool enable)
442 {
443 bool newEnable = enable && sRGBWriteSupport_;
444 if (newEnable != sRGB_)
445 {
446 sRGB_ = newEnable;
447 if (impl_->swapChain_)
448 {
449 // Recreate swap chain for the new backbuffer format
450 CreateDevice(width_, height_, multiSample_);
451 UpdateSwapChain(width_, height_);
452 }
453 }
454 }
455
SetDither(bool enable)456 void Graphics::SetDither(bool enable)
457 {
458 // No effect on Direct3D11
459 }
460
SetFlushGPU(bool enable)461 void Graphics::SetFlushGPU(bool enable)
462 {
463 flushGPU_ = enable;
464
465 if (impl_->device_)
466 {
467 IDXGIDevice1* dxgiDevice;
468 impl_->device_->QueryInterface(IID_IDXGIDevice1, (void**)&dxgiDevice);
469 if (dxgiDevice)
470 {
471 dxgiDevice->SetMaximumFrameLatency(enable ? 1 : 3);
472 dxgiDevice->Release();
473 }
474 }
475 }
476
SetForceGL2(bool enable)477 void Graphics::SetForceGL2(bool enable)
478 {
479 // No effect on Direct3D11
480 }
481
Close()482 void Graphics::Close()
483 {
484 if (window_)
485 {
486 SDL_ShowCursor(SDL_TRUE);
487 SDL_DestroyWindow(window_);
488 window_ = 0;
489 }
490 }
491
TakeScreenShot(Image & destImage)492 bool Graphics::TakeScreenShot(Image& destImage)
493 {
494 URHO3D_PROFILE(TakeScreenShot);
495
496 if (!impl_->device_)
497 return false;
498
499 D3D11_TEXTURE2D_DESC textureDesc;
500 memset(&textureDesc, 0, sizeof textureDesc);
501 textureDesc.Width = (UINT)width_;
502 textureDesc.Height = (UINT)height_;
503 textureDesc.MipLevels = 1;
504 textureDesc.ArraySize = 1;
505 textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
506 textureDesc.SampleDesc.Count = 1;
507 textureDesc.SampleDesc.Quality = 0;
508 textureDesc.Usage = D3D11_USAGE_STAGING;
509 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
510
511 ID3D11Texture2D* stagingTexture = 0;
512 HRESULT hr = impl_->device_->CreateTexture2D(&textureDesc, 0, &stagingTexture);
513 if (FAILED(hr))
514 {
515 URHO3D_SAFE_RELEASE(stagingTexture);
516 URHO3D_LOGD3DERROR("Could not create staging texture for screenshot", hr);
517 return false;
518 }
519
520 ID3D11Resource* source = 0;
521 impl_->defaultRenderTargetView_->GetResource(&source);
522
523 if (multiSample_ > 1)
524 {
525 // If backbuffer is multisampled, need another DEFAULT usage texture to resolve the data to first
526 CreateResolveTexture();
527
528 if (!impl_->resolveTexture_)
529 {
530 stagingTexture->Release();
531 source->Release();
532 return false;
533 }
534
535 impl_->deviceContext_->ResolveSubresource(impl_->resolveTexture_, 0, source, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
536 impl_->deviceContext_->CopyResource(stagingTexture, impl_->resolveTexture_);
537 }
538 else
539 impl_->deviceContext_->CopyResource(stagingTexture, source);
540
541 source->Release();
542
543 D3D11_MAPPED_SUBRESOURCE mappedData;
544 mappedData.pData = 0;
545 hr = impl_->deviceContext_->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedData);
546 if (FAILED(hr) || !mappedData.pData)
547 {
548 URHO3D_LOGD3DERROR("Could not map staging texture for screenshot", hr);
549 stagingTexture->Release();
550 return false;
551 }
552
553 destImage.SetSize(width_, height_, 3);
554 unsigned char* destData = destImage.GetData();
555 for (int y = 0; y < height_; ++y)
556 {
557 unsigned char* src = (unsigned char*)mappedData.pData + y * mappedData.RowPitch;
558 for (int x = 0; x < width_; ++x)
559 {
560 *destData++ = *src++;
561 *destData++ = *src++;
562 *destData++ = *src++;
563 ++src;
564 }
565 }
566
567 impl_->deviceContext_->Unmap(stagingTexture, 0);
568 stagingTexture->Release();
569 return true;
570 }
571
BeginFrame()572 bool Graphics::BeginFrame()
573 {
574 if (!IsInitialized())
575 return false;
576
577 // If using an external window, check it for size changes, and reset screen mode if necessary
578 if (externalWindow_)
579 {
580 int width, height;
581
582 SDL_GetWindowSize(window_, &width, &height);
583 if (width != width_ || height != height_)
584 SetMode(width, height);
585 }
586 else
587 {
588 // To prevent a loop of endless device loss and flicker, do not attempt to render when in fullscreen
589 // and the window is minimized
590 if (fullscreen_ && (SDL_GetWindowFlags(window_) & SDL_WINDOW_MINIMIZED))
591 return false;
592 }
593
594 // Set default rendertarget and depth buffer
595 ResetRenderTargets();
596
597 // Cleanup textures from previous frame
598 for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
599 SetTexture(i, 0);
600
601 numPrimitives_ = 0;
602 numBatches_ = 0;
603
604 SendEvent(E_BEGINRENDERING);
605 return true;
606 }
607
EndFrame()608 void Graphics::EndFrame()
609 {
610 if (!IsInitialized())
611 return;
612
613 {
614 URHO3D_PROFILE(Present);
615
616 SendEvent(E_ENDRENDERING);
617 impl_->swapChain_->Present(vsync_ ? 1 : 0, 0);
618 }
619
620 // Clean up too large scratch buffers
621 CleanupScratchBuffers();
622 }
623
Clear(unsigned flags,const Color & color,float depth,unsigned stencil)624 void Graphics::Clear(unsigned flags, const Color& color, float depth, unsigned stencil)
625 {
626 IntVector2 rtSize = GetRenderTargetDimensions();
627
628 bool oldColorWrite = colorWrite_;
629 bool oldDepthWrite = depthWrite_;
630
631 // D3D11 clear always clears the whole target regardless of viewport or scissor test settings
632 // Emulate partial clear by rendering a quad
633 if (!viewport_.left_ && !viewport_.top_ && viewport_.right_ == rtSize.x_ && viewport_.bottom_ == rtSize.y_)
634 {
635 // Make sure we use the read-write version of the depth stencil
636 SetDepthWrite(true);
637 PrepareDraw();
638
639 if ((flags & CLEAR_COLOR) && impl_->renderTargetViews_[0])
640 impl_->deviceContext_->ClearRenderTargetView(impl_->renderTargetViews_[0], color.Data());
641
642 if ((flags & (CLEAR_DEPTH | CLEAR_STENCIL)) && impl_->depthStencilView_)
643 {
644 unsigned depthClearFlags = 0;
645 if (flags & CLEAR_DEPTH)
646 depthClearFlags |= D3D11_CLEAR_DEPTH;
647 if (flags & CLEAR_STENCIL)
648 depthClearFlags |= D3D11_CLEAR_STENCIL;
649 impl_->deviceContext_->ClearDepthStencilView(impl_->depthStencilView_, depthClearFlags, depth, (UINT8)stencil);
650 }
651 }
652 else
653 {
654 Renderer* renderer = GetSubsystem<Renderer>();
655 if (!renderer)
656 return;
657
658 Geometry* geometry = renderer->GetQuadGeometry();
659
660 Matrix3x4 model = Matrix3x4::IDENTITY;
661 Matrix4 projection = Matrix4::IDENTITY;
662 model.m23_ = Clamp(depth, 0.0f, 1.0f);
663
664 SetBlendMode(BLEND_REPLACE);
665 SetColorWrite((flags & CLEAR_COLOR) != 0);
666 SetCullMode(CULL_NONE);
667 SetDepthTest(CMP_ALWAYS);
668 SetDepthWrite((flags & CLEAR_DEPTH) != 0);
669 SetFillMode(FILL_SOLID);
670 SetScissorTest(false);
671 SetStencilTest((flags & CLEAR_STENCIL) != 0, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, stencil);
672 SetShaders(GetShader(VS, "ClearFramebuffer"), GetShader(PS, "ClearFramebuffer"));
673 SetShaderParameter(VSP_MODEL, model);
674 SetShaderParameter(VSP_VIEWPROJ, projection);
675 SetShaderParameter(PSP_MATDIFFCOLOR, color);
676
677 geometry->Draw(this);
678
679 SetStencilTest(false);
680 ClearParameterSources();
681 }
682
683 // Restore color & depth write state now
684 SetColorWrite(oldColorWrite);
685 SetDepthWrite(oldDepthWrite);
686 }
687
ResolveToTexture(Texture2D * destination,const IntRect & viewport)688 bool Graphics::ResolveToTexture(Texture2D* destination, const IntRect& viewport)
689 {
690 if (!destination || !destination->GetRenderSurface())
691 return false;
692
693 URHO3D_PROFILE(ResolveToTexture);
694
695 IntRect vpCopy = viewport;
696 if (vpCopy.right_ <= vpCopy.left_)
697 vpCopy.right_ = vpCopy.left_ + 1;
698 if (vpCopy.bottom_ <= vpCopy.top_)
699 vpCopy.bottom_ = vpCopy.top_ + 1;
700
701 D3D11_BOX srcBox;
702 srcBox.left = Clamp(vpCopy.left_, 0, width_);
703 srcBox.top = Clamp(vpCopy.top_, 0, height_);
704 srcBox.right = Clamp(vpCopy.right_, 0, width_);
705 srcBox.bottom = Clamp(vpCopy.bottom_, 0, height_);
706 srcBox.front = 0;
707 srcBox.back = 1;
708
709 ID3D11Resource* source = 0;
710 bool resolve = multiSample_ > 1;
711 impl_->defaultRenderTargetView_->GetResource(&source);
712
713 if (!resolve)
714 {
715 if (!srcBox.left && !srcBox.top && srcBox.right == width_ && srcBox.bottom == height_)
716 impl_->deviceContext_->CopyResource((ID3D11Resource*)destination->GetGPUObject(), source);
717 else
718 impl_->deviceContext_->CopySubresourceRegion((ID3D11Resource*)destination->GetGPUObject(), 0, 0, 0, 0, source, 0, &srcBox);
719 }
720 else
721 {
722 if (!srcBox.left && !srcBox.top && srcBox.right == width_ && srcBox.bottom == height_)
723 {
724 impl_->deviceContext_->ResolveSubresource((ID3D11Resource*)destination->GetGPUObject(), 0, source, 0, (DXGI_FORMAT)
725 destination->GetFormat());
726 }
727 else
728 {
729 CreateResolveTexture();
730
731 if (impl_->resolveTexture_)
732 {
733 impl_->deviceContext_->ResolveSubresource(impl_->resolveTexture_, 0, source, 0, DXGI_FORMAT_R8G8B8A8_UNORM);
734 impl_->deviceContext_->CopySubresourceRegion((ID3D11Resource*)destination->GetGPUObject(), 0, 0, 0, 0, impl_->resolveTexture_, 0, &srcBox);
735 }
736 }
737 }
738
739 source->Release();
740
741 return true;
742 }
743
ResolveToTexture(Texture2D * texture)744 bool Graphics::ResolveToTexture(Texture2D* texture)
745 {
746 if (!texture)
747 return false;
748 RenderSurface* surface = texture->GetRenderSurface();
749 if (!surface)
750 return false;
751
752 texture->SetResolveDirty(false);
753 surface->SetResolveDirty(false);
754 ID3D11Resource* source = (ID3D11Resource*)texture->GetGPUObject();
755 ID3D11Resource* dest = (ID3D11Resource*)texture->GetResolveTexture();
756 if (!source || !dest)
757 return false;
758
759 impl_->deviceContext_->ResolveSubresource(dest, 0, source, 0, (DXGI_FORMAT)texture->GetFormat());
760 return true;
761 }
762
ResolveToTexture(TextureCube * texture)763 bool Graphics::ResolveToTexture(TextureCube* texture)
764 {
765 if (!texture)
766 return false;
767
768 texture->SetResolveDirty(false);
769 ID3D11Resource* source = (ID3D11Resource*)texture->GetGPUObject();
770 ID3D11Resource* dest = (ID3D11Resource*)texture->GetResolveTexture();
771 if (!source || !dest)
772 return false;
773
774 for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
775 {
776 // Resolve only the surface(s) that were actually rendered to
777 RenderSurface* surface = texture->GetRenderSurface((CubeMapFace)i);
778 if (!surface->IsResolveDirty())
779 continue;
780
781 surface->SetResolveDirty(false);
782 unsigned subResource = D3D11CalcSubresource(0, i, texture->GetLevels());
783 impl_->deviceContext_->ResolveSubresource(dest, subResource, source, subResource, (DXGI_FORMAT)texture->GetFormat());
784 }
785
786 return true;
787 }
788
789
Draw(PrimitiveType type,unsigned vertexStart,unsigned vertexCount)790 void Graphics::Draw(PrimitiveType type, unsigned vertexStart, unsigned vertexCount)
791 {
792 if (!vertexCount || !impl_->shaderProgram_)
793 return;
794
795 PrepareDraw();
796
797 unsigned primitiveCount;
798 D3D_PRIMITIVE_TOPOLOGY d3dPrimitiveType;
799
800 if (fillMode_ == FILL_POINT)
801 type = POINT_LIST;
802
803 GetD3DPrimitiveType(vertexCount, type, primitiveCount, d3dPrimitiveType);
804 if (d3dPrimitiveType != primitiveType_)
805 {
806 impl_->deviceContext_->IASetPrimitiveTopology(d3dPrimitiveType);
807 primitiveType_ = d3dPrimitiveType;
808 }
809 impl_->deviceContext_->Draw(vertexCount, vertexStart);
810
811 numPrimitives_ += primitiveCount;
812 ++numBatches_;
813 }
814
Draw(PrimitiveType type,unsigned indexStart,unsigned indexCount,unsigned minVertex,unsigned vertexCount)815 void Graphics::Draw(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount)
816 {
817 if (!vertexCount || !impl_->shaderProgram_)
818 return;
819
820 PrepareDraw();
821
822 unsigned primitiveCount;
823 D3D_PRIMITIVE_TOPOLOGY d3dPrimitiveType;
824
825 if (fillMode_ == FILL_POINT)
826 type = POINT_LIST;
827
828 GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
829 if (d3dPrimitiveType != primitiveType_)
830 {
831 impl_->deviceContext_->IASetPrimitiveTopology(d3dPrimitiveType);
832 primitiveType_ = d3dPrimitiveType;
833 }
834 impl_->deviceContext_->DrawIndexed(indexCount, indexStart, 0);
835
836 numPrimitives_ += primitiveCount;
837 ++numBatches_;
838 }
839
Draw(PrimitiveType type,unsigned indexStart,unsigned indexCount,unsigned baseVertexIndex,unsigned minVertex,unsigned vertexCount)840 void Graphics::Draw(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex, unsigned vertexCount)
841 {
842 if (!vertexCount || !impl_->shaderProgram_)
843 return;
844
845 PrepareDraw();
846
847 unsigned primitiveCount;
848 D3D_PRIMITIVE_TOPOLOGY d3dPrimitiveType;
849
850 if (fillMode_ == FILL_POINT)
851 type = POINT_LIST;
852
853 GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
854 if (d3dPrimitiveType != primitiveType_)
855 {
856 impl_->deviceContext_->IASetPrimitiveTopology(d3dPrimitiveType);
857 primitiveType_ = d3dPrimitiveType;
858 }
859 impl_->deviceContext_->DrawIndexed(indexCount, indexStart, baseVertexIndex);
860
861 numPrimitives_ += primitiveCount;
862 ++numBatches_;
863 }
864
DrawInstanced(PrimitiveType type,unsigned indexStart,unsigned indexCount,unsigned minVertex,unsigned vertexCount,unsigned instanceCount)865 void Graphics::DrawInstanced(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned minVertex, unsigned vertexCount,
866 unsigned instanceCount)
867 {
868 if (!indexCount || !instanceCount || !impl_->shaderProgram_)
869 return;
870
871 PrepareDraw();
872
873 unsigned primitiveCount;
874 D3D_PRIMITIVE_TOPOLOGY d3dPrimitiveType;
875
876 if (fillMode_ == FILL_POINT)
877 type = POINT_LIST;
878
879 GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
880 if (d3dPrimitiveType != primitiveType_)
881 {
882 impl_->deviceContext_->IASetPrimitiveTopology(d3dPrimitiveType);
883 primitiveType_ = d3dPrimitiveType;
884 }
885 impl_->deviceContext_->DrawIndexedInstanced(indexCount, instanceCount, indexStart, 0, 0);
886
887 numPrimitives_ += instanceCount * primitiveCount;
888 ++numBatches_;
889 }
890
DrawInstanced(PrimitiveType type,unsigned indexStart,unsigned indexCount,unsigned baseVertexIndex,unsigned minVertex,unsigned vertexCount,unsigned instanceCount)891 void Graphics::DrawInstanced(PrimitiveType type, unsigned indexStart, unsigned indexCount, unsigned baseVertexIndex, unsigned minVertex, unsigned vertexCount,
892 unsigned instanceCount)
893 {
894 if (!indexCount || !instanceCount || !impl_->shaderProgram_)
895 return;
896
897 PrepareDraw();
898
899 unsigned primitiveCount;
900 D3D_PRIMITIVE_TOPOLOGY d3dPrimitiveType;
901
902 if (fillMode_ == FILL_POINT)
903 type = POINT_LIST;
904
905 GetD3DPrimitiveType(indexCount, type, primitiveCount, d3dPrimitiveType);
906 if (d3dPrimitiveType != primitiveType_)
907 {
908 impl_->deviceContext_->IASetPrimitiveTopology(d3dPrimitiveType);
909 primitiveType_ = d3dPrimitiveType;
910 }
911 impl_->deviceContext_->DrawIndexedInstanced(indexCount, instanceCount, indexStart, baseVertexIndex, 0);
912
913 numPrimitives_ += instanceCount * primitiveCount;
914 ++numBatches_;
915 }
916
SetVertexBuffer(VertexBuffer * buffer)917 void Graphics::SetVertexBuffer(VertexBuffer* buffer)
918 {
919 // Note: this is not multi-instance safe
920 static PODVector<VertexBuffer*> vertexBuffers(1);
921 vertexBuffers[0] = buffer;
922 SetVertexBuffers(vertexBuffers);
923 }
924
SetVertexBuffers(const PODVector<VertexBuffer * > & buffers,unsigned instanceOffset)925 bool Graphics::SetVertexBuffers(const PODVector<VertexBuffer*>& buffers, unsigned instanceOffset)
926 {
927 if (buffers.Size() > MAX_VERTEX_STREAMS)
928 {
929 URHO3D_LOGERROR("Too many vertex buffers");
930 return false;
931 }
932
933 for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
934 {
935 VertexBuffer* buffer = 0;
936 bool changed = false;
937
938 buffer = i < buffers.Size() ? buffers[i] : 0;
939 if (buffer)
940 {
941 const PODVector<VertexElement>& elements = buffer->GetElements();
942 // Check if buffer has per-instance data
943 bool hasInstanceData = elements.Size() && elements[0].perInstance_;
944 unsigned offset = hasInstanceData ? instanceOffset * buffer->GetVertexSize() : 0;
945
946 if (buffer != vertexBuffers_[i] || offset != impl_->vertexOffsets_[i])
947 {
948 vertexBuffers_[i] = buffer;
949 impl_->vertexBuffers_[i] = (ID3D11Buffer*)buffer->GetGPUObject();
950 impl_->vertexSizes_[i] = buffer->GetVertexSize();
951 impl_->vertexOffsets_[i] = offset;
952 changed = true;
953 }
954 }
955 else if (vertexBuffers_[i])
956 {
957 vertexBuffers_[i] = 0;
958 impl_->vertexBuffers_[i] = 0;
959 impl_->vertexSizes_[i] = 0;
960 impl_->vertexOffsets_[i] = 0;
961 changed = true;
962 }
963
964 if (changed)
965 {
966 impl_->vertexDeclarationDirty_ = true;
967
968 if (impl_->firstDirtyVB_ == M_MAX_UNSIGNED)
969 impl_->firstDirtyVB_ = impl_->lastDirtyVB_ = i;
970 else
971 {
972 if (i < impl_->firstDirtyVB_)
973 impl_->firstDirtyVB_ = i;
974 if (i > impl_->lastDirtyVB_)
975 impl_->lastDirtyVB_ = i;
976 }
977 }
978 }
979
980 return true;
981 }
982
SetVertexBuffers(const Vector<SharedPtr<VertexBuffer>> & buffers,unsigned instanceOffset)983 bool Graphics::SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers, unsigned instanceOffset)
984 {
985 return SetVertexBuffers(reinterpret_cast<const PODVector<VertexBuffer*>&>(buffers), instanceOffset);
986 }
987
SetIndexBuffer(IndexBuffer * buffer)988 void Graphics::SetIndexBuffer(IndexBuffer* buffer)
989 {
990 if (buffer != indexBuffer_)
991 {
992 if (buffer)
993 impl_->deviceContext_->IASetIndexBuffer((ID3D11Buffer*)buffer->GetGPUObject(),
994 buffer->GetIndexSize() == sizeof(unsigned short) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
995 else
996 impl_->deviceContext_->IASetIndexBuffer(0, DXGI_FORMAT_UNKNOWN, 0);
997
998 indexBuffer_ = buffer;
999 }
1000 }
1001
SetShaders(ShaderVariation * vs,ShaderVariation * ps)1002 void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
1003 {
1004 // Switch to the clip plane variations if necessary
1005 if (useClipPlane_)
1006 {
1007 if (vs)
1008 vs = vs->GetOwner()->GetVariation(VS, vs->GetDefinesClipPlane());
1009 if (ps)
1010 ps = ps->GetOwner()->GetVariation(PS, ps->GetDefinesClipPlane());
1011 }
1012
1013 if (vs == vertexShader_ && ps == pixelShader_)
1014 return;
1015
1016 if (vs != vertexShader_)
1017 {
1018 // Create the shader now if not yet created. If already attempted, do not retry
1019 if (vs && !vs->GetGPUObject())
1020 {
1021 if (vs->GetCompilerOutput().Empty())
1022 {
1023 URHO3D_PROFILE(CompileVertexShader);
1024
1025 bool success = vs->Create();
1026 if (!success)
1027 {
1028 URHO3D_LOGERROR("Failed to compile vertex shader " + vs->GetFullName() + ":\n" + vs->GetCompilerOutput());
1029 vs = 0;
1030 }
1031 }
1032 else
1033 vs = 0;
1034 }
1035
1036 impl_->deviceContext_->VSSetShader((ID3D11VertexShader*)(vs ? vs->GetGPUObject() : 0), 0, 0);
1037 vertexShader_ = vs;
1038 impl_->vertexDeclarationDirty_ = true;
1039 }
1040
1041 if (ps != pixelShader_)
1042 {
1043 if (ps && !ps->GetGPUObject())
1044 {
1045 if (ps->GetCompilerOutput().Empty())
1046 {
1047 URHO3D_PROFILE(CompilePixelShader);
1048
1049 bool success = ps->Create();
1050 if (!success)
1051 {
1052 URHO3D_LOGERROR("Failed to compile pixel shader " + ps->GetFullName() + ":\n" + ps->GetCompilerOutput());
1053 ps = 0;
1054 }
1055 }
1056 else
1057 ps = 0;
1058 }
1059
1060 impl_->deviceContext_->PSSetShader((ID3D11PixelShader*)(ps ? ps->GetGPUObject() : 0), 0, 0);
1061 pixelShader_ = ps;
1062 }
1063
1064 // Update current shader parameters & constant buffers
1065 if (vertexShader_ && pixelShader_)
1066 {
1067 Pair<ShaderVariation*, ShaderVariation*> key = MakePair(vertexShader_, pixelShader_);
1068 ShaderProgramMap::Iterator i = impl_->shaderPrograms_.Find(key);
1069 if (i != impl_->shaderPrograms_.End())
1070 impl_->shaderProgram_ = i->second_.Get();
1071 else
1072 {
1073 ShaderProgram* newProgram = impl_->shaderPrograms_[key] = new ShaderProgram(this, vertexShader_, pixelShader_);
1074 impl_->shaderProgram_ = newProgram;
1075 }
1076
1077 bool vsBuffersChanged = false;
1078 bool psBuffersChanged = false;
1079
1080 for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
1081 {
1082 ID3D11Buffer* vsBuffer = impl_->shaderProgram_->vsConstantBuffers_[i] ? (ID3D11Buffer*)impl_->shaderProgram_->vsConstantBuffers_[i]->
1083 GetGPUObject() : 0;
1084 if (vsBuffer != impl_->constantBuffers_[VS][i])
1085 {
1086 impl_->constantBuffers_[VS][i] = vsBuffer;
1087 shaderParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
1088 vsBuffersChanged = true;
1089 }
1090
1091 ID3D11Buffer* psBuffer = impl_->shaderProgram_->psConstantBuffers_[i] ? (ID3D11Buffer*)impl_->shaderProgram_->psConstantBuffers_[i]->
1092 GetGPUObject() : 0;
1093 if (psBuffer != impl_->constantBuffers_[PS][i])
1094 {
1095 impl_->constantBuffers_[PS][i] = psBuffer;
1096 shaderParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
1097 psBuffersChanged = true;
1098 }
1099 }
1100
1101 if (vsBuffersChanged)
1102 impl_->deviceContext_->VSSetConstantBuffers(0, MAX_SHADER_PARAMETER_GROUPS, &impl_->constantBuffers_[VS][0]);
1103 if (psBuffersChanged)
1104 impl_->deviceContext_->PSSetConstantBuffers(0, MAX_SHADER_PARAMETER_GROUPS, &impl_->constantBuffers_[PS][0]);
1105 }
1106 else
1107 impl_->shaderProgram_ = 0;
1108
1109 // Store shader combination if shader dumping in progress
1110 if (shaderPrecache_)
1111 shaderPrecache_->StoreShaders(vertexShader_, pixelShader_);
1112
1113 // Update clip plane parameter if necessary
1114 if (useClipPlane_)
1115 SetShaderParameter(VSP_CLIPPLANE, clipPlane_);
1116 }
1117
SetShaderParameter(StringHash param,const float * data,unsigned count)1118 void Graphics::SetShaderParameter(StringHash param, const float* data, unsigned count)
1119 {
1120 HashMap<StringHash, ShaderParameter>::Iterator i;
1121 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1122 return;
1123
1124 ConstantBuffer* buffer = i->second_.bufferPtr_;
1125 if (!buffer->IsDirty())
1126 impl_->dirtyConstantBuffers_.Push(buffer);
1127 buffer->SetParameter(i->second_.offset_, (unsigned)(count * sizeof(float)), data);
1128 }
1129
SetShaderParameter(StringHash param,float value)1130 void Graphics::SetShaderParameter(StringHash param, float value)
1131 {
1132 HashMap<StringHash, ShaderParameter>::Iterator i;
1133 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1134 return;
1135
1136 ConstantBuffer* buffer = i->second_.bufferPtr_;
1137 if (!buffer->IsDirty())
1138 impl_->dirtyConstantBuffers_.Push(buffer);
1139 buffer->SetParameter(i->second_.offset_, sizeof(float), &value);
1140 }
1141
SetShaderParameter(StringHash param,int value)1142 void Graphics::SetShaderParameter(StringHash param, int value)
1143 {
1144 HashMap<StringHash, ShaderParameter>::Iterator i;
1145 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1146 return;
1147
1148 ConstantBuffer* buffer = i->second_.bufferPtr_;
1149 if (!buffer->IsDirty())
1150 impl_->dirtyConstantBuffers_.Push(buffer);
1151 buffer->SetParameter(i->second_.offset_, sizeof(int), &value);
1152 }
1153
SetShaderParameter(StringHash param,bool value)1154 void Graphics::SetShaderParameter(StringHash param, bool value)
1155 {
1156 HashMap<StringHash, ShaderParameter>::Iterator i;
1157 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1158 return;
1159
1160 ConstantBuffer* buffer = i->second_.bufferPtr_;
1161 if (!buffer->IsDirty())
1162 impl_->dirtyConstantBuffers_.Push(buffer);
1163 buffer->SetParameter(i->second_.offset_, sizeof(bool), &value);
1164 }
1165
SetShaderParameter(StringHash param,const Color & color)1166 void Graphics::SetShaderParameter(StringHash param, const Color& color)
1167 {
1168 HashMap<StringHash, ShaderParameter>::Iterator i;
1169 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1170 return;
1171
1172 ConstantBuffer* buffer = i->second_.bufferPtr_;
1173 if (!buffer->IsDirty())
1174 impl_->dirtyConstantBuffers_.Push(buffer);
1175 buffer->SetParameter(i->second_.offset_, sizeof(Color), &color);
1176 }
1177
SetShaderParameter(StringHash param,const Vector2 & vector)1178 void Graphics::SetShaderParameter(StringHash param, const Vector2& vector)
1179 {
1180 HashMap<StringHash, ShaderParameter>::Iterator i;
1181 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1182 return;
1183
1184 ConstantBuffer* buffer = i->second_.bufferPtr_;
1185 if (!buffer->IsDirty())
1186 impl_->dirtyConstantBuffers_.Push(buffer);
1187 buffer->SetParameter(i->second_.offset_, sizeof(Vector2), &vector);
1188 }
1189
SetShaderParameter(StringHash param,const Matrix3 & matrix)1190 void Graphics::SetShaderParameter(StringHash param, const Matrix3& matrix)
1191 {
1192 HashMap<StringHash, ShaderParameter>::Iterator i;
1193 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1194 return;
1195
1196 ConstantBuffer* buffer = i->second_.bufferPtr_;
1197 if (!buffer->IsDirty())
1198 impl_->dirtyConstantBuffers_.Push(buffer);
1199 buffer->SetVector3ArrayParameter(i->second_.offset_, 3, &matrix);
1200 }
1201
SetShaderParameter(StringHash param,const Vector3 & vector)1202 void Graphics::SetShaderParameter(StringHash param, const Vector3& vector)
1203 {
1204 HashMap<StringHash, ShaderParameter>::Iterator i;
1205 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1206 return;
1207
1208 ConstantBuffer* buffer = i->second_.bufferPtr_;
1209 if (!buffer->IsDirty())
1210 impl_->dirtyConstantBuffers_.Push(buffer);
1211 buffer->SetParameter(i->second_.offset_, sizeof(Vector3), &vector);
1212 }
1213
SetShaderParameter(StringHash param,const Matrix4 & matrix)1214 void Graphics::SetShaderParameter(StringHash param, const Matrix4& matrix)
1215 {
1216 HashMap<StringHash, ShaderParameter>::Iterator i;
1217 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1218 return;
1219
1220 ConstantBuffer* buffer = i->second_.bufferPtr_;
1221 if (!buffer->IsDirty())
1222 impl_->dirtyConstantBuffers_.Push(buffer);
1223 buffer->SetParameter(i->second_.offset_, sizeof(Matrix4), &matrix);
1224 }
1225
SetShaderParameter(StringHash param,const Vector4 & vector)1226 void Graphics::SetShaderParameter(StringHash param, const Vector4& vector)
1227 {
1228 HashMap<StringHash, ShaderParameter>::Iterator i;
1229 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1230 return;
1231
1232 ConstantBuffer* buffer = i->second_.bufferPtr_;
1233 if (!buffer->IsDirty())
1234 impl_->dirtyConstantBuffers_.Push(buffer);
1235 buffer->SetParameter(i->second_.offset_, sizeof(Vector4), &vector);
1236 }
1237
SetShaderParameter(StringHash param,const Matrix3x4 & matrix)1238 void Graphics::SetShaderParameter(StringHash param, const Matrix3x4& matrix)
1239 {
1240 HashMap<StringHash, ShaderParameter>::Iterator i;
1241 if (!impl_->shaderProgram_ || (i = impl_->shaderProgram_->parameters_.Find(param)) == impl_->shaderProgram_->parameters_.End())
1242 return;
1243
1244 ConstantBuffer* buffer = i->second_.bufferPtr_;
1245 if (!buffer->IsDirty())
1246 impl_->dirtyConstantBuffers_.Push(buffer);
1247 buffer->SetParameter(i->second_.offset_, sizeof(Matrix3x4), &matrix);
1248 }
1249
NeedParameterUpdate(ShaderParameterGroup group,const void * source)1250 bool Graphics::NeedParameterUpdate(ShaderParameterGroup group, const void* source)
1251 {
1252 if ((unsigned)(size_t)shaderParameterSources_[group] == M_MAX_UNSIGNED || shaderParameterSources_[group] != source)
1253 {
1254 shaderParameterSources_[group] = source;
1255 return true;
1256 }
1257 else
1258 return false;
1259 }
1260
HasShaderParameter(StringHash param)1261 bool Graphics::HasShaderParameter(StringHash param)
1262 {
1263 return impl_->shaderProgram_ && impl_->shaderProgram_->parameters_.Find(param) != impl_->shaderProgram_->parameters_.End();
1264 }
1265
HasTextureUnit(TextureUnit unit)1266 bool Graphics::HasTextureUnit(TextureUnit unit)
1267 {
1268 return (vertexShader_ && vertexShader_->HasTextureUnit(unit)) || (pixelShader_ && pixelShader_->HasTextureUnit(unit));
1269 }
1270
ClearParameterSource(ShaderParameterGroup group)1271 void Graphics::ClearParameterSource(ShaderParameterGroup group)
1272 {
1273 shaderParameterSources_[group] = (const void*)M_MAX_UNSIGNED;
1274 }
1275
ClearParameterSources()1276 void Graphics::ClearParameterSources()
1277 {
1278 for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
1279 shaderParameterSources_[i] = (const void*)M_MAX_UNSIGNED;
1280 }
1281
ClearTransformSources()1282 void Graphics::ClearTransformSources()
1283 {
1284 shaderParameterSources_[SP_CAMERA] = (const void*)M_MAX_UNSIGNED;
1285 shaderParameterSources_[SP_OBJECT] = (const void*)M_MAX_UNSIGNED;
1286 }
1287
SetTexture(unsigned index,Texture * texture)1288 void Graphics::SetTexture(unsigned index, Texture* texture)
1289 {
1290 if (index >= MAX_TEXTURE_UNITS)
1291 return;
1292
1293 // Check if texture is currently bound as a rendertarget. In that case, use its backup texture, or blank if not defined
1294 if (texture)
1295 {
1296 if (renderTargets_[0] && renderTargets_[0]->GetParentTexture() == texture)
1297 texture = texture->GetBackupTexture();
1298 else
1299 {
1300 // Resolve multisampled texture now as necessary
1301 if (texture->GetMultiSample() > 1 && texture->GetAutoResolve() && texture->IsResolveDirty())
1302 {
1303 if (texture->GetType() == Texture2D::GetTypeStatic())
1304 ResolveToTexture(static_cast<Texture2D*>(texture));
1305 if (texture->GetType() == TextureCube::GetTypeStatic())
1306 ResolveToTexture(static_cast<TextureCube*>(texture));
1307 }
1308 }
1309
1310 if (texture->GetLevelsDirty())
1311 texture->RegenerateLevels();
1312 }
1313
1314 if (texture && texture->GetParametersDirty())
1315 {
1316 texture->UpdateParameters();
1317 textures_[index] = 0; // Force reassign
1318 }
1319
1320 if (texture != textures_[index])
1321 {
1322 if (impl_->firstDirtyTexture_ == M_MAX_UNSIGNED)
1323 impl_->firstDirtyTexture_ = impl_->lastDirtyTexture_ = index;
1324 else
1325 {
1326 if (index < impl_->firstDirtyTexture_)
1327 impl_->firstDirtyTexture_ = index;
1328 if (index > impl_->lastDirtyTexture_)
1329 impl_->lastDirtyTexture_ = index;
1330 }
1331
1332 textures_[index] = texture;
1333 impl_->shaderResourceViews_[index] = texture ? (ID3D11ShaderResourceView*)texture->GetShaderResourceView() : 0;
1334 impl_->samplers_[index] = texture ? (ID3D11SamplerState*)texture->GetSampler() : 0;
1335 impl_->texturesDirty_ = true;
1336 }
1337 }
1338
SetTextureForUpdate(Texture * texture)1339 void SetTextureForUpdate(Texture* texture)
1340 {
1341 // No-op on Direct3D11
1342 }
1343
SetDefaultTextureFilterMode(TextureFilterMode mode)1344 void Graphics::SetDefaultTextureFilterMode(TextureFilterMode mode)
1345 {
1346 if (mode != defaultTextureFilterMode_)
1347 {
1348 defaultTextureFilterMode_ = mode;
1349 SetTextureParametersDirty();
1350 }
1351 }
1352
SetDefaultTextureAnisotropy(unsigned level)1353 void Graphics::SetDefaultTextureAnisotropy(unsigned level)
1354 {
1355 level = Max(level, 1U);
1356
1357 if (level != defaultTextureAnisotropy_)
1358 {
1359 defaultTextureAnisotropy_ = level;
1360 SetTextureParametersDirty();
1361 }
1362 }
1363
Restore()1364 void Graphics::Restore()
1365 {
1366 // No-op on Direct3D11
1367 }
1368
SetTextureParametersDirty()1369 void Graphics::SetTextureParametersDirty()
1370 {
1371 MutexLock lock(gpuObjectMutex_);
1372
1373 for (PODVector<GPUObject*>::Iterator i = gpuObjects_.Begin(); i != gpuObjects_.End(); ++i)
1374 {
1375 Texture* texture = dynamic_cast<Texture*>(*i);
1376 if (texture)
1377 texture->SetParametersDirty();
1378 }
1379 }
1380
ResetRenderTargets()1381 void Graphics::ResetRenderTargets()
1382 {
1383 for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
1384 SetRenderTarget(i, (RenderSurface*)0);
1385 SetDepthStencil((RenderSurface*)0);
1386 SetViewport(IntRect(0, 0, width_, height_));
1387 }
1388
ResetRenderTarget(unsigned index)1389 void Graphics::ResetRenderTarget(unsigned index)
1390 {
1391 SetRenderTarget(index, (RenderSurface*)0);
1392 }
1393
ResetDepthStencil()1394 void Graphics::ResetDepthStencil()
1395 {
1396 SetDepthStencil((RenderSurface*)0);
1397 }
1398
SetRenderTarget(unsigned index,RenderSurface * renderTarget)1399 void Graphics::SetRenderTarget(unsigned index, RenderSurface* renderTarget)
1400 {
1401 if (index >= MAX_RENDERTARGETS)
1402 return;
1403
1404 if (renderTarget != renderTargets_[index])
1405 {
1406 renderTargets_[index] = renderTarget;
1407 impl_->renderTargetsDirty_ = true;
1408
1409 // If the rendertarget is also bound as a texture, replace with backup texture or null
1410 if (renderTarget)
1411 {
1412 Texture* parentTexture = renderTarget->GetParentTexture();
1413
1414 for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
1415 {
1416 if (textures_[i] == parentTexture)
1417 SetTexture(i, textures_[i]->GetBackupTexture());
1418 }
1419
1420 // If multisampled, mark the texture & surface needing resolve
1421 if (parentTexture->GetMultiSample() > 1 && parentTexture->GetAutoResolve())
1422 {
1423 parentTexture->SetResolveDirty(true);
1424 renderTarget->SetResolveDirty(true);
1425 }
1426
1427 // If mipmapped, mark the levels needing regeneration
1428 if (parentTexture->GetLevels() > 1)
1429 parentTexture->SetLevelsDirty();
1430 }
1431 }
1432 }
1433
SetRenderTarget(unsigned index,Texture2D * texture)1434 void Graphics::SetRenderTarget(unsigned index, Texture2D* texture)
1435 {
1436 RenderSurface* renderTarget = 0;
1437 if (texture)
1438 renderTarget = texture->GetRenderSurface();
1439
1440 SetRenderTarget(index, renderTarget);
1441 }
1442
SetDepthStencil(RenderSurface * depthStencil)1443 void Graphics::SetDepthStencil(RenderSurface* depthStencil)
1444 {
1445 if (depthStencil != depthStencil_)
1446 {
1447 depthStencil_ = depthStencil;
1448 impl_->renderTargetsDirty_ = true;
1449 }
1450 }
1451
SetDepthStencil(Texture2D * texture)1452 void Graphics::SetDepthStencil(Texture2D* texture)
1453 {
1454 RenderSurface* depthStencil = 0;
1455 if (texture)
1456 depthStencil = texture->GetRenderSurface();
1457
1458 SetDepthStencil(depthStencil);
1459 // Constant depth bias depends on the bitdepth
1460 impl_->rasterizerStateDirty_ = true;
1461 }
1462
SetViewport(const IntRect & rect)1463 void Graphics::SetViewport(const IntRect& rect)
1464 {
1465 IntVector2 size = GetRenderTargetDimensions();
1466
1467 IntRect rectCopy = rect;
1468
1469 if (rectCopy.right_ <= rectCopy.left_)
1470 rectCopy.right_ = rectCopy.left_ + 1;
1471 if (rectCopy.bottom_ <= rectCopy.top_)
1472 rectCopy.bottom_ = rectCopy.top_ + 1;
1473 rectCopy.left_ = Clamp(rectCopy.left_, 0, size.x_);
1474 rectCopy.top_ = Clamp(rectCopy.top_, 0, size.y_);
1475 rectCopy.right_ = Clamp(rectCopy.right_, 0, size.x_);
1476 rectCopy.bottom_ = Clamp(rectCopy.bottom_, 0, size.y_);
1477
1478 static D3D11_VIEWPORT d3dViewport;
1479 d3dViewport.TopLeftX = (float)rectCopy.left_;
1480 d3dViewport.TopLeftY = (float)rectCopy.top_;
1481 d3dViewport.Width = (float)(rectCopy.right_ - rectCopy.left_);
1482 d3dViewport.Height = (float)(rectCopy.bottom_ - rectCopy.top_);
1483 d3dViewport.MinDepth = 0.0f;
1484 d3dViewport.MaxDepth = 1.0f;
1485
1486 impl_->deviceContext_->RSSetViewports(1, &d3dViewport);
1487
1488 viewport_ = rectCopy;
1489
1490 // Disable scissor test, needs to be re-enabled by the user
1491 SetScissorTest(false);
1492 }
1493
SetBlendMode(BlendMode mode,bool alphaToCoverage)1494 void Graphics::SetBlendMode(BlendMode mode, bool alphaToCoverage)
1495 {
1496 if (mode != blendMode_ || alphaToCoverage != alphaToCoverage_)
1497 {
1498 blendMode_ = mode;
1499 alphaToCoverage_ = alphaToCoverage;
1500 impl_->blendStateDirty_ = true;
1501 }
1502 }
1503
SetColorWrite(bool enable)1504 void Graphics::SetColorWrite(bool enable)
1505 {
1506 if (enable != colorWrite_)
1507 {
1508 colorWrite_ = enable;
1509 impl_->blendStateDirty_ = true;
1510 }
1511 }
1512
SetCullMode(CullMode mode)1513 void Graphics::SetCullMode(CullMode mode)
1514 {
1515 if (mode != cullMode_)
1516 {
1517 cullMode_ = mode;
1518 impl_->rasterizerStateDirty_ = true;
1519 }
1520 }
1521
SetDepthBias(float constantBias,float slopeScaledBias)1522 void Graphics::SetDepthBias(float constantBias, float slopeScaledBias)
1523 {
1524 if (constantBias != constantDepthBias_ || slopeScaledBias != slopeScaledDepthBias_)
1525 {
1526 constantDepthBias_ = constantBias;
1527 slopeScaledDepthBias_ = slopeScaledBias;
1528 impl_->rasterizerStateDirty_ = true;
1529 }
1530 }
1531
SetDepthTest(CompareMode mode)1532 void Graphics::SetDepthTest(CompareMode mode)
1533 {
1534 if (mode != depthTestMode_)
1535 {
1536 depthTestMode_ = mode;
1537 impl_->depthStateDirty_ = true;
1538 }
1539 }
1540
SetDepthWrite(bool enable)1541 void Graphics::SetDepthWrite(bool enable)
1542 {
1543 if (enable != depthWrite_)
1544 {
1545 depthWrite_ = enable;
1546 impl_->depthStateDirty_ = true;
1547 // Also affects whether a read-only version of depth-stencil should be bound, to allow sampling
1548 impl_->renderTargetsDirty_ = true;
1549 }
1550 }
1551
SetFillMode(FillMode mode)1552 void Graphics::SetFillMode(FillMode mode)
1553 {
1554 if (mode != fillMode_)
1555 {
1556 fillMode_ = mode;
1557 impl_->rasterizerStateDirty_ = true;
1558 }
1559 }
1560
SetLineAntiAlias(bool enable)1561 void Graphics::SetLineAntiAlias(bool enable)
1562 {
1563 if (enable != lineAntiAlias_)
1564 {
1565 lineAntiAlias_ = enable;
1566 impl_->rasterizerStateDirty_ = true;
1567 }
1568 }
1569
SetScissorTest(bool enable,const Rect & rect,bool borderInclusive)1570 void Graphics::SetScissorTest(bool enable, const Rect& rect, bool borderInclusive)
1571 {
1572 // During some light rendering loops, a full rect is toggled on/off repeatedly.
1573 // Disable scissor in that case to reduce state changes
1574 if (rect.min_.x_ <= 0.0f && rect.min_.y_ <= 0.0f && rect.max_.x_ >= 1.0f && rect.max_.y_ >= 1.0f)
1575 enable = false;
1576
1577 if (enable)
1578 {
1579 IntVector2 rtSize(GetRenderTargetDimensions());
1580 IntVector2 viewSize(viewport_.Size());
1581 IntVector2 viewPos(viewport_.left_, viewport_.top_);
1582 IntRect intRect;
1583 int expand = borderInclusive ? 1 : 0;
1584
1585 intRect.left_ = Clamp((int)((rect.min_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_, 0, rtSize.x_ - 1);
1586 intRect.top_ = Clamp((int)((-rect.max_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_, 0, rtSize.y_ - 1);
1587 intRect.right_ = Clamp((int)((rect.max_.x_ + 1.0f) * 0.5f * viewSize.x_) + viewPos.x_ + expand, 0, rtSize.x_);
1588 intRect.bottom_ = Clamp((int)((-rect.min_.y_ + 1.0f) * 0.5f * viewSize.y_) + viewPos.y_ + expand, 0, rtSize.y_);
1589
1590 if (intRect.right_ == intRect.left_)
1591 intRect.right_++;
1592 if (intRect.bottom_ == intRect.top_)
1593 intRect.bottom_++;
1594
1595 if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
1596 enable = false;
1597
1598 if (enable && intRect != scissorRect_)
1599 {
1600 scissorRect_ = intRect;
1601 impl_->scissorRectDirty_ = true;
1602 }
1603 }
1604
1605 if (enable != scissorTest_)
1606 {
1607 scissorTest_ = enable;
1608 impl_->rasterizerStateDirty_ = true;
1609 }
1610 }
1611
SetScissorTest(bool enable,const IntRect & rect)1612 void Graphics::SetScissorTest(bool enable, const IntRect& rect)
1613 {
1614 IntVector2 rtSize(GetRenderTargetDimensions());
1615 IntVector2 viewPos(viewport_.left_, viewport_.top_);
1616
1617 if (enable)
1618 {
1619 IntRect intRect;
1620 intRect.left_ = Clamp(rect.left_ + viewPos.x_, 0, rtSize.x_ - 1);
1621 intRect.top_ = Clamp(rect.top_ + viewPos.y_, 0, rtSize.y_ - 1);
1622 intRect.right_ = Clamp(rect.right_ + viewPos.x_, 0, rtSize.x_);
1623 intRect.bottom_ = Clamp(rect.bottom_ + viewPos.y_, 0, rtSize.y_);
1624
1625 if (intRect.right_ == intRect.left_)
1626 intRect.right_++;
1627 if (intRect.bottom_ == intRect.top_)
1628 intRect.bottom_++;
1629
1630 if (intRect.right_ < intRect.left_ || intRect.bottom_ < intRect.top_)
1631 enable = false;
1632
1633 if (enable && intRect != scissorRect_)
1634 {
1635 scissorRect_ = intRect;
1636 impl_->scissorRectDirty_ = true;
1637 }
1638 }
1639
1640 if (enable != scissorTest_)
1641 {
1642 scissorTest_ = enable;
1643 impl_->rasterizerStateDirty_ = true;
1644 }
1645 }
1646
SetStencilTest(bool enable,CompareMode mode,StencilOp pass,StencilOp fail,StencilOp zFail,unsigned stencilRef,unsigned compareMask,unsigned writeMask)1647 void Graphics::SetStencilTest(bool enable, CompareMode mode, StencilOp pass, StencilOp fail, StencilOp zFail, unsigned stencilRef,
1648 unsigned compareMask, unsigned writeMask)
1649 {
1650 if (enable != stencilTest_)
1651 {
1652 stencilTest_ = enable;
1653 impl_->depthStateDirty_ = true;
1654 }
1655
1656 if (enable)
1657 {
1658 if (mode != stencilTestMode_)
1659 {
1660 stencilTestMode_ = mode;
1661 impl_->depthStateDirty_ = true;
1662 }
1663 if (pass != stencilPass_)
1664 {
1665 stencilPass_ = pass;
1666 impl_->depthStateDirty_ = true;
1667 }
1668 if (fail != stencilFail_)
1669 {
1670 stencilFail_ = fail;
1671 impl_->depthStateDirty_ = true;
1672 }
1673 if (zFail != stencilZFail_)
1674 {
1675 stencilZFail_ = zFail;
1676 impl_->depthStateDirty_ = true;
1677 }
1678 if (compareMask != stencilCompareMask_)
1679 {
1680 stencilCompareMask_ = compareMask;
1681 impl_->depthStateDirty_ = true;
1682 }
1683 if (writeMask != stencilWriteMask_)
1684 {
1685 stencilWriteMask_ = writeMask;
1686 impl_->depthStateDirty_ = true;
1687 }
1688 if (stencilRef != stencilRef_)
1689 {
1690 stencilRef_ = stencilRef;
1691 impl_->stencilRefDirty_ = true;
1692 impl_->depthStateDirty_ = true;
1693 }
1694 }
1695 }
1696
SetClipPlane(bool enable,const Plane & clipPlane,const Matrix3x4 & view,const Matrix4 & projection)1697 void Graphics::SetClipPlane(bool enable, const Plane& clipPlane, const Matrix3x4& view, const Matrix4& projection)
1698 {
1699 useClipPlane_ = enable;
1700
1701 if (enable)
1702 {
1703 Matrix4 viewProj = projection * view;
1704 clipPlane_ = clipPlane.Transformed(viewProj).ToVector4();
1705 SetShaderParameter(VSP_CLIPPLANE, clipPlane_);
1706 }
1707 }
1708
IsInitialized() const1709 bool Graphics::IsInitialized() const
1710 {
1711 return window_ != 0 && impl_->GetDevice() != 0;
1712 }
1713
GetMultiSampleLevels() const1714 PODVector<int> Graphics::GetMultiSampleLevels() const
1715 {
1716 PODVector<int> ret;
1717 ret.Push(1);
1718
1719 if (impl_->device_)
1720 {
1721 for (unsigned i = 2; i <= 16; ++i)
1722 {
1723 if (impl_->CheckMultiSampleSupport(sRGB_ ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM, i))
1724 ret.Push(i);
1725 }
1726 }
1727
1728 return ret;
1729 }
1730
GetFormat(CompressedFormat format) const1731 unsigned Graphics::GetFormat(CompressedFormat format) const
1732 {
1733 switch (format)
1734 {
1735 case CF_RGBA:
1736 return DXGI_FORMAT_R8G8B8A8_UNORM;
1737
1738 case CF_DXT1:
1739 return DXGI_FORMAT_BC1_UNORM;
1740
1741 case CF_DXT3:
1742 return DXGI_FORMAT_BC2_UNORM;
1743
1744 case CF_DXT5:
1745 return DXGI_FORMAT_BC3_UNORM;
1746
1747 default:
1748 return 0;
1749 }
1750 }
1751
GetShader(ShaderType type,const String & name,const String & defines) const1752 ShaderVariation* Graphics::GetShader(ShaderType type, const String& name, const String& defines) const
1753 {
1754 return GetShader(type, name.CString(), defines.CString());
1755 }
1756
GetShader(ShaderType type,const char * name,const char * defines) const1757 ShaderVariation* Graphics::GetShader(ShaderType type, const char* name, const char* defines) const
1758 {
1759 if (lastShaderName_ != name || !lastShader_)
1760 {
1761 ResourceCache* cache = GetSubsystem<ResourceCache>();
1762
1763 String fullShaderName = shaderPath_ + name + shaderExtension_;
1764 // Try to reduce repeated error log prints because of missing shaders
1765 if (lastShaderName_ == name && !cache->Exists(fullShaderName))
1766 return 0;
1767
1768 lastShader_ = cache->GetResource<Shader>(fullShaderName);
1769 lastShaderName_ = name;
1770 }
1771
1772 return lastShader_ ? lastShader_->GetVariation(type, defines) : (ShaderVariation*)0;
1773 }
1774
GetVertexBuffer(unsigned index) const1775 VertexBuffer* Graphics::GetVertexBuffer(unsigned index) const
1776 {
1777 return index < MAX_VERTEX_STREAMS ? vertexBuffers_[index] : 0;
1778 }
1779
GetShaderProgram() const1780 ShaderProgram* Graphics::GetShaderProgram() const
1781 {
1782 return impl_->shaderProgram_;
1783 }
1784
GetTextureUnit(const String & name)1785 TextureUnit Graphics::GetTextureUnit(const String& name)
1786 {
1787 HashMap<String, TextureUnit>::Iterator i = textureUnits_.Find(name);
1788 if (i != textureUnits_.End())
1789 return i->second_;
1790 else
1791 return MAX_TEXTURE_UNITS;
1792 }
1793
GetTextureUnitName(TextureUnit unit)1794 const String& Graphics::GetTextureUnitName(TextureUnit unit)
1795 {
1796 for (HashMap<String, TextureUnit>::Iterator i = textureUnits_.Begin(); i != textureUnits_.End(); ++i)
1797 {
1798 if (i->second_ == unit)
1799 return i->first_;
1800 }
1801 return String::EMPTY;
1802 }
1803
GetTexture(unsigned index) const1804 Texture* Graphics::GetTexture(unsigned index) const
1805 {
1806 return index < MAX_TEXTURE_UNITS ? textures_[index] : 0;
1807 }
1808
GetRenderTarget(unsigned index) const1809 RenderSurface* Graphics::GetRenderTarget(unsigned index) const
1810 {
1811 return index < MAX_RENDERTARGETS ? renderTargets_[index] : 0;
1812 }
1813
GetRenderTargetDimensions() const1814 IntVector2 Graphics::GetRenderTargetDimensions() const
1815 {
1816 int width, height;
1817
1818 if (renderTargets_[0])
1819 {
1820 width = renderTargets_[0]->GetWidth();
1821 height = renderTargets_[0]->GetHeight();
1822 }
1823 else if (depthStencil_) // Depth-only rendering
1824 {
1825 width = depthStencil_->GetWidth();
1826 height = depthStencil_->GetHeight();
1827 }
1828 else
1829 {
1830 width = width_;
1831 height = height_;
1832 }
1833
1834 return IntVector2(width, height);
1835 }
1836
GetDither() const1837 bool Graphics::GetDither() const
1838 {
1839 return false;
1840 }
1841
IsDeviceLost() const1842 bool Graphics::IsDeviceLost() const
1843 {
1844 // Direct3D11 graphics context is never considered lost
1845 /// \todo The device could be lost in case of graphics adapters getting disabled during runtime. This is not currently handled
1846 return false;
1847 }
1848
OnWindowResized()1849 void Graphics::OnWindowResized()
1850 {
1851 if (!impl_->device_ || !window_)
1852 return;
1853
1854 int newWidth, newHeight;
1855
1856 SDL_GetWindowSize(window_, &newWidth, &newHeight);
1857 if (newWidth == width_ && newHeight == height_)
1858 return;
1859
1860 UpdateSwapChain(newWidth, newHeight);
1861
1862 // Reset rendertargets and viewport for the new screen size
1863 ResetRenderTargets();
1864
1865 URHO3D_LOGDEBUGF("Window was resized to %dx%d", width_, height_);
1866
1867 using namespace ScreenMode;
1868
1869 VariantMap& eventData = GetEventDataMap();
1870 eventData[P_WIDTH] = width_;
1871 eventData[P_HEIGHT] = height_;
1872 eventData[P_FULLSCREEN] = fullscreen_;
1873 eventData[P_RESIZABLE] = resizable_;
1874 eventData[P_BORDERLESS] = borderless_;
1875 eventData[P_HIGHDPI] = highDPI_;
1876 SendEvent(E_SCREENMODE, eventData);
1877 }
1878
OnWindowMoved()1879 void Graphics::OnWindowMoved()
1880 {
1881 if (!impl_->device_ || !window_ || fullscreen_)
1882 return;
1883
1884 int newX, newY;
1885
1886 SDL_GetWindowPosition(window_, &newX, &newY);
1887 if (newX == position_.x_ && newY == position_.y_)
1888 return;
1889
1890 position_.x_ = newX;
1891 position_.y_ = newY;
1892
1893 URHO3D_LOGDEBUGF("Window was moved to %d,%d", position_.x_, position_.y_);
1894
1895 using namespace WindowPos;
1896
1897 VariantMap& eventData = GetEventDataMap();
1898 eventData[P_X] = position_.x_;
1899 eventData[P_Y] = position_.y_;
1900 SendEvent(E_WINDOWPOS, eventData);
1901 }
1902
CleanupShaderPrograms(ShaderVariation * variation)1903 void Graphics::CleanupShaderPrograms(ShaderVariation* variation)
1904 {
1905 for (ShaderProgramMap::Iterator i = impl_->shaderPrograms_.Begin(); i != impl_->shaderPrograms_.End();)
1906 {
1907 if (i->first_.first_ == variation || i->first_.second_ == variation)
1908 i = impl_->shaderPrograms_.Erase(i);
1909 else
1910 ++i;
1911 }
1912
1913 if (vertexShader_ == variation || pixelShader_ == variation)
1914 impl_->shaderProgram_ = 0;
1915 }
1916
CleanupRenderSurface(RenderSurface * surface)1917 void Graphics::CleanupRenderSurface(RenderSurface* surface)
1918 {
1919 // No-op on Direct3D11
1920 }
1921
GetOrCreateConstantBuffer(ShaderType type,unsigned index,unsigned size)1922 ConstantBuffer* Graphics::GetOrCreateConstantBuffer(ShaderType type, unsigned index, unsigned size)
1923 {
1924 // Ensure that different shader types and index slots get unique buffers, even if the size is same
1925 unsigned key = type | (index << 1) | (size << 4);
1926 ConstantBufferMap::Iterator i = impl_->allConstantBuffers_.Find(key);
1927 if (i != impl_->allConstantBuffers_.End())
1928 return i->second_.Get();
1929 else
1930 {
1931 SharedPtr<ConstantBuffer> newConstantBuffer(new ConstantBuffer(context_));
1932 newConstantBuffer->SetSize(size);
1933 impl_->allConstantBuffers_[key] = newConstantBuffer;
1934 return newConstantBuffer.Get();
1935 }
1936 }
1937
GetAlphaFormat()1938 unsigned Graphics::GetAlphaFormat()
1939 {
1940 return DXGI_FORMAT_A8_UNORM;
1941 }
1942
GetLuminanceFormat()1943 unsigned Graphics::GetLuminanceFormat()
1944 {
1945 // Note: not same sampling behavior as on D3D9; need to sample the R channel only
1946 return DXGI_FORMAT_R8_UNORM;
1947 }
1948
GetLuminanceAlphaFormat()1949 unsigned Graphics::GetLuminanceAlphaFormat()
1950 {
1951 // Note: not same sampling behavior as on D3D9; need to sample the RG channels
1952 return DXGI_FORMAT_R8G8_UNORM;
1953 }
1954
GetRGBFormat()1955 unsigned Graphics::GetRGBFormat()
1956 {
1957 return DXGI_FORMAT_R8G8B8A8_UNORM;
1958 }
1959
GetRGBAFormat()1960 unsigned Graphics::GetRGBAFormat()
1961 {
1962 return DXGI_FORMAT_R8G8B8A8_UNORM;
1963 }
1964
GetRGBA16Format()1965 unsigned Graphics::GetRGBA16Format()
1966 {
1967 return DXGI_FORMAT_R16G16B16A16_UNORM;
1968 }
1969
GetRGBAFloat16Format()1970 unsigned Graphics::GetRGBAFloat16Format()
1971 {
1972 return DXGI_FORMAT_R16G16B16A16_FLOAT;
1973 }
1974
GetRGBAFloat32Format()1975 unsigned Graphics::GetRGBAFloat32Format()
1976 {
1977 return DXGI_FORMAT_R32G32B32A32_FLOAT;
1978 }
1979
GetRG16Format()1980 unsigned Graphics::GetRG16Format()
1981 {
1982 return DXGI_FORMAT_R16G16_UNORM;
1983 }
1984
GetRGFloat16Format()1985 unsigned Graphics::GetRGFloat16Format()
1986 {
1987 return DXGI_FORMAT_R16G16_FLOAT;
1988 }
1989
GetRGFloat32Format()1990 unsigned Graphics::GetRGFloat32Format()
1991 {
1992 return DXGI_FORMAT_R32G32_FLOAT;
1993 }
1994
GetFloat16Format()1995 unsigned Graphics::GetFloat16Format()
1996 {
1997 return DXGI_FORMAT_R16_FLOAT;
1998 }
1999
GetFloat32Format()2000 unsigned Graphics::GetFloat32Format()
2001 {
2002 return DXGI_FORMAT_R32_FLOAT;
2003 }
2004
GetLinearDepthFormat()2005 unsigned Graphics::GetLinearDepthFormat()
2006 {
2007 return DXGI_FORMAT_R32_FLOAT;
2008 }
2009
GetDepthStencilFormat()2010 unsigned Graphics::GetDepthStencilFormat()
2011 {
2012 return DXGI_FORMAT_R24G8_TYPELESS;
2013 }
2014
GetReadableDepthFormat()2015 unsigned Graphics::GetReadableDepthFormat()
2016 {
2017 return DXGI_FORMAT_R24G8_TYPELESS;
2018 }
2019
GetFormat(const String & formatName)2020 unsigned Graphics::GetFormat(const String& formatName)
2021 {
2022 String nameLower = formatName.ToLower().Trimmed();
2023
2024 if (nameLower == "a")
2025 return GetAlphaFormat();
2026 if (nameLower == "l")
2027 return GetLuminanceFormat();
2028 if (nameLower == "la")
2029 return GetLuminanceAlphaFormat();
2030 if (nameLower == "rgb")
2031 return GetRGBFormat();
2032 if (nameLower == "rgba")
2033 return GetRGBAFormat();
2034 if (nameLower == "rgba16")
2035 return GetRGBA16Format();
2036 if (nameLower == "rgba16f")
2037 return GetRGBAFloat16Format();
2038 if (nameLower == "rgba32f")
2039 return GetRGBAFloat32Format();
2040 if (nameLower == "rg16")
2041 return GetRG16Format();
2042 if (nameLower == "rg16f")
2043 return GetRGFloat16Format();
2044 if (nameLower == "rg32f")
2045 return GetRGFloat32Format();
2046 if (nameLower == "r16f")
2047 return GetFloat16Format();
2048 if (nameLower == "r32f" || nameLower == "float")
2049 return GetFloat32Format();
2050 if (nameLower == "lineardepth" || nameLower == "depth")
2051 return GetLinearDepthFormat();
2052 if (nameLower == "d24s8")
2053 return GetDepthStencilFormat();
2054 if (nameLower == "readabledepth" || nameLower == "hwdepth")
2055 return GetReadableDepthFormat();
2056
2057 return GetRGBFormat();
2058 }
2059
GetMaxBones()2060 unsigned Graphics::GetMaxBones()
2061 {
2062 return 128;
2063 }
2064
GetGL3Support()2065 bool Graphics::GetGL3Support()
2066 {
2067 return gl3Support;
2068 }
2069
OpenWindow(int width,int height,bool resizable,bool borderless)2070 bool Graphics::OpenWindow(int width, int height, bool resizable, bool borderless)
2071 {
2072 if (!externalWindow_)
2073 {
2074 unsigned flags = 0;
2075 if (resizable)
2076 flags |= SDL_WINDOW_RESIZABLE;
2077 if (borderless)
2078 flags |= SDL_WINDOW_BORDERLESS;
2079
2080 window_ = SDL_CreateWindow(windowTitle_.CString(), position_.x_, position_.y_, width, height, flags);
2081 }
2082 else
2083 window_ = SDL_CreateWindowFrom(externalWindow_, 0);
2084
2085 if (!window_)
2086 {
2087 URHO3D_LOGERRORF("Could not create window, root cause: '%s'", SDL_GetError());
2088 return false;
2089 }
2090
2091 SDL_GetWindowPosition(window_, &position_.x_, &position_.y_);
2092
2093 CreateWindowIcon();
2094
2095 return true;
2096 }
2097
AdjustWindow(int & newWidth,int & newHeight,bool & newFullscreen,bool & newBorderless,int & monitor)2098 void Graphics::AdjustWindow(int& newWidth, int& newHeight, bool& newFullscreen, bool& newBorderless, int& monitor)
2099 {
2100 if (!externalWindow_)
2101 {
2102 if (!newWidth || !newHeight)
2103 {
2104 SDL_MaximizeWindow(window_);
2105 SDL_GetWindowSize(window_, &newWidth, &newHeight);
2106 }
2107 else
2108 {
2109 SDL_Rect display_rect;
2110 SDL_GetDisplayBounds(monitor, &display_rect);
2111
2112 if (newFullscreen || (newBorderless && newWidth >= display_rect.w && newHeight >= display_rect.h))
2113 {
2114 // Reposition the window on the specified monitor if it's supposed to cover the entire monitor
2115 SDL_SetWindowPosition(window_, display_rect.x, display_rect.y);
2116 }
2117
2118 SDL_SetWindowSize(window_, newWidth, newHeight);
2119 }
2120
2121 // Hack fix: on SDL 2.0.4 a fullscreen->windowed transition results in a maximized window when the D3D device is reset, so hide before
2122 SDL_HideWindow(window_);
2123 SDL_SetWindowFullscreen(window_, newFullscreen ? SDL_WINDOW_FULLSCREEN : 0);
2124 SDL_SetWindowBordered(window_, newBorderless ? SDL_FALSE : SDL_TRUE);
2125 SDL_ShowWindow(window_);
2126 }
2127 else
2128 {
2129 // If external window, must ask its dimensions instead of trying to set them
2130 SDL_GetWindowSize(window_, &newWidth, &newHeight);
2131 newFullscreen = false;
2132 }
2133 }
2134
CreateDevice(int width,int height,int multiSample)2135 bool Graphics::CreateDevice(int width, int height, int multiSample)
2136 {
2137 // Device needs only to be created once
2138 if (!impl_->device_)
2139 {
2140 HRESULT hr = D3D11CreateDevice(
2141 0,
2142 D3D_DRIVER_TYPE_HARDWARE,
2143 0,
2144 0,
2145 0,
2146 0,
2147 D3D11_SDK_VERSION,
2148 &impl_->device_,
2149 0,
2150 &impl_->deviceContext_
2151 );
2152
2153 if (FAILED(hr))
2154 {
2155 URHO3D_SAFE_RELEASE(impl_->device_);
2156 URHO3D_SAFE_RELEASE(impl_->deviceContext_);
2157 URHO3D_LOGD3DERROR("Failed to create D3D11 device", hr);
2158 return false;
2159 }
2160
2161 CheckFeatureSupport();
2162 // Set the flush mode now as the device has been created
2163 SetFlushGPU(flushGPU_);
2164 }
2165
2166 // Check that multisample level is supported
2167 PODVector<int> multiSampleLevels = GetMultiSampleLevels();
2168 if (!multiSampleLevels.Contains(multiSample))
2169 multiSample = 1;
2170
2171 // Create swap chain. Release old if necessary
2172 if (impl_->swapChain_)
2173 {
2174 impl_->swapChain_->Release();
2175 impl_->swapChain_ = 0;
2176 }
2177
2178 DXGI_SWAP_CHAIN_DESC swapChainDesc;
2179 memset(&swapChainDesc, 0, sizeof swapChainDesc);
2180 swapChainDesc.BufferCount = 1;
2181 swapChainDesc.BufferDesc.Width = (UINT)width;
2182 swapChainDesc.BufferDesc.Height = (UINT)height;
2183 swapChainDesc.BufferDesc.Format = sRGB_ ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM;
2184 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2185 swapChainDesc.OutputWindow = GetWindowHandle(window_);
2186 swapChainDesc.SampleDesc.Count = (UINT)multiSample;
2187 swapChainDesc.SampleDesc.Quality = impl_->GetMultiSampleQuality(swapChainDesc.BufferDesc.Format, multiSample);
2188 swapChainDesc.Windowed = TRUE;
2189 swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
2190
2191 IDXGIDevice* dxgiDevice = 0;
2192 impl_->device_->QueryInterface(IID_IDXGIDevice, (void**)&dxgiDevice);
2193 IDXGIAdapter* dxgiAdapter = 0;
2194 dxgiDevice->GetParent(IID_IDXGIAdapter, (void**)&dxgiAdapter);
2195 IDXGIFactory* dxgiFactory = 0;
2196 dxgiAdapter->GetParent(IID_IDXGIFactory, (void**)&dxgiFactory);
2197 HRESULT hr = dxgiFactory->CreateSwapChain(impl_->device_, &swapChainDesc, &impl_->swapChain_);
2198 // After creating the swap chain, disable automatic Alt-Enter fullscreen/windowed switching
2199 // (the application will switch manually if it wants to)
2200 dxgiFactory->MakeWindowAssociation(GetWindowHandle(window_), DXGI_MWA_NO_ALT_ENTER);
2201
2202 dxgiFactory->Release();
2203 dxgiAdapter->Release();
2204 dxgiDevice->Release();
2205
2206 if (FAILED(hr))
2207 {
2208 URHO3D_SAFE_RELEASE(impl_->swapChain_);
2209 URHO3D_LOGD3DERROR("Failed to create D3D11 swap chain", hr);
2210 return false;
2211 }
2212
2213 multiSample_ = multiSample;
2214 return true;
2215 }
2216
UpdateSwapChain(int width,int height)2217 bool Graphics::UpdateSwapChain(int width, int height)
2218 {
2219 bool success = true;
2220
2221 ID3D11RenderTargetView* nullView = 0;
2222 impl_->deviceContext_->OMSetRenderTargets(1, &nullView, 0);
2223 if (impl_->defaultRenderTargetView_)
2224 {
2225 impl_->defaultRenderTargetView_->Release();
2226 impl_->defaultRenderTargetView_ = 0;
2227 }
2228 if (impl_->defaultDepthStencilView_)
2229 {
2230 impl_->defaultDepthStencilView_->Release();
2231 impl_->defaultDepthStencilView_ = 0;
2232 }
2233 if (impl_->defaultDepthTexture_)
2234 {
2235 impl_->defaultDepthTexture_->Release();
2236 impl_->defaultDepthTexture_ = 0;
2237 }
2238 if (impl_->resolveTexture_)
2239 {
2240 impl_->resolveTexture_->Release();
2241 impl_->resolveTexture_ = 0;
2242 }
2243
2244 impl_->depthStencilView_ = 0;
2245 for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
2246 impl_->renderTargetViews_[i] = 0;
2247 impl_->renderTargetsDirty_ = true;
2248
2249 impl_->swapChain_->ResizeBuffers(1, (UINT)width, (UINT)height, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
2250
2251 // Create default rendertarget view representing the backbuffer
2252 ID3D11Texture2D* backbufferTexture;
2253 HRESULT hr = impl_->swapChain_->GetBuffer(0, IID_ID3D11Texture2D, (void**)&backbufferTexture);
2254 if (FAILED(hr))
2255 {
2256 URHO3D_SAFE_RELEASE(backbufferTexture);
2257 URHO3D_LOGD3DERROR("Failed to get backbuffer texture", hr);
2258 success = false;
2259 }
2260 else
2261 {
2262 hr = impl_->device_->CreateRenderTargetView(backbufferTexture, 0, &impl_->defaultRenderTargetView_);
2263 backbufferTexture->Release();
2264 if (FAILED(hr))
2265 {
2266 URHO3D_SAFE_RELEASE(impl_->defaultRenderTargetView_);
2267 URHO3D_LOGD3DERROR("Failed to create backbuffer rendertarget view", hr);
2268 success = false;
2269 }
2270 }
2271
2272 // Create default depth-stencil texture and view
2273 D3D11_TEXTURE2D_DESC depthDesc;
2274 memset(&depthDesc, 0, sizeof depthDesc);
2275 depthDesc.Width = (UINT)width;
2276 depthDesc.Height = (UINT)height;
2277 depthDesc.MipLevels = 1;
2278 depthDesc.ArraySize = 1;
2279 depthDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
2280 depthDesc.SampleDesc.Count = (UINT)multiSample_;
2281 depthDesc.SampleDesc.Quality = impl_->GetMultiSampleQuality(depthDesc.Format, multiSample_);
2282 depthDesc.Usage = D3D11_USAGE_DEFAULT;
2283 depthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
2284 depthDesc.CPUAccessFlags = 0;
2285 depthDesc.MiscFlags = 0;
2286 hr = impl_->device_->CreateTexture2D(&depthDesc, 0, &impl_->defaultDepthTexture_);
2287 if (FAILED(hr))
2288 {
2289 URHO3D_SAFE_RELEASE(impl_->defaultDepthTexture_);
2290 URHO3D_LOGD3DERROR("Failed to create backbuffer depth-stencil texture", hr);
2291 success = false;
2292 }
2293 else
2294 {
2295 hr = impl_->device_->CreateDepthStencilView(impl_->defaultDepthTexture_, 0, &impl_->defaultDepthStencilView_);
2296 if (FAILED(hr))
2297 {
2298 URHO3D_SAFE_RELEASE(impl_->defaultDepthStencilView_);
2299 URHO3D_LOGD3DERROR("Failed to create backbuffer depth-stencil view", hr);
2300 success = false;
2301 }
2302 }
2303
2304 // Update internally held backbuffer size
2305 width_ = width;
2306 height_ = height;
2307
2308 ResetRenderTargets();
2309 return success;
2310 }
2311
CheckFeatureSupport()2312 void Graphics::CheckFeatureSupport()
2313 {
2314 anisotropySupport_ = true;
2315 dxtTextureSupport_ = true;
2316 lightPrepassSupport_ = true;
2317 deferredSupport_ = true;
2318 hardwareShadowSupport_ = true;
2319 instancingSupport_ = true;
2320 shadowMapFormat_ = DXGI_FORMAT_R16_TYPELESS;
2321 hiresShadowMapFormat_ = DXGI_FORMAT_R32_TYPELESS;
2322 dummyColorFormat_ = DXGI_FORMAT_UNKNOWN;
2323 sRGBSupport_ = true;
2324 sRGBWriteSupport_ = true;
2325 }
2326
ResetCachedState()2327 void Graphics::ResetCachedState()
2328 {
2329 for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
2330 {
2331 vertexBuffers_[i] = 0;
2332 impl_->vertexBuffers_[i] = 0;
2333 impl_->vertexSizes_[i] = 0;
2334 impl_->vertexOffsets_[i] = 0;
2335 }
2336
2337 for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
2338 {
2339 textures_[i] = 0;
2340 impl_->shaderResourceViews_[i] = 0;
2341 impl_->samplers_[i] = 0;
2342 }
2343
2344 for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
2345 {
2346 renderTargets_[i] = 0;
2347 impl_->renderTargetViews_[i] = 0;
2348 }
2349
2350 for (unsigned i = 0; i < MAX_SHADER_PARAMETER_GROUPS; ++i)
2351 {
2352 impl_->constantBuffers_[VS][i] = 0;
2353 impl_->constantBuffers_[PS][i] = 0;
2354 }
2355
2356 depthStencil_ = 0;
2357 impl_->depthStencilView_ = 0;
2358 viewport_ = IntRect(0, 0, width_, height_);
2359
2360 indexBuffer_ = 0;
2361 vertexDeclarationHash_ = 0;
2362 primitiveType_ = 0;
2363 vertexShader_ = 0;
2364 pixelShader_ = 0;
2365 blendMode_ = BLEND_REPLACE;
2366 alphaToCoverage_ = false;
2367 colorWrite_ = true;
2368 cullMode_ = CULL_CCW;
2369 constantDepthBias_ = 0.0f;
2370 slopeScaledDepthBias_ = 0.0f;
2371 depthTestMode_ = CMP_LESSEQUAL;
2372 depthWrite_ = true;
2373 fillMode_ = FILL_SOLID;
2374 lineAntiAlias_ = false;
2375 scissorTest_ = false;
2376 scissorRect_ = IntRect::ZERO;
2377 stencilTest_ = false;
2378 stencilTestMode_ = CMP_ALWAYS;
2379 stencilPass_ = OP_KEEP;
2380 stencilFail_ = OP_KEEP;
2381 stencilZFail_ = OP_KEEP;
2382 stencilRef_ = 0;
2383 stencilCompareMask_ = M_MAX_UNSIGNED;
2384 stencilWriteMask_ = M_MAX_UNSIGNED;
2385 useClipPlane_ = false;
2386 impl_->shaderProgram_ = 0;
2387 impl_->renderTargetsDirty_ = true;
2388 impl_->texturesDirty_ = true;
2389 impl_->vertexDeclarationDirty_ = true;
2390 impl_->blendStateDirty_ = true;
2391 impl_->depthStateDirty_ = true;
2392 impl_->rasterizerStateDirty_ = true;
2393 impl_->scissorRectDirty_ = true;
2394 impl_->stencilRefDirty_ = true;
2395 impl_->blendStateHash_ = M_MAX_UNSIGNED;
2396 impl_->depthStateHash_ = M_MAX_UNSIGNED;
2397 impl_->rasterizerStateHash_ = M_MAX_UNSIGNED;
2398 impl_->firstDirtyTexture_ = impl_->lastDirtyTexture_ = M_MAX_UNSIGNED;
2399 impl_->firstDirtyVB_ = impl_->lastDirtyVB_ = M_MAX_UNSIGNED;
2400 impl_->dirtyConstantBuffers_.Clear();
2401 }
2402
PrepareDraw()2403 void Graphics::PrepareDraw()
2404 {
2405 if (impl_->renderTargetsDirty_)
2406 {
2407 impl_->depthStencilView_ =
2408 (depthStencil_ && depthStencil_->GetUsage() == TEXTURE_DEPTHSTENCIL) ?
2409 (ID3D11DepthStencilView*)depthStencil_->GetRenderTargetView() : impl_->defaultDepthStencilView_;
2410
2411 // If possible, bind a read-only depth stencil view to allow reading depth in shader
2412 if (!depthWrite_ && depthStencil_ && depthStencil_->GetReadOnlyView())
2413 impl_->depthStencilView_ = (ID3D11DepthStencilView*)depthStencil_->GetReadOnlyView();
2414
2415 for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
2416 impl_->renderTargetViews_[i] =
2417 (renderTargets_[i] && renderTargets_[i]->GetUsage() == TEXTURE_RENDERTARGET) ?
2418 (ID3D11RenderTargetView*)renderTargets_[i]->GetRenderTargetView() : 0;
2419 // If rendertarget 0 is null and not doing depth-only rendering, render to the backbuffer
2420 // Special case: if rendertarget 0 is null and depth stencil has same size as backbuffer, assume the intention is to do
2421 // backbuffer rendering with a custom depth stencil
2422 if (!renderTargets_[0] &&
2423 (!depthStencil_ || (depthStencil_ && depthStencil_->GetWidth() == width_ && depthStencil_->GetHeight() == height_)))
2424 impl_->renderTargetViews_[0] = impl_->defaultRenderTargetView_;
2425
2426 impl_->deviceContext_->OMSetRenderTargets(MAX_RENDERTARGETS, &impl_->renderTargetViews_[0], impl_->depthStencilView_);
2427 impl_->renderTargetsDirty_ = false;
2428 }
2429
2430 if (impl_->texturesDirty_ && impl_->firstDirtyTexture_ < M_MAX_UNSIGNED)
2431 {
2432 // Set also VS textures to enable vertex texture fetch to work the same way as on OpenGL
2433 impl_->deviceContext_->VSSetShaderResources(impl_->firstDirtyTexture_, impl_->lastDirtyTexture_ - impl_->firstDirtyTexture_ + 1,
2434 &impl_->shaderResourceViews_[impl_->firstDirtyTexture_]);
2435 impl_->deviceContext_->VSSetSamplers(impl_->firstDirtyTexture_, impl_->lastDirtyTexture_ - impl_->firstDirtyTexture_ + 1,
2436 &impl_->samplers_[impl_->firstDirtyTexture_]);
2437 impl_->deviceContext_->PSSetShaderResources(impl_->firstDirtyTexture_, impl_->lastDirtyTexture_ - impl_->firstDirtyTexture_ + 1,
2438 &impl_->shaderResourceViews_[impl_->firstDirtyTexture_]);
2439 impl_->deviceContext_->PSSetSamplers(impl_->firstDirtyTexture_, impl_->lastDirtyTexture_ - impl_->firstDirtyTexture_ + 1,
2440 &impl_->samplers_[impl_->firstDirtyTexture_]);
2441
2442 impl_->firstDirtyTexture_ = impl_->lastDirtyTexture_ = M_MAX_UNSIGNED;
2443 impl_->texturesDirty_ = false;
2444 }
2445
2446 if (impl_->vertexDeclarationDirty_ && vertexShader_ && vertexShader_->GetByteCode().Size())
2447 {
2448 if (impl_->firstDirtyVB_ < M_MAX_UNSIGNED)
2449 {
2450 impl_->deviceContext_->IASetVertexBuffers(impl_->firstDirtyVB_, impl_->lastDirtyVB_ - impl_->firstDirtyVB_ + 1,
2451 &impl_->vertexBuffers_[impl_->firstDirtyVB_], &impl_->vertexSizes_[impl_->firstDirtyVB_], &impl_->vertexOffsets_[impl_->firstDirtyVB_]);
2452
2453 impl_->firstDirtyVB_ = impl_->lastDirtyVB_ = M_MAX_UNSIGNED;
2454 }
2455
2456 unsigned long long newVertexDeclarationHash = 0;
2457 for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i)
2458 {
2459 if (vertexBuffers_[i])
2460 newVertexDeclarationHash |= vertexBuffers_[i]->GetBufferHash(i);
2461 }
2462 // Do not create input layout if no vertex buffers / elements
2463 if (newVertexDeclarationHash)
2464 {
2465 /// \todo Using a 64bit total hash for vertex shader and vertex buffer elements hash may not guarantee uniqueness
2466 newVertexDeclarationHash += vertexShader_->GetElementHash();
2467 if (newVertexDeclarationHash != vertexDeclarationHash_)
2468 {
2469 VertexDeclarationMap::Iterator i =
2470 impl_->vertexDeclarations_.Find(newVertexDeclarationHash);
2471 if (i == impl_->vertexDeclarations_.End())
2472 {
2473 SharedPtr<VertexDeclaration> newVertexDeclaration(new VertexDeclaration(this, vertexShader_, vertexBuffers_));
2474 i = impl_->vertexDeclarations_.Insert(MakePair(newVertexDeclarationHash, newVertexDeclaration));
2475 }
2476 impl_->deviceContext_->IASetInputLayout((ID3D11InputLayout*)i->second_->GetInputLayout());
2477 vertexDeclarationHash_ = newVertexDeclarationHash;
2478 }
2479 }
2480
2481 impl_->vertexDeclarationDirty_ = false;
2482 }
2483
2484 if (impl_->blendStateDirty_)
2485 {
2486 unsigned newBlendStateHash = (unsigned)((colorWrite_ ? 1 : 0) | (alphaToCoverage_ ? 2 : 0) | (blendMode_ << 2));
2487 if (newBlendStateHash != impl_->blendStateHash_)
2488 {
2489 HashMap<unsigned, ID3D11BlendState*>::Iterator i = impl_->blendStates_.Find(newBlendStateHash);
2490 if (i == impl_->blendStates_.End())
2491 {
2492 URHO3D_PROFILE(CreateBlendState);
2493
2494 D3D11_BLEND_DESC stateDesc;
2495 memset(&stateDesc, 0, sizeof stateDesc);
2496 stateDesc.AlphaToCoverageEnable = alphaToCoverage_ ? TRUE : FALSE;
2497 stateDesc.IndependentBlendEnable = false;
2498 stateDesc.RenderTarget[0].BlendEnable = d3dBlendEnable[blendMode_];
2499 stateDesc.RenderTarget[0].SrcBlend = d3dSrcBlend[blendMode_];
2500 stateDesc.RenderTarget[0].DestBlend = d3dDestBlend[blendMode_];
2501 stateDesc.RenderTarget[0].BlendOp = d3dBlendOp[blendMode_];
2502 stateDesc.RenderTarget[0].SrcBlendAlpha = d3dSrcBlend[blendMode_];
2503 stateDesc.RenderTarget[0].DestBlendAlpha = d3dDestBlend[blendMode_];
2504 stateDesc.RenderTarget[0].BlendOpAlpha = d3dBlendOp[blendMode_];
2505 stateDesc.RenderTarget[0].RenderTargetWriteMask = colorWrite_ ? D3D11_COLOR_WRITE_ENABLE_ALL : 0x0;
2506
2507 ID3D11BlendState* newBlendState = 0;
2508 HRESULT hr = impl_->device_->CreateBlendState(&stateDesc, &newBlendState);
2509 if (FAILED(hr))
2510 {
2511 URHO3D_SAFE_RELEASE(newBlendState);
2512 URHO3D_LOGD3DERROR("Failed to create blend state", hr);
2513 }
2514
2515 i = impl_->blendStates_.Insert(MakePair(newBlendStateHash, newBlendState));
2516 }
2517
2518 impl_->deviceContext_->OMSetBlendState(i->second_, 0, M_MAX_UNSIGNED);
2519 impl_->blendStateHash_ = newBlendStateHash;
2520 }
2521
2522 impl_->blendStateDirty_ = false;
2523 }
2524
2525 if (impl_->depthStateDirty_)
2526 {
2527 unsigned newDepthStateHash =
2528 (depthWrite_ ? 1 : 0) | (stencilTest_ ? 2 : 0) | (depthTestMode_ << 2) | ((stencilCompareMask_ & 0xff) << 5) |
2529 ((stencilWriteMask_ & 0xff) << 13) | (stencilTestMode_ << 21) |
2530 ((stencilFail_ + stencilZFail_ * 5 + stencilPass_ * 25) << 24);
2531 if (newDepthStateHash != impl_->depthStateHash_ || impl_->stencilRefDirty_)
2532 {
2533 HashMap<unsigned, ID3D11DepthStencilState*>::Iterator i = impl_->depthStates_.Find(newDepthStateHash);
2534 if (i == impl_->depthStates_.End())
2535 {
2536 URHO3D_PROFILE(CreateDepthState);
2537
2538 D3D11_DEPTH_STENCIL_DESC stateDesc;
2539 memset(&stateDesc, 0, sizeof stateDesc);
2540 stateDesc.DepthEnable = TRUE;
2541 stateDesc.DepthWriteMask = depthWrite_ ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
2542 stateDesc.DepthFunc = d3dCmpFunc[depthTestMode_];
2543 stateDesc.StencilEnable = stencilTest_ ? TRUE : FALSE;
2544 stateDesc.StencilReadMask = (unsigned char)stencilCompareMask_;
2545 stateDesc.StencilWriteMask = (unsigned char)stencilWriteMask_;
2546 stateDesc.FrontFace.StencilFailOp = d3dStencilOp[stencilFail_];
2547 stateDesc.FrontFace.StencilDepthFailOp = d3dStencilOp[stencilZFail_];
2548 stateDesc.FrontFace.StencilPassOp = d3dStencilOp[stencilPass_];
2549 stateDesc.FrontFace.StencilFunc = d3dCmpFunc[stencilTestMode_];
2550 stateDesc.BackFace.StencilFailOp = d3dStencilOp[stencilFail_];
2551 stateDesc.BackFace.StencilDepthFailOp = d3dStencilOp[stencilZFail_];
2552 stateDesc.BackFace.StencilPassOp = d3dStencilOp[stencilPass_];
2553 stateDesc.BackFace.StencilFunc = d3dCmpFunc[stencilTestMode_];
2554
2555 ID3D11DepthStencilState* newDepthState = 0;
2556 HRESULT hr = impl_->device_->CreateDepthStencilState(&stateDesc, &newDepthState);
2557 if (FAILED(hr))
2558 {
2559 URHO3D_SAFE_RELEASE(newDepthState);
2560 URHO3D_LOGD3DERROR("Failed to create depth state", hr);
2561 }
2562
2563 i = impl_->depthStates_.Insert(MakePair(newDepthStateHash, newDepthState));
2564 }
2565
2566 impl_->deviceContext_->OMSetDepthStencilState(i->second_, stencilRef_);
2567 impl_->depthStateHash_ = newDepthStateHash;
2568 }
2569
2570 impl_->depthStateDirty_ = false;
2571 impl_->stencilRefDirty_ = false;
2572 }
2573
2574 if (impl_->rasterizerStateDirty_)
2575 {
2576 unsigned depthBits = 24;
2577 if (depthStencil_ && depthStencil_->GetParentTexture()->GetFormat() == DXGI_FORMAT_R16_TYPELESS)
2578 depthBits = 16;
2579 int scaledDepthBias = (int)(constantDepthBias_ * (1 << depthBits));
2580
2581 unsigned newRasterizerStateHash =
2582 (scissorTest_ ? 1 : 0) | (lineAntiAlias_ ? 2 : 0) | (fillMode_ << 2) | (cullMode_ << 4) |
2583 ((scaledDepthBias & 0x1fff) << 6) | (((int)(slopeScaledDepthBias_ * 100.0f) & 0x1fff) << 19);
2584 if (newRasterizerStateHash != impl_->rasterizerStateHash_)
2585 {
2586 HashMap<unsigned, ID3D11RasterizerState*>::Iterator i = impl_->rasterizerStates_.Find(newRasterizerStateHash);
2587 if (i == impl_->rasterizerStates_.End())
2588 {
2589 URHO3D_PROFILE(CreateRasterizerState);
2590
2591 D3D11_RASTERIZER_DESC stateDesc;
2592 memset(&stateDesc, 0, sizeof stateDesc);
2593 stateDesc.FillMode = d3dFillMode[fillMode_];
2594 stateDesc.CullMode = d3dCullMode[cullMode_];
2595 stateDesc.FrontCounterClockwise = FALSE;
2596 stateDesc.DepthBias = scaledDepthBias;
2597 stateDesc.DepthBiasClamp = M_INFINITY;
2598 stateDesc.SlopeScaledDepthBias = slopeScaledDepthBias_;
2599 stateDesc.DepthClipEnable = TRUE;
2600 stateDesc.ScissorEnable = scissorTest_ ? TRUE : FALSE;
2601 stateDesc.MultisampleEnable = lineAntiAlias_ ? FALSE : TRUE;
2602 stateDesc.AntialiasedLineEnable = lineAntiAlias_ ? TRUE : FALSE;
2603
2604 ID3D11RasterizerState* newRasterizerState = 0;
2605 HRESULT hr = impl_->device_->CreateRasterizerState(&stateDesc, &newRasterizerState);
2606 if (FAILED(hr))
2607 {
2608 URHO3D_SAFE_RELEASE(newRasterizerState);
2609 URHO3D_LOGD3DERROR("Failed to create rasterizer state", hr);
2610 }
2611
2612 i = impl_->rasterizerStates_.Insert(MakePair(newRasterizerStateHash, newRasterizerState));
2613 }
2614
2615 impl_->deviceContext_->RSSetState(i->second_);
2616 impl_->rasterizerStateHash_ = newRasterizerStateHash;
2617 }
2618
2619 impl_->rasterizerStateDirty_ = false;
2620 }
2621
2622 if (impl_->scissorRectDirty_)
2623 {
2624 D3D11_RECT d3dRect;
2625 d3dRect.left = scissorRect_.left_;
2626 d3dRect.top = scissorRect_.top_;
2627 d3dRect.right = scissorRect_.right_;
2628 d3dRect.bottom = scissorRect_.bottom_;
2629 impl_->deviceContext_->RSSetScissorRects(1, &d3dRect);
2630 impl_->scissorRectDirty_ = false;
2631 }
2632
2633 for (unsigned i = 0; i < impl_->dirtyConstantBuffers_.Size(); ++i)
2634 impl_->dirtyConstantBuffers_[i]->Apply();
2635 impl_->dirtyConstantBuffers_.Clear();
2636 }
2637
CreateResolveTexture()2638 void Graphics::CreateResolveTexture()
2639 {
2640 if (impl_->resolveTexture_)
2641 return;
2642
2643 D3D11_TEXTURE2D_DESC textureDesc;
2644 memset(&textureDesc, 0, sizeof textureDesc);
2645 textureDesc.Width = (UINT)width_;
2646 textureDesc.Height = (UINT)height_;
2647 textureDesc.MipLevels = 1;
2648 textureDesc.ArraySize = 1;
2649 textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
2650 textureDesc.SampleDesc.Count = 1;
2651 textureDesc.SampleDesc.Quality = 0;
2652 textureDesc.Usage = D3D11_USAGE_DEFAULT;
2653 textureDesc.CPUAccessFlags = 0;
2654
2655 HRESULT hr = impl_->device_->CreateTexture2D(&textureDesc, 0, &impl_->resolveTexture_);
2656 if (FAILED(hr))
2657 {
2658 URHO3D_SAFE_RELEASE(impl_->resolveTexture_);
2659 URHO3D_LOGD3DERROR("Could not create resolve texture", hr);
2660 }
2661 }
2662
SetTextureUnitMappings()2663 void Graphics::SetTextureUnitMappings()
2664 {
2665 textureUnits_["DiffMap"] = TU_DIFFUSE;
2666 textureUnits_["DiffCubeMap"] = TU_DIFFUSE;
2667 textureUnits_["NormalMap"] = TU_NORMAL;
2668 textureUnits_["SpecMap"] = TU_SPECULAR;
2669 textureUnits_["EmissiveMap"] = TU_EMISSIVE;
2670 textureUnits_["EnvMap"] = TU_ENVIRONMENT;
2671 textureUnits_["EnvCubeMap"] = TU_ENVIRONMENT;
2672 textureUnits_["LightRampMap"] = TU_LIGHTRAMP;
2673 textureUnits_["LightSpotMap"] = TU_LIGHTSHAPE;
2674 textureUnits_["LightCubeMap"] = TU_LIGHTSHAPE;
2675 textureUnits_["ShadowMap"] = TU_SHADOWMAP;
2676 textureUnits_["FaceSelectCubeMap"] = TU_FACESELECT;
2677 textureUnits_["IndirectionCubeMap"] = TU_INDIRECTION;
2678 textureUnits_["VolumeMap"] = TU_VOLUMEMAP;
2679 textureUnits_["ZoneCubeMap"] = TU_ZONE;
2680 textureUnits_["ZoneVolumeMap"] = TU_ZONE;
2681 }
2682
2683 }
2684