From f244da86a2afbb688c79644cfbf95124eaa1b1d4 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 4 Nov 2019 00:39:25 +1000 Subject: [PATCH] Common: Add helper classes for D3D11 --- src/common/CMakeLists.txt | 58 ++++++----- src/common/common.vcxproj | 40 ++++++++ src/common/common.vcxproj.filters | 27 +++++ src/common/d3d11/shader_compiler.cpp | 142 +++++++++++++++++++++++++++ src/common/d3d11/shader_compiler.h | 25 +++++ src/common/d3d11/staging_texture.cpp | 91 +++++++++++++++++ src/common/d3d11/staging_texture.h | 100 +++++++++++++++++++ src/common/d3d11/stream_buffer.cpp | 88 +++++++++++++++++ src/common/d3d11/stream_buffer.h | 43 ++++++++ src/common/d3d11/texture.cpp | 130 ++++++++++++++++++++++++ src/common/d3d11/texture.h | 47 +++++++++ 11 files changed, 768 insertions(+), 23 deletions(-) create mode 100644 src/common/d3d11/shader_compiler.cpp create mode 100644 src/common/d3d11/shader_compiler.h create mode 100644 src/common/d3d11/staging_texture.cpp create mode 100644 src/common/d3d11/staging_texture.h create mode 100644 src/common/d3d11/stream_buffer.cpp create mode 100644 src/common/d3d11/stream_buffer.h create mode 100644 src/common/d3d11/texture.cpp create mode 100644 src/common/d3d11/texture.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index d441ae7d9..3c26c3615 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,28 +1,40 @@ -set(SRCS - audio_stream.cpp - audio_stream.h - bitfield.h - cd_image.cpp - cd_image.h - cd_image_bin.cpp - cd_image_cue.cpp - cd_xa.cpp - cd_xa.h - gl/program.cpp - gl/program.h - gl/stream_buffer.cpp - gl/stream_buffer.h - gl/texture.cpp - gl/texture.h - jit_code_buffer.cpp - jit_code_buffer.h - state_wrapper.cpp - state_wrapper.h +add_library(common + audio_stream.cpp + audio_stream.h + bitfield.h + cd_image.cpp + cd_image.h + cd_image_bin.cpp + cd_image_cue.cpp + cd_xa.cpp + cd_xa.h + gl/program.cpp + gl/program.h + gl/stream_buffer.cpp + gl/stream_buffer.h + gl/texture.cpp + gl/texture.h + jit_code_buffer.cpp + jit_code_buffer.h + state_wrapper.cpp + state_wrapper.h types.h ) -add_library(common ${SRCS}) - target_include_directories(common PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..") target_include_directories(common PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") -target_link_libraries(common YBaseLib glad libcue Threads::Threads) +target_link_libraries(common PRIVATE YBaseLib glad libcue Threads::Threads) + +if(WIN32) + target_sources(common PRIVATE + d3d11/shader_compiler.cpp + d3d11/shader_compiler.h + d3d11/staging_texture.cpp + d3d11/staging_texture.h + d3d11/stream_buffer.cpp + d3d11/stream_buffer.h + d3d11/texture.cpp + d3d11/texture.h + ) + target_link_libraries(common PRIVATE d3dcompiler.lib) +endif() diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index b4c750b83..c6bd1dc88 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -38,6 +38,10 @@ + + + + @@ -53,6 +57,10 @@ + + + + @@ -215,6 +223,7 @@ true stdcpp17 true + $(IntDir)/%(RelativeDir)/ Console @@ -223,6 +232,9 @@ $(SolutionDir)dep\msvc\lib32-debug;%(AdditionalLibraryDirectories) + + d3dcompiler.lib;%(AdditionalDependencies) + @@ -240,6 +252,7 @@ stdcpp17 OnlyExplicitInline true + $(IntDir)/%(RelativeDir)/ Console @@ -248,6 +261,9 @@ $(SolutionDir)dep\msvc\lib32-debug;%(AdditionalLibraryDirectories) + + d3dcompiler.lib;%(AdditionalDependencies) + @@ -262,6 +278,7 @@ true stdcpp17 true + $(IntDir)/%(RelativeDir)/ Console @@ -270,6 +287,9 @@ $(SolutionDir)dep\msvc\lib32-debug;%(AdditionalLibraryDirectories) + + d3dcompiler.lib;%(AdditionalDependencies) + @@ -287,6 +307,7 @@ stdcpp17 OnlyExplicitInline true + $(IntDir)/%(RelativeDir)/ Console @@ -295,6 +316,9 @@ $(SolutionDir)dep\msvc\lib32-debug;%(AdditionalLibraryDirectories) + + d3dcompiler.lib;%(AdditionalDependencies) + @@ -311,6 +335,7 @@ stdcpp17 false true + $(IntDir)/%(RelativeDir)/ Console @@ -321,6 +346,9 @@ $(SolutionDir)dep\msvc\lib32;%(AdditionalLibraryDirectories) + + d3dcompiler.lib;%(AdditionalDependencies) + @@ -337,6 +365,7 @@ true stdcpp17 true + $(IntDir)/%(RelativeDir)/ Console @@ -347,6 +376,9 @@ $(SolutionDir)dep\msvc\lib32;%(AdditionalLibraryDirectories) + + d3dcompiler.lib;%(AdditionalDependencies) + @@ -363,6 +395,7 @@ stdcpp17 false true + $(IntDir)/%(RelativeDir)/ Console @@ -373,6 +406,9 @@ $(SolutionDir)dep\msvc\lib32;%(AdditionalLibraryDirectories) + + d3dcompiler.lib;%(AdditionalDependencies) + @@ -389,6 +425,7 @@ true stdcpp17 true + $(IntDir)/%(RelativeDir)/ Console @@ -399,6 +436,9 @@ $(SolutionDir)dep\msvc\lib32;%(AdditionalLibraryDirectories) + + d3dcompiler.lib;%(AdditionalDependencies) + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 57ff49c52..c31b18e5d 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -19,6 +19,18 @@ gl + + d3d11 + + + d3d11 + + + d3d11 + + + d3d11 + @@ -37,6 +49,18 @@ gl + + d3d11 + + + d3d11 + + + d3d11 + + + d3d11 + @@ -45,5 +69,8 @@ {52487c57-753d-4888-ba26-ed63ab51a234} + + {30251086-81f3-44f5-add4-7ff9a24098ab} + \ No newline at end of file diff --git a/src/common/d3d11/shader_compiler.cpp b/src/common/d3d11/shader_compiler.cpp new file mode 100644 index 000000000..c96d06072 --- /dev/null +++ b/src/common/d3d11/shader_compiler.cpp @@ -0,0 +1,142 @@ +#include "shader_compiler.h" +#include "YBaseLib/Log.h" +#include "YBaseLib/String.h" +#include +#include +#include +Log_SetChannel(D3D11); + +namespace D3D11::ShaderCompiler { + +static unsigned s_next_bad_shader_id = 1; + +ComPtr CompileShader(Type type, D3D_FEATURE_LEVEL feature_level, std::string_view code, bool debug) +{ + const char* target; + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + { + static constexpr std::array targets = {{"vs_4_0", "ps_4_0", "cs_4_0"}}; + target = targets[static_cast(type)]; + } + break; + + case D3D_FEATURE_LEVEL_10_1: + { + static constexpr std::array targets = {{"vs_4_1", "ps_4_1", "cs_4_1"}}; + target = targets[static_cast(type)]; + } + break; + + case D3D_FEATURE_LEVEL_11_0: + { + static constexpr std::array targets = {{"vs_5_0", "ps_5_0", "cs_5_0"}}; + target = targets[static_cast(type)]; + } + break; + + case D3D_FEATURE_LEVEL_11_1: + default: + { + static constexpr std::array targets = {{"vs_5_1", "ps_5_1", "cs_5_1"}}; + target = targets[static_cast(type)]; + } + break; + } + + static constexpr UINT flags_non_debug = D3DCOMPILE_OPTIMIZATION_LEVEL3; + static constexpr UINT flags_debug = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG; + + ComPtr blob; + ComPtr error_blob; + const HRESULT hr = + D3DCompile(code.data(), code.size(), "0", nullptr, nullptr, "main", target, debug ? flags_debug : flags_non_debug, + 0, blob.GetAddressOf(), error_blob.GetAddressOf()); + + String error_string; + if (error_blob) + { + error_string.AppendString(static_cast(error_blob->GetBufferPointer()), + static_cast(error_blob->GetBufferSize())); + error_blob.Reset(); + } + + if (FAILED(hr)) + { + Log_ErrorPrintf("Failed to compile '%s':\n%s", target, error_string.GetCharArray()); + + std::ofstream ofs(SmallString::FromFormat("bad_shader_%u.txt", s_next_bad_shader_id++), + std::ofstream::out | std::ofstream::binary); + if (ofs.is_open()) + { + ofs << code; + ofs << "\n\nCompile as " << target << " failed: " << hr << "\n"; + ofs.write(error_string.GetCharArray(), error_string.GetLength()); + ofs.close(); + } + + return {}; + } + + if (!error_string.IsEmpty()) + Log_WarningPrintf("'%s' compiled with warnings:\n%s", target, error_string.GetCharArray()); + + return blob; +} + +ComPtr CompileAndCreateVertexShader(ID3D11Device* device, std::string_view code, bool debug) +{ + ComPtr blob = CompileShader(Type::Vertex, device->GetFeatureLevel(), std::move(code), debug); + if (!blob) + return {}; + + ComPtr vs; + const HRESULT hr = + device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, vs.GetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("Failed to create vertex shader: 0x%08X", hr); + return {}; + } + + return vs; +} + +ComPtr CompileAndCreatePixelShader(ID3D11Device* device, std::string_view code, bool debug) +{ + ComPtr blob = CompileShader(Type::Pixel, device->GetFeatureLevel(), std::move(code), debug); + if (!blob) + return {}; + + ComPtr shader; + const HRESULT hr = + device->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, shader.GetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("Failed to create pixel shader: 0x%08X", hr); + return {}; + } + + return shader; +} + +ComPtr CompileAndCreateComputeShader(ID3D11Device* device, std::string_view code, bool debug) +{ + ComPtr blob = CompileShader(Type::Compute, device->GetFeatureLevel(), std::move(code), debug); + if (!blob) + return {}; + + ComPtr shader; + const HRESULT hr = + device->CreateComputeShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, shader.GetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("Failed to create compute shader: 0x%08X", hr); + return {}; + } + + return shader; +} + +} // namespace D3D11::ShaderCompiler \ No newline at end of file diff --git a/src/common/d3d11/shader_compiler.h b/src/common/d3d11/shader_compiler.h new file mode 100644 index 000000000..c1fba1481 --- /dev/null +++ b/src/common/d3d11/shader_compiler.h @@ -0,0 +1,25 @@ +#pragma once +#include "YBaseLib/Windows/WindowsHeaders.h" +#include +#include +#include +#include + +namespace D3D11::ShaderCompiler { +template +using ComPtr = Microsoft::WRL::ComPtr; + +enum class Type +{ + Vertex, + Pixel, + Compute +}; + +ComPtr CompileShader(Type type, D3D_FEATURE_LEVEL feature_level, std::string_view code, bool debug); + +ComPtr CompileAndCreateVertexShader(ID3D11Device* device, std::string_view code, bool debug); +ComPtr CompileAndCreatePixelShader(ID3D11Device* device, std::string_view code, bool debug); +ComPtr CompileAndCreateComputeShader(ID3D11Device* device, std::string_view code, bool debug); + +}; // namespace D3D11::ShaderCompiler diff --git a/src/common/d3d11/staging_texture.cpp b/src/common/d3d11/staging_texture.cpp new file mode 100644 index 000000000..35a16192a --- /dev/null +++ b/src/common/d3d11/staging_texture.cpp @@ -0,0 +1,91 @@ +#include "staging_texture.h" +#include "YBaseLib/Log.h" +Log_SetChannel(D3D11); + +namespace D3D11 { + +StagingTexture::StagingTexture() : m_width(0), m_height(0) {} + +StagingTexture::~StagingTexture() +{ + Destroy(); +} + +bool StagingTexture::Create(ID3D11Device* device, u32 width, u32 height, DXGI_FORMAT format, bool for_uploading) +{ + CD3D11_TEXTURE2D_DESC desc(format, width, height, 1, 1, 0, for_uploading ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_STAGING, + 0, 1, 0, 0); + + ComPtr texture; + const HRESULT tex_hr = device->CreateTexture2D(&desc, nullptr, texture.GetAddressOf()); + if (FAILED(tex_hr)) + { + Log_ErrorPrintf("Create texture failed: 0x%08X", tex_hr); + return false; + } + + m_texture = std::move(texture); + m_width = desc.Width; + m_height = desc.Height; + m_format = desc.Format; + return true; +} + +void StagingTexture::Destroy() +{ + Assert(!IsMapped()); + m_texture.Reset(); +} + +bool StagingTexture::Map(ID3D11DeviceContext* context, bool writing) +{ + Assert(!IsMapped()); + const HRESULT hr = context->Map(m_texture.Get(), 0, writing ? D3D11_MAP_WRITE : D3D11_MAP_READ, 0, &m_map); + if (FAILED(hr)) + { + Log_ErrorPrintf("Map staging texture failed: 0x%08X", hr); + return false; + } + + return true; +} + +void StagingTexture::Unmap(ID3D11DeviceContext* context) +{ + Assert(IsMapped()); + context->Unmap(m_texture.Get(), 0); +} + +void StagingTexture::CopyToTexture(ID3D11DeviceContext* context, u32 src_x, u32 src_y, ID3D11Texture2D* dst_texture, + u32 dst_subresource, u32 dst_x, u32 dst_y, u32 width, u32 height) +{ +#ifdef _DEBUG + Assert((src_x + width) <= m_width && (src_y + height) <= m_height); + + D3D11_TEXTURE2D_DESC dst_desc; + dst_texture->GetDesc(&dst_desc); + Assert((dst_x + width) <= dst_desc.Width && (dst_y + height) <= dst_desc.Height); +#endif + + const CD3D11_BOX box(static_cast(src_x), static_cast(src_y), 0, static_cast(src_x + width), + static_cast(src_y + height), 1); + context->CopySubresourceRegion(dst_texture, dst_subresource, dst_x, dst_y, 0, m_texture.Get(), 0, &box); +} + +void StagingTexture::CopyFromTexture(ID3D11DeviceContext* context, ID3D11Texture2D* src_texture, u32 src_subresource, + u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height) +{ +#ifdef _DEBUG + Assert((dst_x + width) <= m_width && (dst_y + height) <= m_height); + + D3D11_TEXTURE2D_DESC src_desc; + src_texture->GetDesc(&src_desc); + Assert((src_x + width) <= src_desc.Width && (src_y + height) <= src_desc.Height); +#endif + + const CD3D11_BOX box(static_cast(src_x), static_cast(src_y), 0, static_cast(src_x + width), + static_cast(src_y + height), 1); + context->CopySubresourceRegion(m_texture.Get(), 0, dst_x, dst_y, 0, src_texture, src_subresource, &box); +} + +} // namespace D3D \ No newline at end of file diff --git a/src/common/d3d11/staging_texture.h b/src/common/d3d11/staging_texture.h new file mode 100644 index 000000000..19d387051 --- /dev/null +++ b/src/common/d3d11/staging_texture.h @@ -0,0 +1,100 @@ +#pragma once +#include "../types.h" +#include "YBaseLib/Windows/WindowsHeaders.h" +#include +#include +#include + +namespace D3D11 { +class StagingTexture +{ +public: + template + using ComPtr = Microsoft::WRL::ComPtr; + + StagingTexture(); + ~StagingTexture(); + + ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); } + + ALWAYS_INLINE u32 GetWidth() const { return m_width; } + ALWAYS_INLINE u32 GetHeight() const { return m_height; } + ALWAYS_INLINE DXGI_FORMAT GetFormat() const { return m_format; } + ALWAYS_INLINE bool IsMapped() const { return m_map.pData != nullptr; } + + ALWAYS_INLINE operator bool() const { return static_cast(m_texture); } + + bool Create(ID3D11Device* device, u32 width, u32 height, DXGI_FORMAT format, bool for_uploading); + void Destroy(); + + bool Map(ID3D11DeviceContext* context, bool writing); + void Unmap(ID3D11DeviceContext* context); + + void CopyToTexture(ID3D11DeviceContext* context, u32 src_x, u32 src_y, ID3D11Texture2D* dst_texture, + u32 dst_subresource, u32 dst_x, u32 dst_y, u32 width, u32 height); + void CopyFromTexture(ID3D11DeviceContext* context, ID3D11Texture2D* src_texture, u32 src_subresource, u32 src_x, + u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height); + + template + T ReadPixel(u32 x, u32 y) + { + T pixel; + std::memcpy(&pixel, static_cast(m_map.pData) + (y * m_map.RowPitch) + x, sizeof(T)); + return pixel; + } + + template + void WritePixel(u32 x, u32 y, T pixel) + { + std::memcpy(static_cast(m_map.pData) + (y * m_map.RowPitch) + x, &pixel, sizeof(T)); + } + + template + void ReadPixels(u32 x, u32 y, u32 width, u32 height, u32 stride, T* data) + { + const u8* src_ptr = static_cast(m_map.pData) + (y * m_map.RowPitch) + (x * sizeof(T)); + u8* dst_ptr = reinterpret_cast(data); + if (m_map.RowPitch != stride) + { + for (u32 row = 0; row < height; row++) + { + std::memcpy(dst_ptr, src_ptr, sizeof(T) * width); + src_ptr += m_map.RowPitch; + dst_ptr += stride; + } + } + else + { + std::memcpy(dst_ptr, src_ptr, stride * height); + } + } + + template + void WritePixels(u32 x, u32 y, u32 width, u32 height, u32 stride, const T* data) + { + const u8* src_ptr = reinterpret_cast(data); + u8* dst_ptr = static_cast(m_map.pData) + (y * m_map.RowPitch) + (x * sizeof(T)); + if (m_map.RowPitch != stride) + { + for (u32 row = 0; row < height; row++) + { + std::memcpy(dst_ptr, src_ptr, sizeof(T) * width); + src_ptr += stride; + dst_ptr += m_map.RowPitch; + } + } + else + { + std::memcpy(dst_ptr, src_ptr, stride * height); + } + } + +private: + ComPtr m_texture; + u32 m_width; + u32 m_height; + DXGI_FORMAT m_format; + + D3D11_MAPPED_SUBRESOURCE m_map = {}; +}; +} // namespace D3D11 \ No newline at end of file diff --git a/src/common/d3d11/stream_buffer.cpp b/src/common/d3d11/stream_buffer.cpp new file mode 100644 index 000000000..b14ed95b4 --- /dev/null +++ b/src/common/d3d11/stream_buffer.cpp @@ -0,0 +1,88 @@ +#include "stream_buffer.h" +#include "YBaseLib/Log.h" +Log_SetChannel(D3D11); + +namespace D3D11 { + +StreamBuffer::StreamBuffer() : m_size(0), m_position(0) {} + +StreamBuffer::StreamBuffer(ComPtr buffer) : m_buffer(std::move(buffer)), m_position(0) +{ + D3D11_BUFFER_DESC desc; + m_buffer->GetDesc(&desc); + m_size = desc.ByteWidth; +} + +StreamBuffer::~StreamBuffer() +{ + Release(); +} + +bool StreamBuffer::Create(ID3D11Device* device, D3D11_BIND_FLAG bind_flags, u32 size) +{ + CD3D11_BUFFER_DESC desc(size, bind_flags, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE, 0, 0); + ComPtr buffer; + const HRESULT hr = device->CreateBuffer(&desc, nullptr, &buffer); + if (FAILED(hr)) + { + Log_ErrorPrintf("Creating buffer failed: 0x%08X", hr); + return false; + } + + m_buffer = std::move(buffer); + m_size = size; + m_position = 0; + return true; +} + +void StreamBuffer::Adopt(ComPtr buffer) +{ + m_buffer = std::move(buffer); + + D3D11_BUFFER_DESC desc; + m_buffer->GetDesc(&desc); + m_size = desc.ByteWidth; + m_position = 0; +} + +void StreamBuffer::Release() +{ + m_buffer.Reset(); +} + +StreamBuffer::MappingResult StreamBuffer::Map(ID3D11DeviceContext* context, u32 alignment, u32 min_size) +{ + m_position = Common::AlignUp(m_position, alignment); + + D3D11_MAP map; + if ((m_position + min_size) >= m_size) + { + // wrap around + m_position = 0; + map = D3D11_MAP_WRITE_DISCARD; + } + else + { + map = D3D11_MAP_WRITE_NO_OVERWRITE; + } + + D3D11_MAPPED_SUBRESOURCE sr; + const HRESULT hr = context->Map(m_buffer.Get(), 0, map, 0, &sr); + if (FAILED(hr)) + { + Log_ErrorPrintf("Map failed: 0x%08X", hr); + Panic("Map failed"); + return {}; + } + + return MappingResult{static_cast(sr.pData) + m_position, m_position, m_position / alignment, + (m_size - m_position) / alignment}; +} + +void StreamBuffer::Unmap(ID3D11DeviceContext* context, u32 used_size) +{ + context->Unmap(m_buffer.Get(), 0); + m_position += used_size; +} + +} // namespace D3D11 \ No newline at end of file diff --git a/src/common/d3d11/stream_buffer.h b/src/common/d3d11/stream_buffer.h new file mode 100644 index 000000000..c4c7f93be --- /dev/null +++ b/src/common/d3d11/stream_buffer.h @@ -0,0 +1,43 @@ +#pragma once +#include "../types.h" +#include "YBaseLib/Windows/WindowsHeaders.h" +#include +#include + +namespace D3D11 { +class StreamBuffer +{ +public: + template + using ComPtr = Microsoft::WRL::ComPtr; + + StreamBuffer(); + StreamBuffer(ComPtr buffer); + ~StreamBuffer(); + + ALWAYS_INLINE ID3D11Buffer* GetD3DBuffer() const { return m_buffer.Get(); } + ALWAYS_INLINE ID3D11Buffer* const* GetD3DBufferArray() const { return m_buffer.GetAddressOf(); } + ALWAYS_INLINE u32 GetSize() const { return m_size; } + ALWAYS_INLINE u32 GetPosition() const { return m_position; } + + bool Create(ID3D11Device* device, D3D11_BIND_FLAG bind_flags, u32 size); + void Adopt(ComPtr buffer); + void Release(); + + struct MappingResult + { + void* pointer; + u32 buffer_offset; + u32 index_aligned; // offset / alignment, suitable for base vertex + u32 space_aligned; // remaining space / alignment + }; + + MappingResult Map(ID3D11DeviceContext* context, u32 alignment, u32 min_size); + void Unmap(ID3D11DeviceContext* context, u32 used_size); + +private: + ComPtr m_buffer; + u32 m_size; + u32 m_position; +}; +} // namespace GL \ No newline at end of file diff --git a/src/common/d3d11/texture.cpp b/src/common/d3d11/texture.cpp new file mode 100644 index 000000000..1e8eace58 --- /dev/null +++ b/src/common/d3d11/texture.cpp @@ -0,0 +1,130 @@ +#include "texture.h" +#include "YBaseLib/Log.h" +Log_SetChannel(D3D11); + +namespace D3D11 { + +Texture::Texture() : m_width(0), m_height(0) {} + +Texture::Texture(ComPtr texture, ComPtr srv, + ComPtr rtv) + : m_texture(std::move(texture)), m_srv(std::move(srv)), m_rtv(std::move(rtv)) +{ + const D3D11_TEXTURE2D_DESC desc = GetDesc(); + m_width = desc.Width; + m_height = desc.Height; +} + +Texture::~Texture() +{ + Destroy(); +} + +D3D11_TEXTURE2D_DESC Texture::GetDesc() const +{ + D3D11_TEXTURE2D_DESC desc; + m_texture->GetDesc(&desc); + return desc; +} + +bool Texture::Create(ID3D11Device* device, u32 width, u32 height, DXGI_FORMAT format, bool shader_resource, + bool render_target, const void* initial_data, u32 initial_data_stride) +{ + CD3D11_TEXTURE2D_DESC desc(format, width, height, 1, 1, 0, D3D11_USAGE_DEFAULT, 0, 1, 0, 0); + if (shader_resource) + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + if (render_target) + desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + + D3D11_SUBRESOURCE_DATA srd; + srd.pSysMem = initial_data; + srd.SysMemPitch = initial_data_stride; + srd.SysMemSlicePitch = initial_data_stride * height; + + ComPtr texture; + const HRESULT tex_hr = device->CreateTexture2D(&desc, initial_data ? &srd : nullptr, texture.GetAddressOf()); + if (FAILED(tex_hr)) + { + Log_ErrorPrintf("Create texture failed: 0x%08X", tex_hr); + return false; + } + + ComPtr srv; + if (shader_resource) + { + const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_TEXTURE2D, desc.Format, 0, desc.MipLevels, 0, + desc.ArraySize); + const HRESULT hr = device->CreateShaderResourceView(texture.Get(), &srv_desc, srv.GetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("Create SRV for adopted texture failed: 0x%08X", hr); + return false; + } + } + + ComPtr rtv; + if (render_target) + { + const CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, desc.Format, 0, 0, desc.ArraySize); + const HRESULT hr = device->CreateRenderTargetView(texture.Get(), &rtv_desc, rtv.GetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("Create RTV for adopted texture failed: 0x%08X", hr); + return false; + } + } + + m_texture = std::move(texture); + m_srv = std::move(srv); + m_rtv = std::move(rtv); + m_width = desc.Width; + m_height = desc.Height; + return true; +} + +bool Texture::Adopt(ID3D11Device* device, ComPtr texture) +{ + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc(&desc); + + ComPtr srv; + if (desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) + { + const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(D3D11_SRV_DIMENSION_TEXTURE2D, desc.Format, 0, desc.MipLevels, 0, + desc.ArraySize); + const HRESULT hr = device->CreateShaderResourceView(texture.Get(), &srv_desc, srv.ReleaseAndGetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("Create SRV for adopted texture failed: 0x%08X", hr); + return false; + } + } + + ComPtr rtv; + if (desc.BindFlags & D3D11_BIND_RENDER_TARGET) + { + const CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, desc.Format, 0, 0, desc.ArraySize); + const HRESULT hr = device->CreateRenderTargetView(texture.Get(), &rtv_desc, rtv.ReleaseAndGetAddressOf()); + if (FAILED(hr)) + { + Log_ErrorPrintf("Create RTV for adopted texture failed: 0x%08X", hr); + return false; + } + } + + m_texture = std::move(texture); + m_srv = std::move(srv); + m_rtv = std::move(rtv); + m_width = desc.Width; + m_height = desc.Height; + return true; +} + +void Texture::Destroy() +{ + m_rtv.Reset(); + m_srv.Reset(); + m_texture.Reset(); +} + +} // namespace D3D11 \ No newline at end of file diff --git a/src/common/d3d11/texture.h b/src/common/d3d11/texture.h new file mode 100644 index 000000000..2a1303985 --- /dev/null +++ b/src/common/d3d11/texture.h @@ -0,0 +1,47 @@ +#pragma once +#include "../types.h" +#include "YBaseLib/Windows/WindowsHeaders.h" +#include +#include + +namespace D3D11 { +class Texture +{ +public: + template + using ComPtr = Microsoft::WRL::ComPtr; + + Texture(); + Texture(ComPtr texture, ComPtr srv, ComPtr rtv); + ~Texture(); + + ALWAYS_INLINE ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); } + ALWAYS_INLINE ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); } + ALWAYS_INLINE ID3D11RenderTargetView* GetD3DRTV() const { return m_rtv.Get(); } + ALWAYS_INLINE ID3D11ShaderResourceView* const* GetD3DSRVArray() const { return m_srv.GetAddressOf(); } + ALWAYS_INLINE ID3D11RenderTargetView* const* GetD3DRTVArray() const { return m_rtv.GetAddressOf(); } + + ALWAYS_INLINE u32 GetWidth() const { return m_width; } + ALWAYS_INLINE u32 GetHeight() const { return m_height; } + ALWAYS_INLINE DXGI_FORMAT GetFormat() const { return GetDesc().Format; } + D3D11_TEXTURE2D_DESC GetDesc() const; + + ALWAYS_INLINE operator ID3D11Texture2D*() const { return m_texture.Get(); } + ALWAYS_INLINE operator ID3D11ShaderResourceView*() const { return m_srv.Get(); } + ALWAYS_INLINE operator ID3D11RenderTargetView*() const { return m_rtv.Get(); } + ALWAYS_INLINE operator bool() const { return static_cast(m_texture); } + + bool Create(ID3D11Device* device, u32 width, u32 height, DXGI_FORMAT format, bool shader_resource, bool render_target, + const void* initial_data = nullptr, u32 initial_data_stride = 0); + bool Adopt(ID3D11Device* device, ComPtr texture); + + void Destroy(); + +private: + ComPtr m_texture; + ComPtr m_srv; + ComPtr m_rtv; + u32 m_width; + u32 m_height; +}; +} // namespace D3D11 \ No newline at end of file