diff options
Diffstat (limited to 'xbmc/guilib/D3DResource.cpp')
-rw-r--r-- | xbmc/guilib/D3DResource.cpp | 1244 |
1 files changed, 1244 insertions, 0 deletions
diff --git a/xbmc/guilib/D3DResource.cpp b/xbmc/guilib/D3DResource.cpp new file mode 100644 index 0000000..0f1dc89 --- /dev/null +++ b/xbmc/guilib/D3DResource.cpp @@ -0,0 +1,1244 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "D3DResource.h" + +#include "GUIShaderDX.h" +#include "filesystem/File.h" +#include "rendering/dx/DeviceResources.h" +#include "rendering/dx/RenderContext.h" +#include "utils/log.h" + +#include <d3dcompiler.h> + +using namespace DirectX; +using namespace Microsoft::WRL; + +#ifdef TARGET_WINDOWS_DESKTOP +#pragma comment(lib, "d3dcompiler.lib") +#endif + +size_t CD3DHelper::BitsPerPixel(DXGI_FORMAT fmt) +{ + switch (fmt) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return 128; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return 96; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return 64; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return 32; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B4G4R4A4_UNORM: + return 16; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + return 8; + + case DXGI_FORMAT_R1_UNORM: + return 1; + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + return 4; + + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return 8; + + default: + return 0; + } +} + +void ID3DResource::Register() +{ + if (!m_bRegistered) + DX::Windowing()->Register(this); + m_bRegistered = true; +} + +void ID3DResource::Unregister() +{ + if (m_bRegistered) + DX::Windowing()->Unregister(this); + m_bRegistered = false; +} + +CD3DTexture::CD3DTexture() +{ + m_width = 0; + m_height = 0; + m_mipLevels = 0; + m_usage = D3D11_USAGE_DEFAULT; + m_format = DXGI_FORMAT_B8G8R8A8_UNORM; + m_texture = nullptr; + m_renderTargets[0] = nullptr; + m_renderTargets[1] = nullptr; + m_data = nullptr; + m_pitch = 0; + m_bindFlags = 0; + m_cpuFlags = 0; + m_viewIdx = 0; + m_views.clear(); +} + +CD3DTexture::~CD3DTexture() +{ + Release(); + delete[] m_data; +} + +bool CD3DTexture::Create(UINT width, UINT height, UINT mipLevels, D3D11_USAGE usage, DXGI_FORMAT format, const void* pixels /* nullptr */, unsigned int srcPitch /* 0 */) +{ + m_width = width; + m_height = height; + m_mipLevels = mipLevels; + // create the texture + Release(); + + if (format == DXGI_FORMAT_UNKNOWN) + format = DXGI_FORMAT_B8G8R8A8_UNORM; // DXGI_FORMAT_UNKNOWN + + if (!DX::Windowing()->IsFormatSupport(format, D3D11_FORMAT_SUPPORT_TEXTURE2D)) + { + CLog::LogF(LOGERROR, "unsupported texture format {}", format); + return false; + } + + m_cpuFlags = 0; + if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING) + { + m_cpuFlags |= D3D11_CPU_ACCESS_WRITE; + if (usage == D3D11_USAGE_STAGING) + m_cpuFlags |= D3D11_CPU_ACCESS_READ; + } + + m_format = format; + m_usage = usage; + + m_bindFlags = 0; // D3D11_BIND_SHADER_RESOURCE; + if (D3D11_USAGE_DEFAULT == usage && DX::Windowing()->IsFormatSupport(format, D3D11_FORMAT_SUPPORT_RENDER_TARGET)) + m_bindFlags |= D3D11_BIND_RENDER_TARGET; + if ( D3D11_USAGE_STAGING != m_usage ) + { + if (DX::Windowing()->IsFormatSupport(format, D3D11_FORMAT_SUPPORT_SHADER_LOAD) + || DX::Windowing()->IsFormatSupport(format, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) + { + m_bindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + if (DX::Windowing()->IsFormatSupport(format, D3D11_FORMAT_SUPPORT_DECODER_OUTPUT)) + { + m_bindFlags |= D3D11_BIND_DECODER; + } + } + + if (!CreateInternal(pixels, srcPitch)) + { + CLog::LogF(LOGERROR, "failed to create texture."); + return false; + } + + Register(); + + return true; +} + +bool CD3DTexture::CreateInternal(const void* pixels /* nullptr */, unsigned int srcPitch /* 0 */) +{ + ComPtr<ID3D11Device> pD3DDevice = DX::DeviceResources::Get()->GetD3DDevice(); + ComPtr<ID3D11DeviceContext> pD3D11Context = DX::DeviceResources::Get()->GetD3DContext(); + + UINT miscFlags = 0; + bool autogenmm = false; + if (m_mipLevels == 0 && DX::Windowing()->IsFormatSupport(m_format, D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)) + { + autogenmm = pixels != nullptr; + miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS; + } + else + m_mipLevels = 1; + + CD3D11_TEXTURE2D_DESC textureDesc(m_format, m_width, m_height, 1, m_mipLevels, m_bindFlags, m_usage, m_cpuFlags, 1, 0, miscFlags); + D3D11_SUBRESOURCE_DATA initData = {}; + initData.pSysMem = pixels; + initData.SysMemPitch = srcPitch ? srcPitch : CD3DHelper::BitsPerPixel(m_format) * m_width / 8; + initData.SysMemSlicePitch = 0; + + HRESULT hr = pD3DDevice->CreateTexture2D(&textureDesc, (!autogenmm && pixels) ? &initData : nullptr, m_texture.ReleaseAndGetAddressOf()); + if (SUCCEEDED(hr) && autogenmm) + { + pD3D11Context->UpdateSubresource(m_texture.Get(), 0, nullptr, pixels, + (srcPitch ? srcPitch : CD3DHelper::BitsPerPixel(m_format) * m_width / 8), 0); + } + + if (autogenmm) + GenerateMipmaps(); + + return SUCCEEDED(hr); +} + +ID3D11ShaderResourceView* CD3DTexture::GetShaderResource(DXGI_FORMAT format /* = DXGI_FORMAT_UNKNOWN */) +{ + if (!m_texture) + return nullptr; + + if (format == DXGI_FORMAT_UNKNOWN) + format = m_format; + + if (!DX::Windowing()->IsFormatSupport(format, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE) + && !DX::Windowing()->IsFormatSupport(format, D3D11_FORMAT_SUPPORT_SHADER_LOAD)) + return nullptr; + + if (!m_views[format]) + { + ComPtr<ID3D11ShaderResourceView> view; + CD3D11_SHADER_RESOURCE_VIEW_DESC cSRVDesc(D3D11_SRV_DIMENSION_TEXTURE2D, format); + HRESULT hr = DX::DeviceResources::Get()->GetD3DDevice()->CreateShaderResourceView(m_texture.Get(), &cSRVDesc, view.GetAddressOf()); + if (SUCCEEDED(hr)) + m_views.insert_or_assign(format, view); + else + CLog::LogF(LOGWARNING, "cannot create texture view."); + } + + return m_views[format].Get(); +} + +ID3D11ShaderResourceView** CD3DTexture::GetAddressOfSRV(DXGI_FORMAT format) +{ + if (format == DXGI_FORMAT_UNKNOWN) + format = m_format; + + if (!m_views[format]) + GetShaderResource(format); + + return m_views[format].GetAddressOf(); +} + +ID3D11RenderTargetView* CD3DTexture::GetRenderTarget() +{ + return GetRenderTargetInternal(m_viewIdx); +} + +ID3D11RenderTargetView** CD3DTexture::GetAddressOfRTV() +{ + if (!m_renderTargets[m_viewIdx]) + GetRenderTargetInternal(m_viewIdx); + return m_renderTargets[m_viewIdx].GetAddressOf(); +} + +void CD3DTexture::Release() +{ + Unregister(); + + m_views.clear(); + m_renderTargets[0] = nullptr; + m_renderTargets[1] = nullptr; + m_texture = nullptr; +} + +bool CD3DTexture::GetDesc(D3D11_TEXTURE2D_DESC *desc) const +{ + if (m_texture) + { + m_texture->GetDesc(desc); + return true; + } + return false; +} + +bool CD3DTexture::LockRect(UINT subresource, D3D11_MAPPED_SUBRESOURCE *res, D3D11_MAP mapType) const +{ + if (m_texture) + { + if (m_usage == D3D11_USAGE_DEFAULT) + return false; + if ((mapType == D3D11_MAP_READ || mapType == D3D11_MAP_READ_WRITE) && m_usage == D3D11_USAGE_DYNAMIC) + return false; + + return (S_OK == DX::DeviceResources::Get()->GetImmediateContext()->Map(m_texture.Get(), subresource, mapType, 0, res)); + } + return false; +} + +bool CD3DTexture::UnlockRect(UINT subresource) const +{ + if (m_texture) + { + DX::DeviceResources::Get()->GetImmediateContext()->Unmap(m_texture.Get(), subresource); + return true; + } + return false; +} + +void CD3DTexture::SaveTexture() +{ + if (m_texture) + { + delete[] m_data; + m_data = nullptr; + + ID3D11DeviceContext* pContext = DX::DeviceResources::Get()->GetImmediateContext(); + + D3D11_TEXTURE2D_DESC textureDesc; + m_texture->GetDesc(&textureDesc); + + ComPtr<ID3D11Texture2D> texture = nullptr; + if (textureDesc.Usage != D3D11_USAGE_STAGING || 0 == (textureDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) + { + // create texture which can be readed by CPU - D3D11_USAGE_STAGING + CD3D11_TEXTURE2D_DESC stagingDesc(textureDesc); + stagingDesc.Usage = D3D11_USAGE_STAGING; + stagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingDesc.BindFlags = 0; + + if (FAILED(DX::DeviceResources::Get()->GetD3DDevice()->CreateTexture2D(&stagingDesc, NULL, &texture))) + return; + + // copy contents to new texture + pContext->CopyResource(texture.Get(), m_texture.Get()); + } + else + texture = m_texture; + + // read data from texture + D3D11_MAPPED_SUBRESOURCE res; + if (SUCCEEDED(pContext->Map(texture.Get(), 0, D3D11_MAP_READ, 0, &res))) + { + m_pitch = res.RowPitch; + unsigned int memUsage = GetMemoryUsage(res.RowPitch); + m_data = new unsigned char[memUsage]; + memcpy(m_data, res.pData, memUsage); + pContext->Unmap(texture.Get(), 0); + } + else + CLog::LogF(LOGERROR, "Failed to store resource."); + } +} + +void CD3DTexture::OnDestroyDevice(bool fatal) +{ + if (!fatal) + SaveTexture(); + m_views.clear(); + m_renderTargets[0] = nullptr; + m_renderTargets[1] = nullptr; + m_texture = nullptr; +} + +void CD3DTexture::RestoreTexture() +{ + // yay, we're back - make a new copy of the texture + if (!m_texture && m_data) + { + if (!CreateInternal(m_data, m_pitch)) + { + CLog::LogF(LOGERROR, "failed restore texture"); + } + + delete[] m_data; + m_data = NULL; + m_pitch = 0; + } +} + +void CD3DTexture::OnCreateDevice() +{ + RestoreTexture(); +} + +ID3D11RenderTargetView* CD3DTexture::GetRenderTargetInternal(unsigned idx) +{ + if (idx > 1) + return nullptr; + + if (!m_texture) + return nullptr; + + if (!DX::Windowing()->IsFormatSupport(m_format, D3D11_FORMAT_SUPPORT_RENDER_TARGET)) + return nullptr; + + if (!m_renderTargets[idx]) + { + CD3D11_RENDER_TARGET_VIEW_DESC cRTVDesc(D3D11_RTV_DIMENSION_TEXTURE2DARRAY, DXGI_FORMAT_UNKNOWN, 0, idx, 1); + if (FAILED(DX::DeviceResources::Get()->GetD3DDevice()->CreateRenderTargetView(m_texture.Get(), &cRTVDesc, m_renderTargets[idx].ReleaseAndGetAddressOf()))) + { + CLog::LogF(LOGWARNING, "cannot create texture view."); + } + } + + return m_renderTargets[idx].Get(); +} + +unsigned int CD3DTexture::GetMemoryUsage(unsigned int pitch) const +{ + switch (m_format) + { + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC3_UNORM: + return pitch * m_height / 4; + default: + return pitch * m_height; + } +} + +void CD3DTexture::GenerateMipmaps() +{ + if (m_mipLevels == 0) + { + ID3D11ShaderResourceView* pSRView = GetShaderResource(); + if (pSRView != nullptr) + DX::DeviceResources::Get()->GetD3DContext()->GenerateMips(pSRView); + } +} + +// static methods +void CD3DTexture::DrawQuad(const CPoint points[4], + UTILS::COLOR::Color color, + CD3DTexture* texture, + const CRect* texCoords, + SHADER_METHOD options) +{ + unsigned numViews = 0; + ID3D11ShaderResourceView* views = nullptr; + + if (texture) + { + numViews = 1; + views = texture->GetShaderResource(); + } + + DrawQuad(points, color, numViews, &views, texCoords, options); +} + +void CD3DTexture::DrawQuad(const CRect& rect, + UTILS::COLOR::Color color, + CD3DTexture* texture, + const CRect* texCoords, + SHADER_METHOD options) +{ + CPoint points[] = + { + { rect.x1, rect.y1 }, + { rect.x2, rect.y1 }, + { rect.x2, rect.y2 }, + { rect.x1, rect.y2 }, + }; + DrawQuad(points, color, texture, texCoords, options); +} + +void CD3DTexture::DrawQuad(const CPoint points[4], + UTILS::COLOR::Color color, + unsigned numViews, + ID3D11ShaderResourceView** view, + const CRect* texCoords, + SHADER_METHOD options) +{ + XMFLOAT4 xcolor; + CD3DHelper::XMStoreColor(&xcolor, color); + CRect coords = texCoords ? *texCoords : CRect(0.0f, 0.0f, 1.0f, 1.0f); + + Vertex verts[4] = { + { XMFLOAT3(points[0].x, points[0].y, 0), xcolor, XMFLOAT2(coords.x1, coords.y1), XMFLOAT2(0.0f, 0.0f) }, + { XMFLOAT3(points[1].x, points[1].y, 0), xcolor, XMFLOAT2(coords.x2, coords.y1), XMFLOAT2(0.0f, 0.0f) }, + { XMFLOAT3(points[2].x, points[2].y, 0), xcolor, XMFLOAT2(coords.x2, coords.y2), XMFLOAT2(0.0f, 0.0f) }, + { XMFLOAT3(points[3].x, points[3].y, 0), xcolor, XMFLOAT2(coords.x1, coords.y2), XMFLOAT2(0.0f, 0.0f) }, + }; + + CGUIShaderDX* pGUIShader = DX::Windowing()->GetGUIShader(); + + pGUIShader->Begin(view && numViews > 0 ? options : SHADER_METHOD_RENDER_DEFAULT); + if (view && numViews > 0) + pGUIShader->SetShaderViews(numViews, view); + pGUIShader->DrawQuad(verts[0], verts[1], verts[2], verts[3]); +} + +void CD3DTexture::DrawQuad(const CRect& rect, + UTILS::COLOR::Color color, + unsigned numViews, + ID3D11ShaderResourceView** view, + const CRect* texCoords, + SHADER_METHOD options) +{ + CPoint points[] = + { + { rect.x1, rect.y1 }, + { rect.x2, rect.y1 }, + { rect.x2, rect.y2 }, + { rect.x1, rect.y2 }, + }; + DrawQuad(points, color, numViews, view, texCoords, options); +} + +CD3DEffect::CD3DEffect() +{ + m_effect = nullptr; + m_techniquie = nullptr; + m_currentPass = nullptr; +} + +CD3DEffect::~CD3DEffect() +{ + Release(); +} + +bool CD3DEffect::Create(const std::string &effectString, DefinesMap* defines) +{ + Release(); + m_effectString = effectString; + m_defines.clear(); + if (defines != nullptr) + m_defines = *defines; //FIXME: is this a copy of all members? + if (CreateEffect()) + { + Register(); + return true; + } + return false; +} + +void CD3DEffect::Release() +{ + Unregister(); + OnDestroyDevice(false); +} + +void CD3DEffect::OnDestroyDevice(bool fatal) +{ + m_effect = nullptr; + m_techniquie = nullptr; + m_currentPass = nullptr; +} + +void CD3DEffect::OnCreateDevice() +{ + CreateEffect(); +} + +HRESULT CD3DEffect::Open(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) +{ + XFILE::CFile includeFile; + + std::string fileName("special://xbmc/system/shaders/"); + fileName.append(pFileName); + + if (!includeFile.Open(fileName)) + { + CLog::LogF(LOGERROR, "Could not open 3DLUT file: {}", fileName); + return E_FAIL; + } + + int64_t length = includeFile.GetLength(); + void *pData = malloc(length); + if (includeFile.Read(pData, length) != length) + { + free(pData); + return E_FAIL; + } + *ppData = pData; + *pBytes = length; + + return S_OK; +} + +HRESULT CD3DEffect::Close(LPCVOID pData) +{ + free((void*)pData); + return S_OK; +} + +bool CD3DEffect::SetFloatArray(LPCSTR handle, const float* val, unsigned int count) +{ + if (m_effect) + { + return S_OK == m_effect->GetVariableByName(handle)->SetRawValue(val, 0, sizeof(float) * count); + } + return false; +} + +bool CD3DEffect::SetMatrix(LPCSTR handle, const float* mat) +{ + if (m_effect) + { + return S_OK == m_effect->GetVariableByName(handle)->AsMatrix()->SetMatrix(mat); + } + return false; +} + +bool CD3DEffect::SetTechnique(LPCSTR handle) +{ + if (m_effect) + { + m_techniquie = m_effect->GetTechniqueByName(handle); + if (!m_techniquie->IsValid()) + m_techniquie = nullptr; + + return nullptr != m_techniquie; + } + return false; +} + +bool CD3DEffect::SetTexture(LPCSTR handle, CD3DTexture &texture) +{ + if (m_effect) + { + ID3DX11EffectShaderResourceVariable* var = m_effect->GetVariableByName(handle)->AsShaderResource(); + if (var->IsValid()) + return SUCCEEDED(var->SetResource(texture.GetShaderResource())); + } + return false; +} + +bool CD3DEffect::SetResources(LPCSTR handle, ID3D11ShaderResourceView** ppSRViews, size_t count) +{ + if (m_effect) + { + ID3DX11EffectShaderResourceVariable* var = m_effect->GetVariableByName(handle)->AsShaderResource(); + if (var->IsValid()) + return SUCCEEDED(var->SetResourceArray(ppSRViews, 0, count)); + } + return false; +} + +bool CD3DEffect::SetConstantBuffer(LPCSTR handle, ID3D11Buffer *buffer) +{ + if (m_effect) + { + ID3DX11EffectConstantBuffer* effectbuffer = m_effect->GetConstantBufferByName(handle); + if (effectbuffer->IsValid()) + return (S_OK == effectbuffer->SetConstantBuffer(buffer)); + } + return false; +} + +bool CD3DEffect::SetScalar(LPCSTR handle, float value) +{ + if (m_effect) + { + ID3DX11EffectScalarVariable* scalar = m_effect->GetVariableByName(handle)->AsScalar(); + if (scalar->IsValid()) + return (S_OK == scalar->SetFloat(value)); + } + + return false; +} + +bool CD3DEffect::Begin(UINT *passes, DWORD flags) +{ + if (m_effect && m_techniquie) + { + D3DX11_TECHNIQUE_DESC desc = {}; + HRESULT hr = m_techniquie->GetDesc(&desc); + *passes = desc.Passes; + return S_OK == hr; + } + return false; +} + +bool CD3DEffect::BeginPass(UINT pass) +{ + if (m_effect && m_techniquie) + { + m_currentPass = m_techniquie->GetPassByIndex(pass); + if (!m_currentPass || !m_currentPass->IsValid()) + { + m_currentPass = nullptr; + return false; + } + return (S_OK == m_currentPass->Apply(0, DX::DeviceResources::Get()->GetD3DContext())); + } + return false; +} + +bool CD3DEffect::EndPass() +{ + if (m_effect && m_currentPass) + { + m_currentPass = nullptr; + return true; + } + return false; +} + +bool CD3DEffect::End() +{ + if (m_effect && m_techniquie) + { + m_techniquie = nullptr; + return true; + } + return false; +} + +bool CD3DEffect::CreateEffect() +{ + HRESULT hr; + ID3DBlob* pError = nullptr; + + std::vector<D3D_SHADER_MACRO> definemacros; + + for (const auto& it : m_defines) + { + D3D_SHADER_MACRO m; + m.Name = it.first.c_str(); + if (it.second.empty()) + m.Definition = nullptr; + else + m.Definition = it.second.c_str(); + definemacros.push_back( m ); + } + + definemacros.push_back(D3D_SHADER_MACRO()); + definemacros.back().Name = nullptr; + definemacros.back().Definition = nullptr; + + UINT dwShaderFlags = 0; + +#ifdef _DEBUG + //dwShaderFlags |= D3DCOMPILE_DEBUG; + // Disable optimizations to further improve shader debugging + //dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION; +#endif + + hr = D3DX11CompileEffectFromMemory(m_effectString.c_str(), m_effectString.length(), "", &definemacros[0], this, + dwShaderFlags, 0, DX::DeviceResources::Get()->GetD3DDevice(), m_effect.ReleaseAndGetAddressOf(), &pError); + + if(hr == S_OK) + return true; + else if(pError) + { + std::string error; + error.assign((const char*)pError->GetBufferPointer(), pError->GetBufferSize()); + CLog::Log(LOGERROR, "CD3DEffect::CreateEffect(): {}", error); + } + else + CLog::Log(LOGERROR, "CD3DEffect::CreateEffect(): call to D3DXCreateEffect() failed with {}", + hr); + return false; +} + +CD3DBuffer::CD3DBuffer() +{ + m_length = 0; + m_stride = 0; + m_usage = D3D11_USAGE_DEFAULT; + m_format = DXGI_FORMAT_UNKNOWN; + m_buffer = nullptr; + m_data = nullptr; +} + +CD3DBuffer::~CD3DBuffer() +{ + Release(); + delete[] m_data; +} + +bool CD3DBuffer::Create(D3D11_BIND_FLAG type, UINT count, UINT stride, DXGI_FORMAT format, D3D11_USAGE usage, const void* data) +{ + m_type = type; + m_stride = stride ? stride : CD3DHelper::BitsPerPixel(format); + m_format = format; + m_length = count * m_stride; + m_usage = usage; + m_cpuFlags = 0; + + if (m_usage == D3D11_USAGE_DYNAMIC || m_usage == D3D11_USAGE_STAGING) + { + m_cpuFlags |= D3D11_CPU_ACCESS_WRITE; + if (m_usage == D3D11_USAGE_STAGING) + m_cpuFlags |= D3D11_CPU_ACCESS_READ; + } + + Release(); + + // create the vertex buffer + if (CreateBuffer(data)) + { + Register(); + return true; + } + return false; +} + +void CD3DBuffer::Release() +{ + Unregister(); + m_buffer = nullptr; +} + +bool CD3DBuffer::Map(void **data) +{ + if (m_buffer) + { + D3D11_MAPPED_SUBRESOURCE resource; + if (SUCCEEDED(DX::DeviceResources::Get()->GetD3DContext()->Map(m_buffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &resource))) + { + *data = resource.pData; + return true; + } + } + return false; +} + +bool CD3DBuffer::Unmap() +{ + if (m_buffer) + { + DX::DeviceResources::Get()->GetD3DContext()->Unmap(m_buffer.Get(), 0); + return true; + } + return false; +} + +void CD3DBuffer::OnDestroyDevice(bool fatal) +{ + if (fatal) + { + m_buffer = nullptr; + return; + } + + ComPtr<ID3D11Device> pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + ComPtr<ID3D11DeviceContext> pContext = DX::DeviceResources::Get()->GetImmediateContext(); + + if (!pDevice || !pContext || !m_buffer) + return; + + D3D11_BUFFER_DESC srcDesc; + m_buffer->GetDesc(&srcDesc); + + ComPtr<ID3D11Buffer> buffer; + if (srcDesc.Usage != D3D11_USAGE_STAGING || 0 == (srcDesc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) + { + CD3D11_BUFFER_DESC trgDesc(srcDesc); + trgDesc.Usage = D3D11_USAGE_STAGING; + trgDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + trgDesc.BindFlags = 0; + + if (SUCCEEDED(pDevice->CreateBuffer(&trgDesc, NULL, &buffer))) + pContext->CopyResource(buffer.Get(), m_buffer.Get()); + } + else + buffer = m_buffer; + + if (buffer != nullptr) + { + D3D11_MAPPED_SUBRESOURCE res; + if (SUCCEEDED(pContext->Map(buffer.Get(), 0, D3D11_MAP_READ, 0, &res))) + { + m_data = new unsigned char[srcDesc.ByteWidth]; + memcpy(m_data, res.pData, srcDesc.ByteWidth); + pContext->Unmap(buffer.Get(), 0); + } + } + m_buffer = nullptr; +} + +void CD3DBuffer::OnCreateDevice() +{ + // yay, we're back - make a new copy of the vertices + if (!m_buffer && m_data) + { + CreateBuffer(m_data); + delete[] m_data; + m_data = nullptr; + } +} + +bool CD3DBuffer::CreateBuffer(const void* pData) +{ + CD3D11_BUFFER_DESC bDesc(m_length, m_type, m_usage, m_cpuFlags); + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = pData; + return (S_OK == DX::DeviceResources::Get()->GetD3DDevice()->CreateBuffer(&bDesc, (pData ? &initData : nullptr), m_buffer.ReleaseAndGetAddressOf())); +} + +/****************************************************/ +/* D3D Vertex Shader Class */ +/****************************************************/ +CD3DVertexShader::CD3DVertexShader() +{ + m_VS = nullptr; + m_vertexLayout = nullptr; + m_VSBuffer = nullptr; + m_inputLayout = nullptr; + m_vertexLayoutSize = 0; + m_inited = false; +} + +CD3DVertexShader::~CD3DVertexShader() +{ + Release(); +} + +void CD3DVertexShader::Release() +{ + Unregister(); + ReleaseShader(); + m_VSBuffer = nullptr; + if (m_vertexLayout) + { + delete[] m_vertexLayout; + m_vertexLayout = nullptr; + } +} + +void CD3DVertexShader::ReleaseShader() +{ + UnbindShader(); + + m_VS = nullptr; + m_inputLayout = nullptr; + m_inited = false; +} + +bool CD3DVertexShader::Create(const std::wstring& vertexFile, D3D11_INPUT_ELEMENT_DESC* vertexLayout, unsigned int vertexLayoutSize) +{ + ReleaseShader(); + + ComPtr<ID3D11Device> pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + + if (!pDevice) + return false; + + if (FAILED(D3DReadFileToBlob(vertexFile.c_str(), m_VSBuffer.ReleaseAndGetAddressOf()))) + { + CLog::LogF(LOGERROR, "failed to load the vertex shader."); + return false; + } + + if (vertexLayout && vertexLayoutSize) + { + m_vertexLayoutSize = vertexLayoutSize; + m_vertexLayout = new D3D11_INPUT_ELEMENT_DESC[vertexLayoutSize]; + for (unsigned int i = 0; i < vertexLayoutSize; ++i) + m_vertexLayout[i] = vertexLayout[i]; + } + else + return false; + + m_inited = CreateInternal(); + + if (m_inited) + Register(); + + return m_inited; +} + +bool CD3DVertexShader::Create(const void* code, size_t codeLength, D3D11_INPUT_ELEMENT_DESC* vertexLayout, unsigned int vertexLayoutSize) +{ + ReleaseShader(); + + ComPtr<ID3D11Device> pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + + if (!pDevice) + return false; + + // trick to load bytecode into ID3DBlob + if (FAILED(D3DStripShader(code, codeLength, D3DCOMPILER_STRIP_REFLECTION_DATA, m_VSBuffer.ReleaseAndGetAddressOf()))) + { + CLog::LogF(LOGERROR, "failed to load the vertex shader."); + return false; + } + + if (vertexLayout && vertexLayoutSize) + { + m_vertexLayoutSize = vertexLayoutSize; + m_vertexLayout = new D3D11_INPUT_ELEMENT_DESC[vertexLayoutSize]; + for (unsigned int i = 0; i < vertexLayoutSize; ++i) + m_vertexLayout[i] = vertexLayout[i]; + } + else + return false; + + m_inited = CreateInternal(); + + if (m_inited) + Register(); + + return m_inited; +} + +bool CD3DVertexShader::CreateInternal() +{ + ComPtr<ID3D11Device> pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + + CLog::LogF(LOGDEBUG, "creating vertex shader."); + + // Create the vertex shader + if (FAILED(pDevice->CreateVertexShader(m_VSBuffer->GetBufferPointer(), m_VSBuffer->GetBufferSize(), nullptr, m_VS.ReleaseAndGetAddressOf()))) + { + CLog::LogF(LOGERROR, "failed to Create the vertex shader."); + m_VSBuffer = nullptr; + return false; + } + + CLog::LogF(LOGDEBUG, "creating input layout."); + + if (FAILED(pDevice->CreateInputLayout(m_vertexLayout, m_vertexLayoutSize, m_VSBuffer->GetBufferPointer(), m_VSBuffer->GetBufferSize(), m_inputLayout.ReleaseAndGetAddressOf()))) + { + CLog::LogF(LOGERROR, "failed to create the input layout."); + return false; + } + + return true; +} + +void CD3DVertexShader::BindShader() +{ + if (!m_inited) + return; + + ComPtr<ID3D11DeviceContext> pContext = DX::DeviceResources::Get()->GetD3DContext(); + if (!pContext) + return; + + pContext->IASetInputLayout(m_inputLayout.Get()); + pContext->VSSetShader(m_VS.Get(), nullptr, 0); +} + +void CD3DVertexShader::UnbindShader() +{ + if (!m_inited) + return; + + ComPtr<ID3D11DeviceContext> pContext = DX::DeviceResources::Get()->GetD3DContext(); + pContext->IASetInputLayout(nullptr); + pContext->VSSetShader(nullptr, nullptr, 0); +} + +void CD3DVertexShader::OnCreateDevice() +{ + if (m_VSBuffer && !m_VS) + m_inited = CreateInternal(); +} + +void CD3DVertexShader::OnDestroyDevice(bool fatal) +{ + ReleaseShader(); +} + +/****************************************************/ +/* D3D Pixel Shader Class */ +/****************************************************/ +CD3DPixelShader::CD3DPixelShader() +{ + m_PS = nullptr; + m_PSBuffer = nullptr; + m_inited = false; +} + +CD3DPixelShader::~CD3DPixelShader() +{ + Release(); +} + +void CD3DPixelShader::Release() +{ + Unregister(); + ReleaseShader(); + m_PSBuffer = nullptr; +} + +void CD3DPixelShader::ReleaseShader() +{ + m_inited = false; + m_PS = nullptr; +} + +bool CD3DPixelShader::Create(const std::wstring& wstrFile) +{ + ReleaseShader(); + + ComPtr<ID3D11Device> pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + + if (!pDevice) + return false; + + if (FAILED(D3DReadFileToBlob(wstrFile.c_str(), m_PSBuffer.ReleaseAndGetAddressOf()))) + { + CLog::LogF(LOGERROR, "Failed to load the vertex shader."); + return false; + } + + m_inited = CreateInternal(); + + if (m_inited) + Register(); + + return m_inited; +} + +bool CD3DPixelShader::Create(const void* code, size_t codeLength) +{ + ReleaseShader(); + + ComPtr<ID3D11Device> pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + + if (!pDevice) + return false; + + // trick to load bytecode into ID3DBlob + if (FAILED(D3DStripShader(code, codeLength, D3DCOMPILER_STRIP_REFLECTION_DATA, m_PSBuffer.ReleaseAndGetAddressOf()))) + { + CLog::LogF(LOGERROR, "Failed to load the vertex shader."); + return false; + } + + m_inited = CreateInternal(); + + if (m_inited) + Register(); + + return m_inited; +} + +bool CD3DPixelShader::CreateInternal() +{ + ComPtr<ID3D11Device> pDevice = DX::DeviceResources::Get()->GetD3DDevice(); + + CLog::LogF(LOGDEBUG, "Create the pixel shader."); + + // Create the vertex shader + if (FAILED(pDevice->CreatePixelShader(m_PSBuffer->GetBufferPointer(), m_PSBuffer->GetBufferSize(), nullptr, m_PS.ReleaseAndGetAddressOf()))) + { + CLog::LogF(LOGERROR, "Failed to Create the pixel shader."); + m_PSBuffer = nullptr; + return false; + } + + return true; +} + +void CD3DPixelShader::BindShader() +{ + if (!m_inited) + return; + + ComPtr<ID3D11DeviceContext> pContext = DX::DeviceResources::Get()->GetD3DContext(); + if (!pContext) + return; + + pContext->PSSetShader(m_PS.Get(), nullptr, 0); +} + +void CD3DPixelShader::UnbindShader() +{ + if (!m_inited) + return; + + ComPtr<ID3D11DeviceContext> pContext = DX::DeviceResources::Get()->GetD3DContext(); + pContext->IASetInputLayout(nullptr); + pContext->VSSetShader(nullptr, nullptr, 0); +} + +void CD3DPixelShader::OnCreateDevice() +{ + if (m_PSBuffer && !m_PS) + m_inited = CreateInternal(); +} + +void CD3DPixelShader::OnDestroyDevice(bool fatal) +{ + ReleaseShader(); +} |