blob: ff73d2b87d402d08606634d1c79dc4af0f030350 [file] [log] [blame]
#include "fiddle_context.hpp"
#ifndef _WIN32
std::unique_ptr<FiddleContext> FiddleContext::MakeD3DPLS(FiddleContextOptions) { return nullptr; }
#else
#include "rive/pls/pls_renderer.hpp"
#include "rive/pls/d3d/pls_render_context_d3d_impl.hpp"
#include "rive/pls/d3d/d3d11.hpp"
#include <array>
#include <dxgi1_2.h>
#define GLFW_INCLUDE_NONE
#define GLFW_EXPOSE_NATIVE_WIN32
#include "GLFW/glfw3.h"
#include <GLFW/glfw3native.h>
using namespace rive;
using namespace rive::pls;
class FiddleContextD3DPLS : public FiddleContext
{
public:
FiddleContextD3DPLS(ComPtr<IDXGIFactory2> d3dFactory,
ComPtr<ID3D11Device> gpu,
ComPtr<ID3D11DeviceContext> gpuContext,
const PLSRenderContextD3DImpl::ContextOptions& contextOptions) :
m_d3dFactory(std::move(d3dFactory)),
m_gpu(std::move(gpu)),
m_gpuContext(std::move(gpuContext)),
m_plsContext(PLSRenderContextD3DImpl::MakeContext(m_gpu, m_gpuContext, contextOptions))
{}
float dpiScale(GLFWwindow*) const override { return 1; }
rive::Factory* factory() override { return m_plsContext.get(); }
rive::pls::PLSRenderContext* plsContextOrNull() override { return m_plsContext.get(); }
rive::pls::PLSRenderTarget* plsRenderTargetOrNull() override { return m_renderTarget.get(); }
void onSizeChanged(GLFWwindow* window, int width, int height, uint32_t sampleCount) override
{
m_swapchain.Reset();
DXGI_SWAP_CHAIN_DESC1 scd{};
scd.Width = width;
scd.Height = height;
scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.SampleDesc.Count = 1;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_UNORDERED_ACCESS;
scd.BufferCount = 2;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
VERIFY_OK(m_d3dFactory->CreateSwapChainForHwnd(m_gpu.Get(),
glfwGetWin32Window(window),
&scd,
NULL,
NULL,
m_swapchain.ReleaseAndGetAddressOf()));
auto plsContextImpl = m_plsContext->static_impl_cast<PLSRenderContextD3DImpl>();
m_renderTarget = plsContextImpl->makeRenderTarget(width, height);
m_readbackTexture = nullptr;
}
void toggleZoomWindow() override {}
std::unique_ptr<Renderer> makeRenderer(int width, int height) override
{
return std::make_unique<PLSRenderer>(m_plsContext.get());
}
void begin(const rive::pls::PLSRenderContext::FrameDescriptor& frameDescriptor) override
{
m_plsContext->beginFrame(frameDescriptor);
}
void flushPLSContext() final
{
if (m_renderTarget->targetTexture() == nullptr)
{
ComPtr<ID3D11Texture2D> backbuffer;
VERIFY_OK(m_swapchain->GetBuffer(
0,
__uuidof(ID3D11Texture2D),
reinterpret_cast<void**>(backbuffer.ReleaseAndGetAddressOf())));
m_renderTarget->setTargetTexture(backbuffer);
}
m_plsContext->flush({.renderTarget = m_renderTarget.get()});
}
void end(GLFWwindow*, std::vector<uint8_t>* pixelData = nullptr) override
{
flushPLSContext();
if (pixelData != nullptr)
{
uint32_t w = m_renderTarget->width();
uint32_t h = m_renderTarget->height();
if (m_readbackTexture == nullptr)
{
D3D11_TEXTURE2D_DESC readbackTexDesc{};
readbackTexDesc.Width = w;
readbackTexDesc.Height = h;
readbackTexDesc.MipLevels = 1;
readbackTexDesc.ArraySize = 1;
readbackTexDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
readbackTexDesc.SampleDesc.Count = 1;
readbackTexDesc.Usage = D3D11_USAGE_STAGING;
readbackTexDesc.BindFlags = 0;
readbackTexDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
readbackTexDesc.MiscFlags = 0;
VERIFY_OK(m_gpu->CreateTexture2D(&readbackTexDesc,
nullptr,
m_readbackTexture.ReleaseAndGetAddressOf()));
}
D3D11_MAPPED_SUBRESOURCE map;
m_gpuContext->CopyResource(m_readbackTexture.Get(), m_renderTarget->targetTexture());
m_gpuContext->Map(m_readbackTexture.Get(), 0, D3D11_MAP_READ, 0, &map);
pixelData->resize(h * w * 4);
for (uint32_t y = 0; y < h; ++y)
{
auto row = reinterpret_cast<const char*>(map.pData) + map.RowPitch * y;
memcpy(pixelData->data() + (h - y - 1) * w * 4, row, w * 4);
}
m_gpuContext->Unmap(m_readbackTexture.Get(), 0);
}
m_swapchain->Present(0, 0);
m_renderTarget->setTargetTexture(nullptr);
}
private:
ComPtr<IDXGIFactory2> m_d3dFactory;
ComPtr<ID3D11Device> m_gpu;
ComPtr<ID3D11DeviceContext> m_gpuContext;
ComPtr<IDXGISwapChain1> m_swapchain;
ComPtr<ID3D11Texture2D> m_readbackTexture;
std::unique_ptr<PLSRenderContext> m_plsContext;
rcp<PLSRenderTargetD3D> m_renderTarget;
};
std::unique_ptr<FiddleContext> FiddleContext::MakeD3DPLS(FiddleContextOptions fiddleOptions)
{
// Create a DXGIFactory object.
ComPtr<IDXGIFactory2> factory;
VERIFY_OK(CreateDXGIFactory(__uuidof(IDXGIFactory2),
reinterpret_cast<void**>(factory.ReleaseAndGetAddressOf())));
ComPtr<IDXGIAdapter> adapter;
DXGI_ADAPTER_DESC adapterDesc{};
PLSRenderContextD3DImpl::ContextOptions contextOptions;
if (fiddleOptions.disableRasterOrdering)
{
contextOptions.disableRasterizerOrderedViews = true;
// Also disable typed UAVs in atomic mode, to get more complete test coverage.
contextOptions.disableTypedUAVLoadStore = true;
}
for (UINT i = 0; factory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND; ++i)
{
adapter->GetDesc(&adapterDesc);
contextOptions.isIntel = adapterDesc.VendorId == 0x163C || adapterDesc.VendorId == 0x8086 ||
adapterDesc.VendorId == 0x8087;
break;
}
ComPtr<ID3D11Device> gpu;
ComPtr<ID3D11DeviceContext> gpuContext;
D3D_FEATURE_LEVEL featureLevels[] = {D3D_FEATURE_LEVEL_11_1};
UINT creationFlags = 0;
#ifdef DEBUG
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
VERIFY_OK(D3D11CreateDevice(adapter.Get(),
D3D_DRIVER_TYPE_UNKNOWN,
NULL,
creationFlags,
featureLevels,
std::size(featureLevels),
D3D11_SDK_VERSION,
gpu.ReleaseAndGetAddressOf(),
NULL,
gpuContext.ReleaseAndGetAddressOf()));
if (!gpu || !gpuContext)
{
return nullptr;
}
printf("D3D device: %S\n", adapterDesc.Description);
return std::make_unique<FiddleContextD3DPLS>(std::move(factory),
std::move(gpu),
std::move(gpuContext),
contextOptions);
}
#endif