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