#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2013 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_GRAPHICS_SOURCE 1 #include "Direct3D11RenderTarget2Observer.h" #include "../Direct3D11RasterizerResources.h" #include #include namespace Nuclex { namespace Graphics { namespace Rasterization { // ------------------------------------------------------------------------------------------- // Direct3D11RenderTarget2Observer::Direct3D11RenderTarget2Observer( Direct3D11RasterizerResources &resources, RenderTarget2 *renderTarget2, const IDXGISwapChainNPtr &swapChain ) : resources(resources), renderTarget2(renderTarget2), swapChain(swapChain), renderTargetTexture(getTextureFromSwapChain(swapChain)) { createRenderTargetView(); createDepthBuffer(); createDepthView(); } // ------------------------------------------------------------------------------------------- // Direct3D11RenderTarget2Observer::Direct3D11RenderTarget2Observer( Direct3D11RasterizerResources &resources, RenderTarget2 *renderTarget2 ) : resources(resources), renderTarget2(renderTarget2) { using namespace std; assert("Creation of additional render targets is not implemented yet"); } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::Destroying() { this->resources.RenderTarget2Holder.Evict(this->renderTarget2, this); } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::Resized(std::size_t width, std::size_t height) { D3D11_TEXTURE2D_DESC textureDescription; this->renderTargetTexture->GetDesc(&textureDescription); bool sizeChanged = (static_cast(textureDescription.Width) != width) || (static_cast(textureDescription.Height) != height); // When the primary render target (associated with the swap chain) gets resized, // the size will already have been matched by RestoreAfterSwapChainRecreation(), so // this will only ever be entered for free render targets. if(sizeChanged) { using namespace std; assert("Creation of additional render targets is not implemented yet"); } } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::Cleared() { Cleared(Color::Black, 1.0f, 0); } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::Cleared(Color color, float depth, std::uint8_t stencil) { std::array floatColor = color.GetAsFloats(); this->resources.GetDeviceContext()->ClearRenderTargetView( this->renderTargetView, floatColor.data() ); this->resources.GetDeviceContext()->ClearDepthStencilView( this->depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, depth, stencil ); } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::Changed(const Box &) { throw std::runtime_error("Not implemented yet"); } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::Read(const Rectangle &, void *, std::size_t) { throw std::runtime_error("Not implemented yet"); } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::ShutdownForSwapChainRecreation() { this->depthStencilView = nullptr; this->depthStencilTexture = nullptr; this->renderTargetView = nullptr; this->renderTargetTexture = nullptr; } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::RestoreAfterSwapChainRecreation( std::size_t, std::size_t ) { this->renderTargetTexture = getTextureFromSwapChain(this->swapChain); // TODO: Tell the render target its new size // What if the render target has multiple observers? // Should size be an array? Or should GetSize() require a Rasterizer reference? // Or should the primary render target always return -1, -1 for its size? createRenderTargetView(); createDepthBuffer(); createDepthView(); } // ------------------------------------------------------------------------------------------- // ID3D11Texture2DPtr Direct3D11RenderTarget2Observer::getTextureFromSwapChain( const IDXGISwapChainNPtr &swapChain ) { void *backBufferAsVoid; HRESULT resultHandle = swapChain->GetBuffer(0, IID_ID3D11Texture2D, &backBufferAsVoid); if(FAILED(resultHandle)) { throw std::runtime_error("Could not retrieve back buffer texture from swap chain"); } bool addRef = false; // GetParent() has already called AddRef() return ID3D11Texture2DPtr(reinterpret_cast(backBufferAsVoid), addRef); } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::createRenderTargetView() { HRESULT resultHandle = this->resources.GetDevice()->CreateRenderTargetView( this->renderTargetTexture, nullptr, &this->renderTargetView ); if(FAILED(resultHandle)) { throw std::runtime_error("Could not create a view for the render target"); } } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::createDepthBuffer() { D3D11_TEXTURE2D_DESC textureDescription; this->renderTargetTexture->GetDesc(&textureDescription); D3D11_TEXTURE2D_DESC depthStencilDescription; depthStencilDescription.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthStencilDescription.Width = textureDescription.Width; depthStencilDescription.Height = textureDescription.Height; depthStencilDescription.ArraySize = 1; depthStencilDescription.MipLevels = 1; depthStencilDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL; depthStencilDescription.Usage = D3D11_USAGE_DEFAULT; depthStencilDescription.CPUAccessFlags = 0; depthStencilDescription.SampleDesc.Count = 1; depthStencilDescription.SampleDesc.Quality = 0; depthStencilDescription.MiscFlags = 0; HRESULT resultHandle = this->resources.GetDevice()->CreateTexture2D( &depthStencilDescription, nullptr, &this->depthStencilTexture ); if(FAILED(resultHandle)) { throw std::runtime_error("Could not create texture for depth and stencil buffer"); } } // ------------------------------------------------------------------------------------------- // void Direct3D11RenderTarget2Observer::createDepthView() { D3D11_DEPTH_STENCIL_VIEW_DESC depthViewDescription; depthViewDescription.Format = DXGI_FORMAT_UNKNOWN; depthViewDescription.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; depthViewDescription.Flags = 0; depthViewDescription.Texture2D.MipSlice = 0; HRESULT resultHandle = this->resources.GetDevice()->CreateDepthStencilView( this->depthStencilTexture, &depthViewDescription, &this->depthStencilView ); if(FAILED(resultHandle)) { throw std::runtime_error("Could not create a view for the depth and stencil buffer"); } } // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Graphics::Rasterization