librashader/test/capi-tests/librashader-capi-tests/dx11-example/main.cpp
2023-02-16 21:32:05 -05:00

417 lines
16 KiB
C++
Vendored

// based off https://github.com/kevinmoran/BeginnerDirect3D11/tree/master/02.%20Drawing%20a%20Triangle
//
// This example should not be taken as "good" code, it is just an example of how to use librashader in Direct3D11.
//
// Namely, you should not recreate the input texture every frame. It is much cheaper to have one long lived copy texture.
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#define UNICODE
#include <d3d11_1.h>
#include <windows.h>
#pragma comment(lib, "d3d11.lib")
#include <d3dcompiler.h>
#pragma comment(lib, "d3dcompiler.lib")
#include <assert.h>
#define LIBRA_RUNTIME_D3D11
#define LIBRA_RUNTIME_D3D12
#include "../../../../include/librashader.h"
#include "../../../../include/librashader_ld.h"
static bool global_windowDidResize = false;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
LRESULT result = 0;
switch (msg) {
case WM_KEYDOWN: {
if (wparam == VK_ESCAPE) DestroyWindow(hwnd);
break;
}
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
case WM_SIZE: {
global_windowDidResize = true;
break;
}
default:
result = DefWindowProcW(hwnd, msg, wparam, lparam);
}
return result;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
LPSTR /*lpCmdLine*/, int /*nShowCmd*/) {
// Open a window
HWND hwnd;
{
WNDCLASSEXW winClass = {};
winClass.cbSize = sizeof(WNDCLASSEXW);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = &WndProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIconW(0, IDI_APPLICATION);
winClass.hCursor = LoadCursorW(0, IDC_ARROW);
winClass.lpszClassName = L"MyWindowClass";
winClass.hIconSm = LoadIconW(0, IDI_APPLICATION);
if (!RegisterClassExW(&winClass)) {
MessageBoxA(0, "RegisterClassEx failed", "Fatal Error", MB_OK);
return GetLastError();
}
RECT initialRect = {0, 0, 1024, 768};
AdjustWindowRectEx(&initialRect, WS_OVERLAPPEDWINDOW, FALSE,
WS_EX_OVERLAPPEDWINDOW);
LONG initialWidth = initialRect.right - initialRect.left;
LONG initialHeight = initialRect.bottom - initialRect.top;
hwnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, winClass.lpszClassName,
L"librashader-capi DirectX 11",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,
CW_USEDEFAULT, initialWidth, initialHeight, 0, 0,
hInstance, 0);
if (!hwnd) {
MessageBoxA(0, "CreateWindowEx failed", "Fatal Error", MB_OK);
return GetLastError();
}
}
// Create D3D11 Device and Context
ID3D11Device1* d3d11Device;
ID3D11DeviceContext1* d3d11DeviceContext;
{
ID3D11Device* baseDevice;
ID3D11DeviceContext* baseDeviceContext;
D3D_FEATURE_LEVEL featureLevels[] = {D3D_FEATURE_LEVEL_11_0};
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#if defined(DEBUG_BUILD)
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
HRESULT hResult = D3D11CreateDevice(
0, D3D_DRIVER_TYPE_HARDWARE, 0, creationFlags, featureLevels,
ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &baseDevice, 0,
&baseDeviceContext);
if (FAILED(hResult)) {
MessageBoxA(0, "D3D11CreateDevice() failed", "Fatal Error", MB_OK);
return GetLastError();
}
// Get 1.1 interface of D3D11 Device and Context
hResult = baseDevice->QueryInterface(__uuidof(ID3D11Device1),
(void**)&d3d11Device);
assert(SUCCEEDED(hResult));
baseDevice->Release();
hResult = baseDeviceContext->QueryInterface(
__uuidof(ID3D11DeviceContext1), (void**)&d3d11DeviceContext);
assert(SUCCEEDED(hResult));
baseDeviceContext->Release();
}
#ifdef DEBUG_BUILD
// Set up debug layer to break on D3D11 errors
ID3D11Debug* d3dDebug = nullptr;
d3d11Device->QueryInterface(__uuidof(ID3D11Debug), (void**)&d3dDebug);
if (d3dDebug) {
ID3D11InfoQueue* d3dInfoQueue = nullptr;
if (SUCCEEDED(d3dDebug->QueryInterface(__uuidof(ID3D11InfoQueue),
(void**)&d3dInfoQueue))) {
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION,
true);
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR,
true);
d3dInfoQueue->Release();
}
d3dDebug->Release();
}
#endif
auto libra = librashader_load_instance();
libra_shader_preset_t preset;
auto error = libra.preset_create(
"../../../shaders_slang/border/gameboy-player/"
"gameboy-player-crt-royale.slangp",
&preset);
libra_d3d11_filter_chain_t filter_chain;
libra.d3d11_filter_chain_create(&preset, d3d11Device, NULL,
&filter_chain);
// Create Swap Chain
IDXGISwapChain1* d3d11SwapChain;
{
// Get DXGI Factory (needed to create Swap Chain)
IDXGIFactory2* dxgiFactory;
{
IDXGIDevice1* dxgiDevice;
HRESULT hResult = d3d11Device->QueryInterface(
__uuidof(IDXGIDevice1), (void**)&dxgiDevice);
assert(SUCCEEDED(hResult));
IDXGIAdapter* dxgiAdapter;
hResult = dxgiDevice->GetAdapter(&dxgiAdapter);
assert(SUCCEEDED(hResult));
dxgiDevice->Release();
DXGI_ADAPTER_DESC adapterDesc;
dxgiAdapter->GetDesc(&adapterDesc);
OutputDebugStringA("Graphics Device: ");
OutputDebugStringW(adapterDesc.Description);
hResult = dxgiAdapter->GetParent(__uuidof(IDXGIFactory2),
(void**)&dxgiFactory);
assert(SUCCEEDED(hResult));
dxgiAdapter->Release();
}
DXGI_SWAP_CHAIN_DESC1 d3d11SwapChainDesc = {};
d3d11SwapChainDesc.Width = 0; // use window width
d3d11SwapChainDesc.Height = 0; // use window height
d3d11SwapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
d3d11SwapChainDesc.SampleDesc.Count = 1;
d3d11SwapChainDesc.SampleDesc.Quality = 0;
d3d11SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
d3d11SwapChainDesc.BufferCount = 2;
d3d11SwapChainDesc.Scaling = DXGI_SCALING_STRETCH;
d3d11SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
d3d11SwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
d3d11SwapChainDesc.Flags = 0;
HRESULT hResult = dxgiFactory->CreateSwapChainForHwnd(
d3d11Device, hwnd, &d3d11SwapChainDesc, 0, 0, &d3d11SwapChain);
assert(SUCCEEDED(hResult));
dxgiFactory->Release();
}
// Create Framebuffer Render Target
ID3D11RenderTargetView* d3d11FrameBufferView;
{
ID3D11Texture2D* d3d11FrameBuffer;
HRESULT hResult = d3d11SwapChain->GetBuffer(
0, __uuidof(ID3D11Texture2D), (void**)&d3d11FrameBuffer);
assert(SUCCEEDED(hResult));
hResult = d3d11Device->CreateRenderTargetView(d3d11FrameBuffer, 0,
&d3d11FrameBufferView);
assert(SUCCEEDED(hResult));
d3d11FrameBuffer->Release();
}
// Create Vertex Shader
ID3DBlob* vsBlob;
ID3D11VertexShader* vertexShader;
{
ID3DBlob* shaderCompileErrorsBlob;
HRESULT hResult = D3DCompileFromFile(L"shaders.hlsl", nullptr, nullptr,
"vs_main", "vs_5_0", 0, 0, &vsBlob,
&shaderCompileErrorsBlob);
if (FAILED(hResult)) {
const char* errorString = NULL;
if (hResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
errorString = "Could not compile shader; file not found";
else if (shaderCompileErrorsBlob) {
errorString =
(const char*)shaderCompileErrorsBlob->GetBufferPointer();
shaderCompileErrorsBlob->Release();
}
MessageBoxA(0, errorString, "Shader Compiler Error",
MB_ICONERROR | MB_OK);
return 1;
}
hResult = d3d11Device->CreateVertexShader(vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
nullptr, &vertexShader);
assert(SUCCEEDED(hResult));
}
// Create Pixel Shader
ID3D11PixelShader* pixelShader;
{
ID3DBlob* psBlob;
ID3DBlob* shaderCompileErrorsBlob;
HRESULT hResult = D3DCompileFromFile(L"shaders.hlsl", nullptr, nullptr,
"ps_main", "ps_5_0", 0, 0, &psBlob,
&shaderCompileErrorsBlob);
if (FAILED(hResult)) {
const char* errorString = NULL;
if (hResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
errorString = "Could not compile shader; file not found";
else if (shaderCompileErrorsBlob) {
errorString =
(const char*)shaderCompileErrorsBlob->GetBufferPointer();
shaderCompileErrorsBlob->Release();
}
MessageBoxA(0, errorString, "Shader Compiler Error",
MB_ICONERROR | MB_OK);
return 1;
}
hResult = d3d11Device->CreatePixelShader(psBlob->GetBufferPointer(),
psBlob->GetBufferSize(),
nullptr, &pixelShader);
assert(SUCCEEDED(hResult));
psBlob->Release();
}
// Create Input Layout
ID3D11InputLayout* inputLayout;
{
D3D11_INPUT_ELEMENT_DESC inputElementDesc[] = {
{"POS", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0,
D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}};
HRESULT hResult = d3d11Device->CreateInputLayout(
inputElementDesc, ARRAYSIZE(inputElementDesc),
vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &inputLayout);
assert(SUCCEEDED(hResult));
vsBlob->Release();
}
// Create Vertex Buffer
ID3D11Buffer* vertexBuffer;
UINT numVerts;
UINT stride;
UINT offset;
{
float vertexData[] = {// x, y, r, g, b, a
0.0f, 0.5f, 0.f, 1.f, 0.f, 1.f,
0.5f, -0.5f, 1.f, 0.f, 0.f, 1.f,
-0.5f, -0.5f, 0.f, 0.f, 1.f, 1.f};
stride = 6 * sizeof(float);
numVerts = sizeof(vertexData) / stride;
offset = 0;
D3D11_BUFFER_DESC vertexBufferDesc = {};
vertexBufferDesc.ByteWidth = sizeof(vertexData);
vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vertexSubresourceData = {vertexData};
HRESULT hResult = d3d11Device->CreateBuffer(
&vertexBufferDesc, &vertexSubresourceData, &vertexBuffer);
assert(SUCCEEDED(hResult));
}
// Main Loop
bool isRunning = true;
size_t frameCount = 0;
while (isRunning) {
MSG msg = {};
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) isRunning = false;
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
if (global_windowDidResize) {
d3d11DeviceContext->OMSetRenderTargets(0, 0, 0);
d3d11FrameBufferView->Release();
HRESULT res =
d3d11SwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
assert(SUCCEEDED(res));
ID3D11Texture2D* d3d11FrameBuffer;
res = d3d11SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
(void**)&d3d11FrameBuffer);
assert(SUCCEEDED(res));
res = d3d11Device->CreateRenderTargetView(d3d11FrameBuffer, NULL,
&d3d11FrameBufferView);
assert(SUCCEEDED(res));
d3d11FrameBuffer->Release();
global_windowDidResize = false;
}
FLOAT backgroundColor[4] = {0.1f, 0.2f, 0.6f, 1.0f};
d3d11DeviceContext->ClearRenderTargetView(d3d11FrameBufferView,
backgroundColor);
RECT winRect;
GetClientRect(hwnd, &winRect);
D3D11_VIEWPORT viewport = {0.0f,
0.0f,
(FLOAT)(winRect.right - winRect.left),
(FLOAT)(winRect.bottom - winRect.top),
0.0f,
1.0f};
d3d11DeviceContext->RSSetViewports(1, &viewport);
d3d11DeviceContext->OMSetRenderTargets(1, &d3d11FrameBufferView,
nullptr);
d3d11DeviceContext->IASetPrimitiveTopology(
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
d3d11DeviceContext->IASetInputLayout(inputLayout);
d3d11DeviceContext->VSSetShader(vertexShader, nullptr, 0);
d3d11DeviceContext->PSSetShader(pixelShader, nullptr, 0);
d3d11DeviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride,
&offset);
d3d11DeviceContext->Draw(numVerts, 0);
ID3D11Texture2D* framebufferCopy;
ID3D11ShaderResourceView* copySrv;
{
ID3D11Texture2D* d3d11FrameBuffer;
HRESULT hResult = d3d11SwapChain->GetBuffer(
0, __uuidof(ID3D11Texture2D), (void**)&d3d11FrameBuffer);
assert(SUCCEEDED(hResult));
D3D11_TEXTURE2D_DESC framebufferDesc;
d3d11FrameBuffer->GetDesc(&framebufferDesc);
framebufferDesc.BindFlags =
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
framebufferDesc.CPUAccessFlags =
D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_READ;
hResult = d3d11Device->CreateTexture2D(&framebufferDesc, nullptr,
&framebufferCopy);
assert(SUCCEEDED(hResult));
d3d11DeviceContext->CopyResource(framebufferCopy, d3d11FrameBuffer);
hResult = d3d11Device->CreateShaderResourceView(framebufferCopy, 0,
&copySrv);
assert(SUCCEEDED(hResult));
d3d11FrameBuffer->Release();
}
assert(copySrv != nullptr);
libra_source_image_d3d11_t input = {copySrv,
viewport.Width,
viewport.Height,};
libra_viewport_t vp = {0, 0, viewport.Width, viewport.Height, };
libra.d3d11_filter_chain_frame(&filter_chain, NULL, frameCount, input, vp,
d3d11FrameBufferView, NULL, NULL);
copySrv->Release();
framebufferCopy->Release();
d3d11SwapChain->Present(1, 0);
frameCount += 1;
}
return 0;
}