diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index b8a5862ac8..9ccc6d0686 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -38,6 +38,13 @@ const int FB_WIDTH = 480; const int FB_HEIGHT = 272; + +struct Vertex { + float x, y, z; + float u, v; + uint32_t rgba; +}; + FormatBuffer fb; FormatBuffer depthbuf; u32 clut[4096]; @@ -62,7 +69,7 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw) InputLayoutDesc inputDesc = { { - { 24, false }, + { sizeof(Vertex), false }, }, { { 0, SEM_POSITION, DataFormat::R32G32B32_FLOAT, 0 }, @@ -73,7 +80,7 @@ SoftGPU::SoftGPU(GraphicsContext *gfxCtx, Draw::DrawContext *draw) ShaderModule *vshader = draw_->GetVshaderPreset(VS_TEXTURE_COLOR_2D); - vdata = draw_->CreateBuffer(24 * 4, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); + vdata = draw_->CreateBuffer(sizeof(Vertex) * 4, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); idata = draw_->CreateBuffer(sizeof(int) * 6, BufferUsageFlag::DYNAMIC | BufferUsageFlag::INDEXDATA); InputLayout *inputLayout = draw_->CreateInputLayout(inputDesc); @@ -213,12 +220,6 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { x2 -= 1.0f; y2 -= 1.0f; - struct Vertex { - float x, y, z; - float u, v; - uint32_t rgba; - }; - if (hasImage) { float v0 = 1.0f; float v1 = 0.0f; @@ -235,10 +236,10 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) { { x2, y2, 0, u1, v1, 0xFFFFFFFF }, // BR { x2, y, 0, u1, v0, 0xFFFFFFFF }, // TR }; - vdata->SetData((const uint8_t *)verts, sizeof(verts)); + draw_->UpdateBuffer(vdata, (const uint8_t *)verts, 0, sizeof(verts), Draw::UPDATE_DISCARD); int indexes[] = { 0, 1, 2, 0, 2, 3 }; - idata->SetData((const uint8_t *)indexes, sizeof(indexes)); + draw_->UpdateBuffer(idata, (const uint8_t *)indexes, 0, sizeof(indexes), Draw::UPDATE_DISCARD); draw_->BindTexture(0, fbTex); diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index 4dca2e6482..6c09cfb67d 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -10,16 +10,18 @@ #include "Windows/GPU/D3D11Context.h" #include "Windows/W32Util/Misc.h" #include "thin3d/thin3d.h" +#include "thin3d/d3d11_loader.h" -void D3D11Context::SwapBuffers() { - swapChain_->Present(0, 0); +D3D11Context::D3D11Context() : draw_(nullptr), adapterId(-1), hDC(nullptr), hWnd_(nullptr), hD3D11(nullptr) { + LoadD3D11(); } -static void GetRes(HWND hWnd, int &xres, int &yres) { - RECT rc; - GetClientRect(hWnd, &rc); - xres = rc.right - rc.left; - yres = rc.bottom - rc.top; +D3D11Context::~D3D11Context() { + UnloadD3D11(); +} + +void D3D11Context::SwapBuffers() { + draw_->HandleEvent(Draw::Event::PRESENT_REQUESTED); } void D3D11Context::SwapInterval(int interval) { @@ -31,25 +33,20 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { hWnd_ = wnd; HRESULT hr = S_OK; - RECT rc; - GetClientRect(hWnd_, &rc); - UINT width = rc.right - rc.left; - UINT height = rc.bottom - rc.top; - UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif - D3D_DRIVER_TYPE driverTypes[] = { + static const D3D_DRIVER_TYPE driverTypes[] = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE, }; UINT numDriverTypes = ARRAYSIZE(driverTypes); - const D3D_FEATURE_LEVEL featureLevels[] = { - // D3D_FEATURE_LEVEL_11_1, + static const D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, @@ -57,149 +54,28 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { UINT numFeatureLevels = ARRAYSIZE(featureLevels); // Temporarily commenting out until we can dynamically load D3D11CreateDevice. - /* for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) { driverType_ = driverTypes[driverTypeIndex]; - hr = D3D11CreateDevice(nullptr, driverType_, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, + hr = ptr_D3D11CreateDevice(nullptr, driverType_, nullptr, createDeviceFlags, (D3D_FEATURE_LEVEL *)featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &device_, &featureLevel_, &context_); if (hr == E_INVALIDARG) { // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it - hr = D3D11CreateDevice(nullptr, driverType_, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1, + hr = ptr_D3D11CreateDevice(nullptr, driverType_, nullptr, createDeviceFlags, (D3D_FEATURE_LEVEL *)&featureLevels[1], numFeatureLevels - 1, D3D11_SDK_VERSION, &device_, &featureLevel_, &context_); } - if (SUCCEEDED(hr)) break; } - */ if (FAILED(hr)) return false; - // Obtain DXGI factory from device (since we used nullptr for pAdapter above) - IDXGIFactory1* dxgiFactory = nullptr; - { - IDXGIDevice* dxgiDevice = nullptr; - hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); - if (SUCCEEDED(hr)) { - IDXGIAdapter* adapter = nullptr; - hr = dxgiDevice->GetAdapter(&adapter); - if (SUCCEEDED(hr)) { - hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&dxgiFactory)); - adapter->Release(); - } - dxgiDevice->Release(); - } - } - if (FAILED(hr)) - return false; - - // Create swap chain - /* - IDXGIFactory2* dxgiFactory2 = nullptr; - hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory2)); - if (dxgiFactory2) - { - // DirectX 11.1 or later - hr = device_->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&device_1)); - if (SUCCEEDED(hr)) - { - (void)context_->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&context_1)); - } - - DXGI_SWAP_CHAIN_DESC1 sd; - ZeroMemory(&sd, sizeof(sd)); - sd.Width = width; - sd.Height = height; - sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.BufferCount = 1; - - hr = dxgiFactory2->CreateSwapChainForHwnd(device_, g_hWnd, &sd, nullptr, nullptr, &g_pSwapChain1); - if (SUCCEEDED(hr)) - { - hr = g_pSwapChain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast(&g_pSwapChain)); - } - dxgiFactory2->Release(); - } else { - */ - // DirectX 11.0 systems - DXGI_SWAP_CHAIN_DESC sd; - ZeroMemory(&sd, sizeof(sd)); - sd.BufferCount = 1; - sd.BufferDesc.Width = width; - sd.BufferDesc.Height = height; - sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.BufferDesc.RefreshRate.Numerator = 60; - sd.BufferDesc.RefreshRate.Denominator = 1; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.OutputWindow = hWnd_; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.Windowed = TRUE; - - hr = dxgiFactory->CreateSwapChain(device_, &sd, &swapChain_); - // } - - // Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut - dxgiFactory->MakeWindowAssociation(hWnd_, DXGI_MWA_NO_ALT_ENTER); - - dxgiFactory->Release(); - - if (FAILED(hr)) - return false; - - // Create a render target view - ID3D11Texture2D* pBackBuffer = nullptr; - hr = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&pBackBuffer)); - if (FAILED(hr)) - return false; - - hr = device_->CreateRenderTargetView(pBackBuffer, nullptr, &renderTargetView_); - pBackBuffer->Release(); - if (FAILED(hr)) - return false; - - // Create depth stencil texture - D3D11_TEXTURE2D_DESC descDepth; - ZeroMemory(&descDepth, sizeof(descDepth)); - descDepth.Width = width; - descDepth.Height = height; - descDepth.MipLevels = 1; - descDepth.ArraySize = 1; - descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - descDepth.SampleDesc.Count = 1; - descDepth.SampleDesc.Quality = 0; - descDepth.Usage = D3D11_USAGE_DEFAULT; - descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; - descDepth.CPUAccessFlags = 0; - descDepth.MiscFlags = 0; - hr = device_->CreateTexture2D(&descDepth, nullptr, &depthStencilTex_); - if (FAILED(hr)) - return false; - - // Create the depth stencil view - D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; - ZeroMemory(&descDSV, sizeof(descDSV)); - descDSV.Format = descDepth.Format; - descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - descDSV.Texture2D.MipSlice = 0; - hr = device_->CreateDepthStencilView(depthStencilTex_, &descDSV, &depthStencilView_); - if (FAILED(hr)) - return false; - - context_->OMSetRenderTargets(1, &renderTargetView_, depthStencilView_); - - int xres, yres; - GetRes(hWnd_, xres, yres); - - draw_ = Draw::T3DCreateD3D11Context(device_, context_); + draw_ = Draw::T3DCreateD3D11Context(device_, context_, hWnd_); return true; } void D3D11Context::Resize() { + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER); // This should only be called from the emu thread. /* int xres, yres; @@ -218,6 +94,7 @@ void D3D11Context::Resize() { } } */ + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER); } void D3D11Context::Shutdown() { diff --git a/Windows/GPU/D3D11Context.h b/Windows/GPU/D3D11Context.h index 3eecf07ff3..7139ece4d6 100644 --- a/Windows/GPU/D3D11Context.h +++ b/Windows/GPU/D3D11Context.h @@ -27,9 +27,8 @@ class DrawContext; class D3D11Context : public WindowsGraphicsContext { public: - D3D11Context() : draw_(nullptr), adapterId(-1), hDC(nullptr), hWnd_(nullptr), hD3D11(nullptr) { - } - + D3D11Context(); + ~D3D11Context(); bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override; void Shutdown() override; void SwapInterval(int interval) override; @@ -43,10 +42,6 @@ private: Draw::DrawContext *draw_; ID3D11Device *device_; ID3D11DeviceContext *context_; - IDXGISwapChain *swapChain_ = nullptr; - ID3D11RenderTargetView *renderTargetView_ = nullptr; - ID3D11Texture2D *depthStencilTex_ = nullptr; - ID3D11DepthStencilView *depthStencilView_ = nullptr; D3D_DRIVER_TYPE driverType_; D3D_FEATURE_LEVEL featureLevel_ = D3D_FEATURE_LEVEL_11_0; diff --git a/ext/native/gfx_es2/draw_buffer.cpp b/ext/native/gfx_es2/draw_buffer.cpp index cf12727757..13b4e111ec 100644 --- a/ext/native/gfx_es2/draw_buffer.cpp +++ b/ext/native/gfx_es2/draw_buffer.cpp @@ -38,11 +38,11 @@ void DrawBuffer::Init(Draw::DrawContext *t3d, Draw::Pipeline *pipeline) { if (inited_) return; - t3d_ = t3d; + draw_ = t3d; inited_ = true; if (pipeline->RequiresBuffer()) { - vbuf_ = t3d_->CreateBuffer(MAX_VERTS * sizeof(Vertex), BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); + vbuf_ = draw_->CreateBuffer(MAX_VERTS * sizeof(Vertex), BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); } else { vbuf_ = nullptr; } @@ -91,14 +91,14 @@ void DrawBuffer::Flush(bool set_blend_state) { return; pipeline_->SetMatrix4x4("WorldViewProj", drawMatrix_.getReadPtr()); - t3d_->BindPipeline(pipeline_); + draw_->BindPipeline(pipeline_); if (vbuf_) { - vbuf_->SubData((const uint8_t *)verts_, 0, sizeof(Vertex) * count_); - t3d_->BindVertexBuffers(0, 1, &vbuf_, nullptr); + draw_->UpdateBuffer(vbuf_, (const uint8_t *)verts_, 0, sizeof(Vertex) * count_, Draw::UPDATE_DISCARD); + draw_->BindVertexBuffers(0, 1, &vbuf_, nullptr); int offset = 0; - t3d_->Draw(count_, offset); + draw_->Draw(count_, offset); } else { - t3d_->DrawUP((const void *)verts_, count_); + draw_->DrawUP((const void *)verts_, count_); } count_ = 0; } diff --git a/ext/native/gfx_es2/draw_buffer.h b/ext/native/gfx_es2/draw_buffer.h index 2627fa9708..f55b0cf840 100644 --- a/ext/native/gfx_es2/draw_buffer.h +++ b/ext/native/gfx_es2/draw_buffer.h @@ -160,7 +160,7 @@ private: Matrix4x4 drawMatrix_; - Draw::DrawContext *t3d_; + Draw::DrawContext *draw_; Draw::Buffer *vbuf_; Draw::Pipeline *pipeline_; diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index 91983009a2..2431958a14 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -236,6 +236,7 @@ + @@ -689,6 +690,7 @@ + diff --git a/ext/native/native.vcxproj.filters b/ext/native/native.vcxproj.filters index 6d94a4845e..d8e0ec9789 100644 --- a/ext/native/native.vcxproj.filters +++ b/ext/native/native.vcxproj.filters @@ -320,8 +320,8 @@ gfx - - gfx + + thin3d @@ -772,8 +772,8 @@ gfx - - gfx + + thin3d @@ -847,4 +847,4 @@ {06c6305a-a646-485b-85b9-645a24dd6553} - + \ No newline at end of file diff --git a/ext/native/thin3d/d3d11_loader.cpp b/ext/native/thin3d/d3d11_loader.cpp new file mode 100644 index 0000000000..8f935bdbc0 --- /dev/null +++ b/ext/native/thin3d/d3d11_loader.cpp @@ -0,0 +1,47 @@ +#include "thin3d/d3d11_loader.h" + +static HMODULE g_DXGIModule; +static HMODULE g_D3D11Module; +static HMODULE g_D3DCompileModule; + +LPCREATEDXGIFACTORY ptr_CreateDXGIFactory; +LPD3D11CREATEDEVICE ptr_D3D11CreateDevice; +LPD3D11CREATEDEVICEANDSWAPCHAIN ptr_D3D11CreateDeviceAndSwapChain; +pD3DCompile ptr_D3DCompile; + +bool LoadD3D11() { + if (g_D3D11Module) { + return true; + } + g_D3D11Module = LoadLibrary(L"d3d11.dll"); + if (g_D3D11Module) { + ptr_D3D11CreateDevice = (LPD3D11CREATEDEVICE)GetProcAddress(g_D3D11Module, "D3D11CreateDevice"); + ptr_D3D11CreateDeviceAndSwapChain = (LPD3D11CREATEDEVICEANDSWAPCHAIN)GetProcAddress(g_D3D11Module, "D3D11CreateDeviceAndSwapChain"); + } + if (!ptr_CreateDXGIFactory) { + g_DXGIModule = LoadLibrary(L"dxgi.dll"); + if (g_DXGIModule) { + ptr_CreateDXGIFactory = (LPCREATEDXGIFACTORY)GetProcAddress(g_DXGIModule, "CreateDXGIFactory1"); + } + } + g_D3DCompileModule = LoadLibrary(L"D3dcompiler_47.dll"); + ptr_D3DCompile = (pD3DCompile)GetProcAddress(g_D3DCompileModule, "D3DCompile"); + + return g_DXGIModule != nullptr && g_D3D11Module != nullptr && g_D3DCompileModule != nullptr; +} + +bool UnloadD3D11() { + if (g_DXGIModule) { + FreeLibrary(g_DXGIModule); + g_DXGIModule = nullptr; + } + if (g_D3D11Module) { + FreeLibrary(g_D3D11Module); + g_D3D11Module = nullptr; + } + if (g_D3DCompileModule) { + FreeLibrary(g_D3DCompileModule); + g_D3DCompileModule = nullptr; + } + return true; +} \ No newline at end of file diff --git a/ext/native/thin3d/d3d11_loader.h b/ext/native/thin3d/d3d11_loader.h new file mode 100644 index 0000000000..38ed514a84 --- /dev/null +++ b/ext/native/thin3d/d3d11_loader.h @@ -0,0 +1,21 @@ +#pragma once + +// Standard Windows includes +#include +#include +#include +#include +#include + +typedef HRESULT(WINAPI *LPCREATEDXGIFACTORY)(REFIID, void **); +typedef HRESULT(WINAPI *LPD3D11CREATEDEVICEANDSWAPCHAIN)(__in_opt IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, __in_ecount_opt(FeatureLevels) CONST D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, __in_opt CONST DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, __out_opt IDXGISwapChain **ppSwapChain, __out_opt ID3D11Device **ppDevice, __out_opt D3D_FEATURE_LEVEL *pFeatureLevel, __out_opt ID3D11DeviceContext **ppImmediateContext); +typedef HRESULT(WINAPI *LPD3D11CREATEDEVICE)(IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT32, D3D_FEATURE_LEVEL *, UINT, UINT32, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **); +// typedef HRESULT(WINAPI *LPD3DCOMPILE)(LPCVOID pSrcData, SIZE_T SrcDataSize, LPCSTR pSourceName, const D3D_SHADER_MACRO pDefines, ID3DInclude *pInclude, LPCSTR pEntrypoint, LPCSTR pTarget, UINT Flags1, UINT Flags2, ID3DBlob *ppCode, ID3DBlob *ppErrorMsgs); + +extern LPCREATEDXGIFACTORY ptr_CreateDXGIFactory; +extern LPD3D11CREATEDEVICE ptr_D3D11CreateDevice; +extern LPD3D11CREATEDEVICEANDSWAPCHAIN ptr_D3D11CreateDeviceAndSwapChain; +extern pD3DCompile ptr_D3DCompile; + +bool LoadD3D11(); +bool UnloadD3D11(); \ No newline at end of file diff --git a/ext/native/thin3d/thin3d.cpp b/ext/native/thin3d/thin3d.cpp index 00d64cee89..753ac1762a 100644 --- a/ext/native/thin3d/thin3d.cpp +++ b/ext/native/thin3d/thin3d.cpp @@ -22,6 +22,8 @@ size_t DataFormatSizeInBytes(DataFormat fmt) { case DataFormat::R8G8B8A8_UNORM: case DataFormat::R8G8B8A8_UNORM_SRGB: return 4; + case DataFormat::B8G8R8A8_UNORM: + case DataFormat::B8G8R8A8_UNORM_SRGB: return 4; case DataFormat::R8G8B8A8_SNORM: return 4; case DataFormat::R8G8B8A8_UINT: return 4; @@ -79,6 +81,14 @@ static const std::vector fsTexCol = { " return input.color * tex2D(Sampler0, input.uv);\n" "}\n" }, + {ShaderLanguage::HLSL_D3D11, + "struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n" + "SamplerState samp : register(s0);\n" + "Texture2D tex : register(t0);\n" + "float4 main(PS_INPUT input) : SV_Target {\n" + " return input.color * tex.Sample(samp, input.uv);\n" + "}\n" + }, {ShaderLanguage::GLSL_VULKAN, "#version 140\n" "#extension GL_ARB_separate_shader_objects : enable\n" @@ -105,6 +115,12 @@ static const std::vector fsCol = { " return input.color;\n" "}\n" }, + { ShaderLanguage::HLSL_D3D11, + "struct PS_INPUT { float4 color : COLOR0; };\n" + "float4 main(PS_INPUT input) : SV_Target {\n" + " return input.color;\n" + "}\n" + }, { ShaderLanguage::GLSL_VULKAN, "#version 140\n" "#extension GL_ARB_separate_shader_objects : enable\n" @@ -139,6 +155,17 @@ static const std::vector vsCol = { " return output;\n" "}\n" }, + { ShaderLanguage::HLSL_D3D11, + "struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n" + "struct VS_OUTPUT { float4 Color0 : COLOR0; float4 Position : SV_Position; };\n" + "float4x4 WorldViewProj : register(c0);\n" + "VS_OUTPUT main(VS_INPUT input) {\n" + " VS_OUTPUT output;\n" + " output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n" + " output.Color0 = input.Color0;\n" + " return output;\n" + "}\n" + }, { ShaderLanguage::GLSL_VULKAN, "#version 400\n" "#extension GL_ARB_separate_shader_objects : enable\n" @@ -188,6 +215,18 @@ static const std::vector vsTexCol = { " return output;\n" "}\n" }, + { ShaderLanguage::HLSL_D3D11, + "struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n" + "struct VS_OUTPUT { float4 Color0 : COLOR0; float2 Texcoord0 : TEXCOORD0; float4 Position : SV_Position; };\n" + "float4x4 WorldViewProj : register(c0);\n" + "VS_OUTPUT main(VS_INPUT input) {\n" + " VS_OUTPUT output;\n" + " output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n" + " output.Texcoord0 = input.Texcoord0;\n" + " output.Color0 = input.Color0;\n" + " return output;\n" + "}\n" + }, { ShaderLanguage::GLSL_VULKAN, "#version 400\n" "#extension GL_ARB_separate_shader_objects : enable\n" @@ -214,7 +253,7 @@ struct VsTexColUB { float WorldViewProj[16]; }; -inline ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector &sources) { +static ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector &sources) { uint32_t supported = draw->GetSupportedShaderLanguages(); for (auto iter : sources) { if ((uint32_t)iter.lang & supported) { @@ -234,10 +273,12 @@ void DrawContext::CreatePresets() { DrawContext::~DrawContext() { for (int i = 0; i < VS_MAX_PRESET; i++) { - vsPresets_[i]->Release(); + if (vsPresets_[i]) + vsPresets_[i]->Release(); } for (int i = 0; i < FS_MAX_PRESET; i++) { - fsPresets_[i]->Release(); + if (fsPresets_[i]) + fsPresets_[i]->Release(); } } diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index cc61d30246..96880f3357 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -17,6 +17,10 @@ class Matrix4x4; #ifdef _WIN32 +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN +#include + struct IDirect3DDevice9; struct IDirect3D9; struct IDirect3DDevice9Ex; @@ -113,6 +117,7 @@ enum BufferUsageFlag : int { VERTEXDATA = 1, INDEXDATA = 2, GENERIC = 4, + UNIFORM = 8, DYNAMIC = 16, }; @@ -142,6 +147,8 @@ enum class Primitive { LINE_STRIP_ADJ, TRIANGLE_LIST_ADJ, TRIANGLE_STRIP_ADJ, + + UNDEFINED, }; enum VertexShaderPreset : int { @@ -182,6 +189,7 @@ enum class DataFormat : uint8_t { R8G8B8A8_UNORM, R8G8B8A8_UNORM_SRGB, B8G8R8A8_UNORM, // D3D style + B8G8R8A8_UNORM_SRGB, // D3D style R8G8B8A8_SNORM, R8G8B8A8_UINT, @@ -329,10 +337,15 @@ enum FBBlitFilter { FB_BLIT_LINEAR = 1, }; +enum UpdateBufferFlags { + UPDATE_DISCARD = 1, +}; + enum class Event { // These happen on D3D resize LOST_BACKBUFFER, GOT_BACKBUFFER, + PRESENT_REQUESTED, }; struct FramebufferDesc { @@ -384,8 +397,6 @@ public: class Buffer : public RefCountedObject { public: - virtual void SetData(const uint8_t *data, size_t size) = 0; - virtual void SubData(const uint8_t *data, size_t offset, size_t size) = 0; }; class Texture : public RefCountedObject { @@ -564,6 +575,9 @@ public: virtual ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) = 0; virtual Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc) = 0; + // Copies data from the CPU over into the buffer, at a specific offset. This does not change the size of the buffer and cannot write outside it. + virtual void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) = 0; + virtual void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) = 0; virtual bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) = 0; @@ -633,7 +647,7 @@ DrawContext *T3DCreateGLContext(); #ifdef _WIN32 DrawContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx); -DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context); +DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, HWND hWnd); #endif DrawContext *T3DCreateVulkanContext(VulkanContext *context); diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index fada98fe3c..e037f16308 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -1,4 +1,6 @@ #include "thin3d/thin3d.h" +#include "thin3d/d3d11_loader.h" +#include "math/dataconv.h" #include #include @@ -18,7 +20,7 @@ class D3D11RasterState; class D3D11DrawContext : public DrawContext { public: - D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext); + D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, HWND hWnd); ~D3D11DrawContext(); const DeviceCaps &GetDeviceCaps() const override { @@ -40,6 +42,8 @@ public: ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) override; Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override; + void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) override; bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; @@ -64,7 +68,10 @@ public: void SetScissorRect(int left, int top, int width, int height) override; void SetViewports(int count, Viewport *viewports) override; void SetBlendFactor(float color[4]) override { - memcpy(blendFactor_, color, sizeof(float) * 4); + if (memcmp(blendFactor_, color, sizeof(float) * 4)) { + memcpy(blendFactor_, color, sizeof(float) * 4); + blendFactorDirty_ = true; + } } void Draw(int vertexCount, int offset) override; @@ -95,13 +102,27 @@ public: } } - void HandleEvent(Event ev) override {} + void HandleEvent(Event ev) override { + switch (ev) { + case Event::PRESENT_REQUESTED: + swapChain_->Present(0, 0); + break; + } + } private: void ApplyCurrentState(); + HWND hWnd_; ID3D11Device *device_; ID3D11DeviceContext *context_; + IDXGISwapChain *swapChain_ = nullptr; + + ID3D11RenderTargetView *bbRenderTargetView_ = nullptr; + // Strictly speaking we don't need a depth buffer for the backbuffer. + ID3D11Texture2D *bbDepthStencilTex_ = nullptr; + ID3D11DepthStencilView *bbDepthStencilView_ = nullptr; + D3D11Pipeline *curPipeline_; DeviceCaps caps_; @@ -109,6 +130,15 @@ private: D3D11DepthStencilState *curDepth_ = nullptr; D3D11RasterState *curRaster_ = nullptr; ID3D11InputLayout *curInputLayout_ = nullptr; + ID3D11VertexShader *curVS_ = nullptr; + ID3D11PixelShader *curPS_ = nullptr; + ID3D11GeometryShader *curGS_ = nullptr; + D3D11_PRIMITIVE_TOPOLOGY curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + + ID3D11Buffer *nextVertexBuffers_[4]{}; + int nextVertexBufferOffsets_[4]{}; + ID3D11Buffer *nextIndexBuffer_ = nullptr; + int nextIndexBufferOffset_ = 0; // Dynamic state float blendFactor_[4]; @@ -117,9 +147,91 @@ private: bool stencilRefDirty_; }; +static void GetRes(HWND hWnd, int &xres, int &yres) { + RECT rc; + GetClientRect(hWnd, &rc); + xres = rc.right - rc.left; + yres = rc.bottom - rc.top; +} -D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *context) : device_(device), context_(context) { +D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *context, HWND hWnd) : device_(device), context_(context), hWnd_(hWnd) { + HRESULT hr; + // Obtain DXGI factory from device (since we used nullptr for pAdapter above) + IDXGIFactory1* dxgiFactory = nullptr; + IDXGIDevice* dxgiDevice = nullptr; + IDXGIAdapter* adapter = nullptr; + hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); + if (SUCCEEDED(hr)) { + hr = dxgiDevice->GetAdapter(&adapter); + if (SUCCEEDED(hr)) { + hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&dxgiFactory)); + adapter->Release(); + } + dxgiDevice->Release(); + } + int width; + int height; + GetRes(hWnd_, width, height); + + // DirectX 11.0 systems + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 1; + sd.BufferDesc.Width = width; + sd.BufferDesc.Height = height; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd_; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.Windowed = TRUE; + + hr = dxgiFactory->CreateSwapChain(device_, &sd, &swapChain_); + dxgiFactory->MakeWindowAssociation(hWnd_, DXGI_MWA_NO_ALT_ENTER); + dxgiFactory->Release(); + + if (FAILED(hr)) + return; + + // Create a render target view + ID3D11Texture2D* pBackBuffer = nullptr; + hr = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&pBackBuffer)); + if (FAILED(hr)) + return; + + hr = device_->CreateRenderTargetView(pBackBuffer, nullptr, &bbRenderTargetView_); + pBackBuffer->Release(); + if (FAILED(hr)) + return; + + // Create depth stencil texture + D3D11_TEXTURE2D_DESC descDepth{}; + descDepth.Width = width; + descDepth.Height = height; + descDepth.MipLevels = 1; + descDepth.ArraySize = 1; + descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + descDepth.SampleDesc.Count = 1; + descDepth.SampleDesc.Quality = 0; + descDepth.Usage = D3D11_USAGE_DEFAULT; + descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; + descDepth.CPUAccessFlags = 0; + descDepth.MiscFlags = 0; + hr = device_->CreateTexture2D(&descDepth, nullptr, &bbDepthStencilTex_); + + // Create the depth stencil view + D3D11_DEPTH_STENCIL_VIEW_DESC descDSV{}; + descDSV.Format = descDepth.Format; + descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + descDSV.Texture2D.MipSlice = 0; + hr = device_->CreateDepthStencilView(bbDepthStencilTex_, &descDSV, &bbDepthStencilView_); + + context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_); + + CreatePresets(); } D3D11DrawContext::~D3D11DrawContext() { @@ -132,7 +244,7 @@ void D3D11DrawContext::SetViewports(int count, Viewport *viewports) { } void D3D11DrawContext::SetScissorRect(int left, int top, int width, int height) { - D3D11_RECT rc; + D3D11_RECT rc{}; rc.left = left; rc.top = top; rc.right = left + width; @@ -170,19 +282,45 @@ static const D3D11_STENCIL_OP stencilOpToD3D11[] = { D3D11_STENCIL_OP_DECR, }; -DXGI_FORMAT dataFormatToD3D11(DataFormat format) { +static DXGI_FORMAT dataFormatToD3D11(DataFormat format) { switch (format) { case DataFormat::R32_FLOAT: return DXGI_FORMAT_R32_FLOAT; case DataFormat::R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT; case DataFormat::R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_FLOAT; case DataFormat::R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT; case DataFormat::R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; + case DataFormat::R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + case DataFormat::B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM; + case DataFormat::B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + case DataFormat::R16_FLOAT: return DXGI_FORMAT_R16_FLOAT; + case DataFormat::R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT; + case DataFormat::R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT; + case DataFormat::D24_S8: return DXGI_FORMAT_D24_UNORM_S8_UINT; + case DataFormat::D16: return DXGI_FORMAT_D16_UNORM; + case DataFormat::D32F: return DXGI_FORMAT_D32_FLOAT; + case DataFormat::D32F_S8: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; case DataFormat::ETC1: default: return DXGI_FORMAT_UNKNOWN; } } +static D3D11_PRIMITIVE_TOPOLOGY primToD3D11[] = { + D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, + D3D11_PRIMITIVE_TOPOLOGY_LINELIST, + D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED, + // Tesselation shader only + D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST, // ??? + // These are for geometry shaders only. + D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ, + D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ, +}; + inline void CopyStencilSide(D3D11_DEPTH_STENCILOP_DESC &side, const StencilSide &input) { side.StencilFunc = compareToD3D11[(int)input.compareOp]; side.StencilDepthFailOp = stencilOpToD3D11[(int)input.depthFailOp]; @@ -240,6 +378,7 @@ public: bs->Release(); } ID3D11BlendState *bs; + float blendFactor[4]; }; BlendState *D3D11DrawContext::CreateBlendState(const BlendStateDesc &desc) { @@ -382,31 +521,181 @@ public: D3D11BlendState *blend; D3D11DepthStencilState *depth; D3D11RasterState *raster; + ID3D11VertexShader *vs; + ID3D11PixelShader *ps; + ID3D11GeometryShader *gs; + D3D11_PRIMITIVE_TOPOLOGY topology; }; class D3D11Texture : public Texture { public: - D3D11Texture() {} - void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) {} + D3D11Texture(const TextureDesc &desc) { + width_ = desc.width; + height_ = desc.height; + depth_ = desc.depth; + } + ~D3D11Texture() { + if (tex) + tex->Release(); + if (view) + view->Release(); + } + + void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) { + ELOG("SetImageData not supported, create a new texture instead"); + } + + ID3D11Texture2D *tex = nullptr; + ID3D11ShaderResourceView *view = nullptr; }; Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) { - D3D11Texture *tex = new D3D11Texture(); + D3D11Texture *tex = new D3D11Texture(desc); - // .... + if (!(GetDataFormatSupport(desc.format) & FMT_TEXTURE)) { + // D3D11 does not support this format as a texture format. + return false; + } + D3D11_TEXTURE2D_DESC descColor{}; + descColor.Width = desc.width; + descColor.Height = desc.height; + descColor.MipLevels = desc.mipLevels; + descColor.ArraySize = 1; + descColor.Format = dataFormatToD3D11(desc.format); + descColor.SampleDesc.Count = 1; + descColor.SampleDesc.Quality = 0; + descColor.Usage = D3D11_USAGE_DEFAULT; + descColor.BindFlags = D3D11_BIND_SHADER_RESOURCE; + descColor.CPUAccessFlags = 0; + descColor.MiscFlags = 0; + + D3D11_SUBRESOURCE_DATA initData[12]{}; + if (desc.initData.size()) { + int w = desc.width; + int h = desc.height; + for (int i = 0; i < desc.initData.size(); i++) { + initData[i].pSysMem = desc.initData[0]; + initData[i].SysMemPitch = (UINT)(w * DataFormatSizeInBytes(desc.format)); + initData[i].SysMemSlicePitch = (UINT)(w * h * DataFormatSizeInBytes(desc.format)); + w /= 2; + h /= 2; + } + } + + HRESULT hr = device_->CreateTexture2D(&descColor, desc.initData.size() ? initData : nullptr, &tex->tex); + if (!SUCCEEDED(hr)) { + delete tex; + return nullptr; + } + hr = device_->CreateShaderResourceView(tex->tex, nullptr, &tex->view); + if (!SUCCEEDED(hr)) { + delete tex; + return nullptr; + } return tex; } - class D3D11ShaderModule : public ShaderModule { public: + ~D3D11ShaderModule() { + if (vs) + vs->Release(); + if (ps) + ps->Release(); + if (gs) + gs->Release(); + } + ShaderStage GetStage() const override { return stage; } + std::vector byteCode_; + ShaderStage stage; + + ID3D11VertexShader *vs = nullptr; + ID3D11PixelShader *ps = nullptr; + ID3D11GeometryShader *gs = nullptr; }; ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) { - // ... + switch (language) { + case ShaderLanguage::HLSL_D3D11: + case ShaderLanguage::HLSL_D3D11_BYTECODE: + break; + default: + ELOG("Unsupported shader language"); + return nullptr; + } + std::string compiled; + std::string errors; + if (language == ShaderLanguage::HLSL_D3D11) { + const char *target = nullptr; + switch (stage) { + case ShaderStage::FRAGMENT: target = "ps_5_0"; break; + case ShaderStage::GEOMETRY: target = "gs_5_0"; break; + case ShaderStage::VERTEX: target = "vs_5_0"; break; + break; + case ShaderStage::COMPUTE: + case ShaderStage::CONTROL: + case ShaderStage::EVALUATION: + default: + break; + } + if (!target) { + return nullptr; + } + + ID3DBlob *compiledCode = nullptr; + ID3DBlob *errorMsgs = nullptr; + HRESULT result = ptr_D3DCompile(data, dataSize, nullptr, nullptr, nullptr, "main", target, 0, 0, &compiledCode, &errorMsgs); + if (compiledCode) { + compiled = std::string((const char *)compiledCode->GetBufferPointer(), compiledCode->GetBufferSize()); + compiledCode->Release(); + } + if (errorMsgs) { + errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize()); + ELOG("Failed compiling:\n%s\n%s", data, errors.c_str()); + errorMsgs->Release(); + } + + if (result != S_OK) { + return nullptr; + } + + // OK, we can now proceed + language = ShaderLanguage::HLSL_D3D11_BYTECODE; + data = (const uint8_t *)compiled.c_str(); + dataSize = compiled.size(); + } + + if (language == ShaderLanguage::HLSL_D3D11_BYTECODE) { + // Easy! + D3D11ShaderModule *module = new D3D11ShaderModule(); + module->stage = stage; + module->byteCode_ = std::vector(data, data + dataSize); + HRESULT result = S_OK; + switch (stage) { + case ShaderStage::VERTEX: + result = device_->CreateVertexShader(data, dataSize, nullptr, &module->vs); + break; + case ShaderStage::FRAGMENT: + result = device_->CreatePixelShader(data, dataSize, nullptr, &module->ps); + break; + case ShaderStage::GEOMETRY: + result = device_->CreateGeometryShader(data, dataSize, nullptr, &module->gs); + break; + default: + ELOG("Unsupported shader stage"); + result = S_FALSE; + break; + } + if (result == S_OK) { + return module; + } else { + delete module; + return nullptr; + } + } return nullptr; } @@ -420,13 +709,25 @@ Pipeline *D3D11DrawContext::CreateGraphicsPipeline(const PipelineDesc &desc) { dPipeline->depth->AddRef(); dPipeline->input->AddRef(); dPipeline->raster->AddRef(); + dPipeline->topology = primToD3D11[(int)desc.prim]; std::vector shaders; D3D11ShaderModule *vshader = nullptr; for (auto iter : desc.shaders) { - shaders.push_back((D3D11ShaderModule *)iter); - if (iter->GetStage() == ShaderStage::VERTEX) - vshader = (D3D11ShaderModule *)iter; + D3D11ShaderModule *module = (D3D11ShaderModule *)iter; + shaders.push_back(module); + switch (module->GetStage()) { + case ShaderStage::VERTEX: + vshader = module; + dPipeline->vs = module->vs; + break; + case ShaderStage::FRAGMENT: + dPipeline->ps = module->ps; + break; + case ShaderStage::GEOMETRY: + dPipeline->gs = module->gs; + break; + } } if (!vshader) { @@ -438,15 +739,21 @@ Pipeline *D3D11DrawContext::CreateGraphicsPipeline(const PipelineDesc &desc) { // Can finally create the input layout auto &inputDesc = dPipeline->input->desc; const std::vector &elements = dPipeline->input->elements; - device_->CreateInputLayout(elements.data(), (UINT)elements.size(), vshader->byteCode_.data(), vshader->byteCode_.size(), &dPipeline->il); + HRESULT hr = device_->CreateInputLayout(elements.data(), (UINT)elements.size(), vshader->byteCode_.data(), vshader->byteCode_.size(), &dPipeline->il); + if (!SUCCEEDED(hr)) { + Crash(); + } return dPipeline; } void D3D11DrawContext::BindPipeline(Pipeline *pipeline) { D3D11Pipeline *dPipeline = (D3D11Pipeline *)pipeline; + if (curPipeline_ == dPipeline) + return; curPipeline_ = dPipeline; } +// Gonna need dirtyflags soon.. void D3D11DrawContext::ApplyCurrentState() { if (curBlend_ != curPipeline_->blend || blendFactorDirty_) { context_->OMSetBlendState(curPipeline_->blend->bs, blendFactor_, 0); @@ -466,44 +773,119 @@ void D3D11DrawContext::ApplyCurrentState() { context_->IASetInputLayout(curPipeline_->il); curInputLayout_ = curPipeline_->il; } + if (curVS_ != curPipeline_->vs) { + context_->VSSetShader(curPipeline_->vs, nullptr, 0); + curVS_ = curPipeline_->vs; + } + if (curPS_ != curPipeline_->ps) { + context_->PSSetShader(curPipeline_->ps, nullptr, 0); + curPS_ = curPipeline_->ps; + } + if (curGS_ != curPipeline_->gs) { + context_->GSSetShader(curPipeline_->gs, nullptr, 0); + curGS_ = curPipeline_->gs; + } + if (curTopology_ != curPipeline_->topology) { + context_->IASetPrimitiveTopology(curPipeline_->topology); + curTopology_ = curPipeline_->topology; + } + + int numVBs = (int)curPipeline_->input->strides.size(); + context_->IASetVertexBuffers(0, 1, nextVertexBuffers_, (UINT *)curPipeline_->input->strides.data(), (UINT *)nextVertexBufferOffsets_); + if (nextIndexBuffer_) { + context_->IASetIndexBuffer(nextIndexBuffer_, DXGI_FORMAT_R32_UINT, nextIndexBufferOffset_); + } } class D3D11Buffer : public Buffer { public: - ID3D11Buffer *buf; - - virtual void SetData(const uint8_t *data, size_t size) override { - - } - virtual void SubData(const uint8_t *data, size_t offset, size_t size) override { - + ~D3D11Buffer() { + if (buf) + buf->Release(); + if (srView) + srView->Release(); } + ID3D11Buffer *buf = nullptr; + ID3D11ShaderResourceView *srView = nullptr; + size_t size; }; Buffer *D3D11DrawContext::CreateBuffer(size_t size, uint32_t usageFlags) { D3D11Buffer *b = new D3D11Buffer(); + D3D11_BUFFER_DESC desc{}; + desc.ByteWidth = (UINT)size; + desc.BindFlags = 0; + if (usageFlags & VERTEXDATA) + desc.BindFlags |= D3D11_BIND_VERTEX_BUFFER; + if (usageFlags & INDEXDATA) + desc.BindFlags |= D3D11_BIND_INDEX_BUFFER; + if (usageFlags & UNIFORM) + desc.BindFlags |= D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.Usage = D3D11_USAGE_DYNAMIC; + + b->size = size; + HRESULT hr = device_->CreateBuffer(&desc, nullptr, &b->buf); + if (FAILED(hr)) { + delete b; + return nullptr; + } + if (usageFlags & UNIFORM) { + // D3D11_SHADER_RESOURCE_VIEW_DESC resDesc{}; + // device_->CreateShaderResourceView(b->buf, &resDesc, &b->srView); + } return b; } -void D3D11DrawContext::BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) { +void D3D11DrawContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) { + D3D11Buffer *buf = (D3D11Buffer *)buffer; + if ((flags & UPDATE_DISCARD) || (offset == 0 && size == buf->size)) { + // Can just discard the old contents. This is only allowed for DYNAMIC buffers. + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(buf->buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, data, size); + context_->Unmap(buf->buf, 0); + return; + } + + D3D11_BOX box{}; + box.left = (UINT)offset; + box.right = (UINT)(offset + size); + context_->UpdateSubresource(buf->buf, 0, &box, data, 0, 0); } + +void D3D11DrawContext::BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) { + // Lazy application + for (int i = 0; i < count; i++) { + D3D11Buffer *buf = (D3D11Buffer *)buffers[i]; + nextVertexBuffers_[start + i] = buf->buf; + nextVertexBufferOffsets_[start + i] = offsets ? offsets[i] : 0; + } +} + void D3D11DrawContext::BindIndexBuffer(Buffer *indexBuffer, int offset) { + D3D11Buffer *buf = (D3D11Buffer *)indexBuffer; + // Lazy application + nextIndexBuffer_ = buf->buf; + nextIndexBufferOffset_ = offset; } void D3D11DrawContext::Draw(int vertexCount, int offset) { ApplyCurrentState(); + context_->Draw(vertexCount, offset); } -void D3D11DrawContext::DrawIndexed(int vertexCount, int offset) { +void D3D11DrawContext::DrawIndexed(int indexCount, int offset) { ApplyCurrentState(); + context_->DrawIndexed(indexCount, offset, 0); } void D3D11DrawContext::DrawUP(const void *vdata, int vertexCount) { ApplyCurrentState(); + // TODO: Upload the data then draw.. } - uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const { // TODO: Actually do proper checks switch (fmt) { @@ -539,41 +921,172 @@ uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const { // A D3D11Framebuffer is a D3D11Framebuffer plus all the textures it owns. class D3D11Framebuffer : public Framebuffer { public: + D3D11Framebuffer() {} + ~D3D11Framebuffer() { + if (colorTex) + colorTex->Release(); + if (colorRTView) + colorRTView->Release(); + if (colorSRView) + colorSRView->Release(); + if (depthStencilTex) + depthStencilTex->Release(); + if (depthStencilRTView) + depthStencilRTView->Release(); + } int width; int height; + + ID3D11Texture2D *colorTex = nullptr; + ID3D11RenderTargetView *colorRTView = nullptr; + ID3D11ShaderResourceView *colorSRView = nullptr; + + ID3D11Texture2D *depthStencilTex = nullptr; + ID3D11DepthStencilView *depthStencilRTView = nullptr; }; Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) { + HRESULT hr; D3D11Framebuffer *fb = new D3D11Framebuffer(); fb->width = desc.width; fb->height = desc.height; + if (desc.numColorAttachments) { + D3D11_TEXTURE2D_DESC descColor{}; + descColor.Width = desc.width; + descColor.Height = desc.height; + descColor.MipLevels = 1; + descColor.ArraySize = 1; + descColor.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + descColor.SampleDesc.Count = 1; + descColor.SampleDesc.Quality = 0; + descColor.Usage = D3D11_USAGE_DEFAULT; + descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + descColor.CPUAccessFlags = 0; + descColor.MiscFlags = 0; + hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + hr = device_->CreateRenderTargetView(fb->colorTex, nullptr, &fb->colorRTView); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + hr = device_->CreateShaderResourceView(fb->colorTex, nullptr, &fb->colorSRView); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + } + + if (desc.z_stencil) { + D3D11_TEXTURE2D_DESC descDepth{}; + descDepth.Width = desc.width; + descDepth.Height = desc.height; + descDepth.MipLevels = 1; + descDepth.ArraySize = 1; + descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + descDepth.SampleDesc.Count = 1; + descDepth.SampleDesc.Quality = 0; + descDepth.Usage = D3D11_USAGE_DEFAULT; + descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; + descDepth.CPUAccessFlags = 0; + descDepth.MiscFlags = 0; + hr = device_->CreateTexture2D(&descDepth, nullptr, &fb->depthStencilTex); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + D3D11_DEPTH_STENCIL_VIEW_DESC descDSV{}; + descDSV.Format = descDepth.Format; + descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + descDSV.Texture2D.MipSlice = 0; + hr = device_->CreateDepthStencilView(fb->depthStencilTex, &descDSV, &fb->depthStencilRTView); + if (FAILED(hr)) { + delete fb; + return nullptr; + } + } + return fb; } void D3D11DrawContext::BindTextures(int start, int count, Texture **textures) { - + // Collect the resource views from the textures. + ID3D11ShaderResourceView *views[8]; + for (int i = 0; i < count; i++) { + D3D11Texture *tex = (D3D11Texture *)textures[i]; + views[i] = tex->view; + } + context_->PSSetShaderResources(start, count, views); } void D3D11DrawContext::BindSamplerStates(int start, int count, SamplerState **states) { - + ID3D11SamplerState *samplers[8]; + for (int i = 0; i < count; i++) { + D3D11SamplerState *samp = (D3D11SamplerState *)states[i]; + samplers[i] = samp->ss; + } + context_->PSSetSamplers(start, count, samplers); } void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) { - + if (mask & ClearFlag::COLOR) { + float colorRGBA[4]; + Uint8x1ToFloat4(colorRGBA, colorval); + context_->ClearRenderTargetView(bbRenderTargetView_, colorRGBA); + } + if (mask & (ClearFlag::DEPTH | ClearFlag::STENCIL)) { + UINT clearFlag = 0; + if (mask & ClearFlag::DEPTH) + clearFlag |= D3D11_CLEAR_DEPTH; + if (mask & ClearFlag::STENCIL) + clearFlag |= D3D11_CLEAR_STENCIL; + context_->ClearDepthStencilView(bbDepthStencilView_, clearFlag, depthVal, stencilVal); + } } -void D3D11DrawContext::CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) {} -bool D3D11DrawContext::BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { return true; } +void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) { + D3D11Framebuffer *src = (D3D11Framebuffer *)srcfb; + D3D11Framebuffer *dst = (D3D11Framebuffer *)dstfb; + + // CopySubResource ? +} + +bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) { + D3D11Framebuffer *src = (D3D11Framebuffer *)srcfb; + D3D11Framebuffer *dst = (D3D11Framebuffer *)dstfb; + + // Unfortunately D3D11 has no equivalent to this, gotta render a quad. + return true; +} // These functions should be self explanatory. -void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo) {} -// color must be 0, for now. -void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) {} -void D3D11DrawContext::BindFramebufferForRead(Framebuffer *fbo) {} +void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo) { + D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; + context_->OMSetRenderTargets(1, &fb->colorRTView, fb->depthStencilRTView); +} -void D3D11DrawContext::BindBackbufferAsRenderTarget() {} -uintptr_t D3D11DrawContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { return 0; } +// color must be 0, for now. +void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) { + D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; + context_->PSSetShaderResources(binding, 1, &fb->colorSRView); +} + +void D3D11DrawContext::BindFramebufferForRead(Framebuffer *fbo) { + // This is meaningless in D3D11 +} + +void D3D11DrawContext::BindBackbufferAsRenderTarget() { + context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_); +} + +uintptr_t D3D11DrawContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { + // D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; + return 0; +} void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; @@ -581,8 +1094,8 @@ void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h *h = fb->height; } -DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context) { - return nullptr; // new D3D11DrawContext(device, context); +DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, HWND hWnd) { + return new D3D11DrawContext(device, context, hWnd); } } // namespace Draw \ No newline at end of file diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index b2c61be3a2..8e7bad916b 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -142,6 +142,8 @@ static int FormatToD3DDeclType(DataFormat type) { } } +class D3D9Buffer; + class D3D9DepthStencilState : public DepthStencilState { public: BOOL depthTestEnabled; @@ -219,77 +221,6 @@ public: } }; -// Simulate a simple buffer type like the other backends have, use the usage flags to create the right internal type. -class D3D9Buffer : public Buffer { -public: - D3D9Buffer(LPDIRECT3DDEVICE9 device, size_t size, uint32_t flags) : vbuffer_(nullptr), ibuffer_(nullptr), maxSize_(size) { - if (flags & BufferUsageFlag::INDEXDATA) { - DWORD usage = D3DUSAGE_DYNAMIC; - device->CreateIndexBuffer((UINT)size, usage, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &ibuffer_, NULL); - } - else { - DWORD usage = D3DUSAGE_DYNAMIC; - device->CreateVertexBuffer((UINT)size, usage, 0, D3DPOOL_DEFAULT, &vbuffer_, NULL); - } - } - virtual ~D3D9Buffer() override { - if (ibuffer_) { - ibuffer_->Release(); - } - if (vbuffer_) { - vbuffer_->Release(); - } - } - - void SetData(const uint8_t *data, size_t size) override { - if (!size) - return; - if (size > maxSize_) { - ELOG("Can't SetData with bigger size than buffer was created with on D3D"); - return; - } - if (vbuffer_) { - void *ptr; - vbuffer_->Lock(0, (UINT)size, &ptr, D3DLOCK_DISCARD); - memcpy(ptr, data, size); - vbuffer_->Unlock(); - } else if (ibuffer_) { - void *ptr; - ibuffer_->Lock(0, (UINT)size, &ptr, D3DLOCK_DISCARD); - memcpy(ptr, data, size); - ibuffer_->Unlock(); - } - } - void SubData(const uint8_t *data, size_t offset, size_t size) override { - if (!size) - return; - if (offset + size > maxSize_) { - ELOG("Can't SubData with bigger size than buffer was created with on D3D"); - return; - } - if (vbuffer_) { - void *ptr; - HRESULT res = vbuffer_->Lock((UINT)offset, (UINT)size, &ptr, D3DLOCK_DISCARD); - if (!FAILED(res)) { - memcpy(ptr, data, size); - vbuffer_->Unlock(); - } - } else if (ibuffer_) { - void *ptr; - HRESULT res = ibuffer_->Lock((UINT)offset, (UINT)size, &ptr, D3DLOCK_DISCARD); - if (!FAILED(res)) { - memcpy(ptr, data, size); - ibuffer_->Unlock(); - } - } - } - -public: - LPDIRECT3DVERTEXBUFFER9 vbuffer_; - LPDIRECT3DINDEXBUFFER9 ibuffer_; - size_t maxSize_; -}; - class D3D9InputLayout : public InputLayout { public: D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc &desc); @@ -550,6 +481,9 @@ public: Texture *CreateTexture(const TextureDesc &desc) override; Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override; + + void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) override {} bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; @@ -847,10 +781,61 @@ D3D9InputLayout::D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc delete[] elements; } +// Simulate a simple buffer type like the other backends have, use the usage flags to create the right internal type. +class D3D9Buffer : public Buffer { +public: + D3D9Buffer(LPDIRECT3DDEVICE9 device, size_t size, uint32_t flags) : vbuffer_(nullptr), ibuffer_(nullptr), maxSize_(size) { + if (flags & BufferUsageFlag::INDEXDATA) { + DWORD usage = D3DUSAGE_DYNAMIC; + device->CreateIndexBuffer((UINT)size, usage, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &ibuffer_, NULL); + } else { + DWORD usage = D3DUSAGE_DYNAMIC; + device->CreateVertexBuffer((UINT)size, usage, 0, D3DPOOL_DEFAULT, &vbuffer_, NULL); + } + } + virtual ~D3D9Buffer() override { + if (ibuffer_) { + ibuffer_->Release(); + } + if (vbuffer_) { + vbuffer_->Release(); + } + } + + LPDIRECT3DVERTEXBUFFER9 vbuffer_; + LPDIRECT3DINDEXBUFFER9 ibuffer_; + size_t maxSize_; +}; + Buffer *D3D9Context::CreateBuffer(size_t size, uint32_t usageFlags) { return new D3D9Buffer(device_, size, usageFlags); } +void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) { + D3D9Buffer *buf = (D3D9Buffer *)buffer; + if (!size) + return; + if (offset + size > buf->maxSize_) { + ELOG("Can't SubData with bigger size than buffer was created with"); + return; + } + if (buf->vbuffer_) { + void *ptr; + HRESULT res = buf->vbuffer_->Lock((UINT)offset, (UINT)size, &ptr, (flags & UPDATE_DISCARD) ? D3DLOCK_DISCARD : 0); + if (!FAILED(res)) { + memcpy(ptr, data, size); + buf->vbuffer_->Unlock(); + } + } else if (buf->ibuffer_) { + void *ptr; + HRESULT res = buf->ibuffer_->Lock((UINT)offset, (UINT)size, &ptr, (flags & UPDATE_DISCARD) ? D3DLOCK_DISCARD : 0); + if (!FAILED(res)) { + memcpy(ptr, data, size); + buf->ibuffer_->Unlock(); + } + } +} + void D3D9Pipeline::Apply(LPDIRECT3DDEVICE9 device) { vshader->Apply(device); pshader->Apply(device); diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 9bb4ede624..22dc8e4e3c 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -153,6 +153,8 @@ static const unsigned short primToGL[] = { #endif }; +class OpenGLBuffer; + static const char *glsl_fragment_prelude = "#ifdef GL_ES\n" "precision mediump float;\n" @@ -270,62 +272,6 @@ public: GLenum frontFace; }; -class OpenGLBuffer : public Buffer, GfxResourceHolder { -public: - OpenGLBuffer(size_t size, uint32_t flags) { - glGenBuffers(1, &buffer_); - target_ = (flags & BufferUsageFlag::INDEXDATA) ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER; - usage_ = 0; - if (flags & BufferUsageFlag::DYNAMIC) - usage_ = GL_STREAM_DRAW; - else - usage_ = GL_STATIC_DRAW; - knownSize_ = 0; - register_gl_resource_holder(this); - } - ~OpenGLBuffer() override { - unregister_gl_resource_holder(this); - glDeleteBuffers(1, &buffer_); - } - - void SetData(const uint8_t *data, size_t size) override { - Bind(0); - glBufferData(target_, size, data, usage_); - knownSize_ = size; - } - - void SubData(const uint8_t *data, size_t offset, size_t size) override { - Bind(0); - if (size + offset > knownSize_) { - // Allocate the buffer. - glBufferData(target_, size + offset, NULL, usage_); - knownSize_ = size + offset; - } - glBufferSubData(target_, offset, size, data); - } - void Bind(int offset) { - // TODO: Can't support offset using ES 2.0 - glBindBuffer(target_, buffer_); - } - - void GLLost() override { - buffer_ = 0; - } - - void GLRestore() override { - ILOG("Recreating vertex buffer after gl_restore"); - knownSize_ = 0; // Will cause a new glBufferData call. Should genBuffers again though? - glGenBuffers(1, &buffer_); - } - -private: - GLuint buffer_; - GLuint target_; - GLuint usage_; - - size_t knownSize_; -}; - GLuint ShaderStageToOpenGL(ShaderStage stage) { switch (stage) { case ShaderStage::VERTEX: return GL_VERTEX_SHADER; @@ -524,6 +470,8 @@ public: Buffer *CreateBuffer(size_t size, uint32_t usageFlags) override; Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override; + void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) override; bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; @@ -939,10 +887,63 @@ RasterState *OpenGLContext::CreateRasterState(const RasterStateDesc &desc) { return rs; } +class OpenGLBuffer : public Buffer, GfxResourceHolder { +public: + OpenGLBuffer(size_t size, uint32_t flags) { + glGenBuffers(1, &buffer_); + target_ = (flags & BufferUsageFlag::INDEXDATA) ? GL_ELEMENT_ARRAY_BUFFER : GL_ARRAY_BUFFER; + usage_ = 0; + if (flags & BufferUsageFlag::DYNAMIC) + usage_ = GL_STREAM_DRAW; + else + usage_ = GL_STATIC_DRAW; + totalSize_ = size; + glBindBuffer(target_, buffer_); + glBufferData(target_, size, NULL, usage_); + register_gl_resource_holder(this); + } + ~OpenGLBuffer() override { + unregister_gl_resource_holder(this); + glDeleteBuffers(1, &buffer_); + } + + void Bind(int offset) { + // TODO: Can't support offset using ES 2.0 + glBindBuffer(target_, buffer_); + } + + void GLLost() override { + buffer_ = 0; + } + + void GLRestore() override { + ILOG("Recreating vertex buffer after gl_restore"); + totalSize_ = 0; // Will cause a new glBufferData call. Should genBuffers again though? + glGenBuffers(1, &buffer_); + } + + GLuint buffer_; + GLuint target_; + GLuint usage_; + + size_t totalSize_; +}; + Buffer *OpenGLContext::CreateBuffer(size_t size, uint32_t usageFlags) { return new OpenGLBuffer(size, usageFlags); } +void OpenGLContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) { + OpenGLBuffer *buf = (OpenGLBuffer *)buffer; + + buf->Bind(0); + if (size + offset > buf->totalSize_) { + Crash(); + } + // if (flags & UPDATE_DISCARD) we could try to orphan the buffer using glBufferData. + glBufferSubData(buf->target_, offset, size, data); +} + Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc) { if (!desc.shaders.size()) { ELOG("Pipeline requires at least one shader"); diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 204905bc66..21da29347b 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -176,38 +176,6 @@ public: } }; -// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw, -// to avoid synchronization issues. -class VKBuffer : public Buffer { -public: - VKBuffer(size_t size, uint32_t flags) : dataSize_(size) { - data_ = new uint8_t[size]; - } - ~VKBuffer() override { - delete[] data_; - } - - void SetData(const uint8_t *data, size_t size) override { - delete[] data_; - dataSize_ = size; - data_ = new uint8_t[size]; - if (data) { - memcpy(data_, data, size); - } - } - - void SubData(const uint8_t *data, size_t offset, size_t size) override { - memcpy(data_, data_ + offset, size); - } - - size_t GetSize() const { return dataSize_; } - const uint8_t *GetData() const { return data_; } - -private: - uint8_t *data_; - size_t dataSize_; -}; - VkShaderStageFlagBits StageToVulkan(ShaderStage stage) { switch (stage) { case ShaderStage::VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; @@ -329,6 +297,7 @@ private: }; class VKTexture; +class VKBuffer; class VKSamplerState; struct DescriptorSetKey { @@ -369,6 +338,8 @@ public: Buffer *CreateBuffer(size_t size, uint32_t usageFlags) override; Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override; + void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override; + void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth) override; bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override; @@ -1057,10 +1028,33 @@ BlendState *VKContext::CreateBlendState(const BlendStateDesc &desc) { return bs; } +// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw, +// to avoid synchronization issues. +class VKBuffer : public Buffer { +public: + VKBuffer(size_t size, uint32_t flags) : dataSize_(size) { + data_ = new uint8_t[size]; + } + ~VKBuffer() override { + delete[] data_; + } + + size_t GetSize() const { return dataSize_; } + const uint8_t *GetData() const { return data_; } + + uint8_t *data_; + size_t dataSize_; +}; + Buffer *VKContext::CreateBuffer(size_t size, uint32_t usageFlags) { return new VKBuffer(size, usageFlags); } +void VKContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) { + VKBuffer *buf = (VKBuffer *)buffer; + memcpy(buf->data_ + offset, data, size); +} + void VKContext::BindTextures(int start, int count, Texture **textures) { for (int i = start; i < start + count; i++) { boundTextures_[i] = static_cast(textures[i]);