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