// 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 #include #pragma comment(lib, "d3d11.lib") #include #pragma comment(lib, "d3dcompiler.lib") #include #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( "../../../slang-shaders/border/gameboy-player/" "gameboy-player-crt-royale.slangp", &preset); libra_d3d11_filter_chain_t filter_chain; libra.d3d11_filter_chain_create(&preset, NULL, d3d11Device, &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, ©Srv); 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, frameCount, input, vp, d3d11FrameBufferView, NULL, NULL); copySrv->Release(); framebufferCopy->Release(); d3d11SwapChain->Present(1, 0); frameCount += 1; } return 0; }