Skip to content

Instantly share code, notes, and snippets.

@tcantenot
Forked from cshenton/tri.c
Created November 23, 2024 10:49
Show Gist options
  • Save tcantenot/7d67dcc0046d1d4063e9d6950bd2ca1d to your computer and use it in GitHub Desktop.
Save tcantenot/7d67dcc0046d1d4063e9d6950bd2ca1d to your computer and use it in GitHub Desktop.
Seeing how fast a d3d11 swapchain can go.
#include <assert.h>
#include <stdio.h>
#include <time.h>
#define COBJMACROS
#include <windows.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define TITLE "D3D11 Speedtest"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
const char SHADER_SRC[] = "\n"
"cbuffer Constants : register(b0)\n"
"{\n"
" int frame;\n"
"};\n"
"\n"
"struct PixelData {\n"
" float4 position : SV_POSITION;\n"
" float4 color : COL;\n"
"};\n"
"\n"
"uint hash(uint a)\n"
"{\n"
" a = (a+0x7ed55d16) + (a<<12);\n"
" a = (a^0xc761c23c) ^ (a>>19);\n"
" a = (a+0x165667b1) + (a<<5);\n"
" a = (a+0xd3a2646c) ^ (a<<9);\n"
" a = (a+0xfd7046c5) + (a<<3);\n"
" a = (a^0xb55a4f09) ^ (a>>16);\n"
" return a;\n"
"}\n"
"\n"
"PixelData vert(uint v: SV_VertexID)\n"
"{\n"
" float2 positions[3] = { float2(0.5, -0.5), float2(-0.5, -0.5), float2(0.0, 0.5) };\n"
" PixelData pd;\n"
"\n"
" uint ch = hash(~uint(frame));\n"
" pd.color = float4(((ch >> 16) & 0xff) / 255.0, ((ch >> 8) & 0xff) / 255.0, ((ch) & 0xff) / 255.0, 1.0);\n"
" pd.position = float4(positions[v], 0.0, 1.0);\n"
" return pd;\n"
"}\n"
"\n"
"float4 pix(PixelData pd) : SV_TARGET\n"
"{\n"
" return pd.color;\n"
"}\n";
typedef struct Constants {
int frame;
} Constants;
int main()
{
HRESULT hr;
WNDCLASSA wnd_class = { 0, DefWindowProcA, 0, 0, 0, 0, 0, 0, 0, TITLE };
RegisterClassA(&wnd_class);
DWORD style = WS_POPUP | WS_MAXIMIZE | WS_VISIBLE;
HWND window = CreateWindowExA(0, TITLE, TITLE, style, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
assert(window);
//////////////////////////////////////////////////////////////////////////////////////////////////////
D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_1 };
ID3D11Device* base_device;
ID3D11DeviceContext* base_ctx;
hr = D3D11CreateDevice(
NULL, D3D_DRIVER_TYPE_HARDWARE,
NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT,
feature_levels, ARRAYSIZE(feature_levels),
D3D11_SDK_VERSION, &base_device,
NULL, &base_ctx);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
ID3D11Device1* device;
hr = ID3D11Device_QueryInterface(base_device, &IID_ID3D11Device1, (void**)(&device));
assert(SUCCEEDED(hr));
ID3D11DeviceContext1* ctx;
hr = ID3D11DeviceContext_QueryInterface(base_ctx, &IID_ID3D11DeviceContext1, (void**)&ctx);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
IDXGIDevice1* dxgi_dev;
hr = ID3D11Device_QueryInterface(device, &IID_IDXGIDevice1, (void**)&dxgi_dev);
assert(SUCCEEDED(hr));
IDXGIAdapter1* adapter;
hr = IDXGIDevice_GetParent(dxgi_dev, &IID_IDXGIAdapter1, (void**)&adapter);
assert(SUCCEEDED(hr));
IDXGIFactory2* factory;
hr = IDXGIAdapter1_GetParent(adapter, &IID_IDXGIFactory2, (void**)&factory);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
DXGI_SWAP_CHAIN_DESC1 swapchain_desc = {
.Width = 80,
.Height = 60,
.Format = DXGI_FORMAT_B8G8R8A8_UNORM,
.SampleDesc = {.Count = 1},
.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
.BufferCount = 3,
.Scaling = DXGI_SCALING_NONE,
.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING,
.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD,
.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED,
};
IDXGISwapChain1* swapchain;
hr = IDXGIFactory2_CreateSwapChainForHwnd(factory, (IUnknown*)device, window,
&swapchain_desc, NULL, NULL, &swapchain);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
ID3D11Texture2D* framebuffer;
hr = IDXGISwapChain1_GetBuffer(swapchain, 0, &IID_ID3D11Texture2D, (void**)&framebuffer);
assert(SUCCEEDED(hr));
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {
.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D,
};
ID3D11RenderTargetView* rtv;
hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource*)framebuffer, &rtv_desc, &rtv);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
D3D11_TEXTURE2D_DESC depth_tex_desc;
ID3D11Texture2D_GetDesc(framebuffer, &depth_tex_desc);
depth_tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depth_tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
ID3D11Texture2D* depth_tex;
hr = ID3D11Device_CreateTexture2D(device, &depth_tex_desc, NULL, &depth_tex);
assert(SUCCEEDED(hr));
ID3D11DepthStencilView* dsv;
ID3D11Device_CreateDepthStencilView(device, (ID3D11Resource*)depth_tex, NULL, &dsv);
//////////////////////////////////////////////////////////////////////////////////////////////////////
ID3DBlob* vert_src;
hr = D3DCompile(SHADER_SRC, sizeof(SHADER_SRC), NULL, NULL, NULL, "vert", "vs_5_0", 0, 0, &vert_src, NULL);
assert(SUCCEEDED(hr));
ID3D11VertexShader* vert_shd;
hr = ID3D11Device_CreateVertexShader(
device,
ID3D10Blob_GetBufferPointer(vert_src),
ID3D10Blob_GetBufferSize(vert_src),
NULL,
&vert_shd);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
ID3DBlob* pix_src;
hr = D3DCompile(SHADER_SRC, sizeof(SHADER_SRC), NULL, NULL, NULL, "pix", "ps_5_0", 0, 0, &pix_src, NULL);
assert(SUCCEEDED(hr));
ID3D11PixelShader* pix_shd;
hr = ID3D11Device_CreatePixelShader(device,
ID3D10Blob_GetBufferPointer(pix_src),
ID3D10Blob_GetBufferSize(pix_src),
NULL,
&pix_shd);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
D3D11_BUFFER_DESC cbuffer_desc = {
.ByteWidth = sizeof(Constants) + 0xf & 0xfffffff0,
.Usage = D3D11_USAGE_DYNAMIC,
.BindFlags = D3D11_BIND_CONSTANT_BUFFER,
.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE,
};
ID3D11Buffer* cbuffer;
hr = ID3D11Device_CreateBuffer(device, &cbuffer_desc, NULL, &cbuffer);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
D3D11_RASTERIZER_DESC rasterizer_desc = {
.FillMode = D3D11_FILL_SOLID,
.CullMode = D3D11_CULL_BACK,
};
ID3D11RasterizerState* raster_state;
hr = ID3D11Device_CreateRasterizerState(device, &rasterizer_desc, &raster_state);
assert(SUCCEEDED(hr));
//////////////////////////////////////////////////////////////////////////////////////////////////////
D3D11_DEPTH_STENCIL_DESC depth_stencil_desc = {
.DepthEnable = TRUE,
.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL,
.DepthFunc = D3D11_COMPARISON_LESS,
};
ID3D11DepthStencilState* depth_stencil_state;
ID3D11Device_CreateDepthStencilState(device, &depth_stencil_desc, &depth_stencil_state);
//////////////////////////////////////////////////////////////////////////////////////////////////////
float clear_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
float width = (float)depth_tex_desc.Width;
float height = (float)depth_tex_desc.Height;
D3D11_VIEWPORT viewport = { 0.0f, 0.0f, width, height, 0.0f, 1.0f };
printf("%f, %f\n", width, height);
//////////////////////////////////////////////////////////////////////////////////////////////////////
int frame = 0;
LARGE_INTEGER start_time, end_time, ElapsedMicroseconds;
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&start_time);
clock_t frame_time = clock();
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
for (;;) {
MSG msg;
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) {
return 0;
}
DispatchMessageA(&msg);
}
D3D11_MAPPED_SUBRESOURCE mapped;
Constants c = { .frame = frame++ };
ID3D11DeviceContext_Map(ctx, (ID3D11Resource*)cbuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
memcpy(mapped.pData, &c, sizeof(c));
ID3D11DeviceContext_Unmap(ctx, (ID3D11Resource*)cbuffer, 0);
ID3D11DeviceContext_ClearRenderTargetView(ctx, rtv, clear_color);
ID3D11DeviceContext_ClearDepthStencilView(ctx, dsv, D3D11_CLEAR_DEPTH, 1.0f, 0);
ID3D11DeviceContext_IASetPrimitiveTopology(ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D11DeviceContext_VSSetShader(ctx, vert_shd, NULL, 0);
ID3D11DeviceContext_VSSetConstantBuffers(ctx, 0, 1, &cbuffer);
ID3D11DeviceContext_RSSetViewports(ctx, 1, &viewport);
ID3D11DeviceContext_RSSetState(ctx, raster_state);
ID3D11DeviceContext_PSSetShader(ctx, pix_shd, NULL, 0);
ID3D11DeviceContext_OMSetRenderTargets(ctx, 1, &rtv, dsv);
ID3D11DeviceContext_OMSetDepthStencilState(ctx, depth_stencil_state, 0);
ID3D11DeviceContext_OMSetBlendState(ctx, NULL, NULL, 0xffffffff);
ID3D11DeviceContext_Draw(ctx, 3, 0);
IDXGISwapChain1_Present(swapchain, 0, DXGI_PRESENT_ALLOW_TEARING);
QueryPerformanceCounter(&end_time);
long long elapsed_us = 1000000 * (end_time.QuadPart - start_time.QuadPart) / frequency.QuadPart;
if (elapsed_us > 250000) {
printf("%f FPS\n", (double)frame / ((double)elapsed_us) * 1000000.0 );
frame = 0;
start_time = end_time;
}
}
}
@rlewkowicz
Copy link

What was your determination? I'll play with this, but I'm running into small swap delays. Idk if Its my implementation, but I take a frame from screen cap and show it with a swap buffer. I can't imagine that should take more than a ms or two. I see a delay though and I go right from frame cap to back buffer. That means I'm at 60-100ms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment