// perf.cpp — measures the resolution-scaling performance benefit of the SVR // upscale path, isolated with GPU timestamp queries. No VR runtime involved. // // The saving from any upscaler is that the game renders fewer, cheaper pixels; // the kernel then reconstructs full resolution at a small fixed cost. This // harness renders an expensive procedural fragment shader (domain-warped fBm, // octave count = per-pixel shading load) to eye-sized render targets, times // the scene on the GPU at full resolution and at renderScale R, runs the real // SVR kernel (svr_cuda.dll) to reconstruct R -> full, and reports the net // frame speedup against the pixel-count ceiling. The octave sweep spans light // to heavy shading so the speedup curve is visible; a real title sits on it // wherever its own per-pixel cost lands. #include #include #include #include #include #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "d3dcompiler.lib") static const char* kShader = R"( cbuffer CB : register(b0) { float4 p; } // x=octaves, yz=size, w=time struct VSOut { float4 pos : SV_Position; float2 uv : TEXCOORD0; }; VSOut vs(uint id : SV_VertexID) { VSOut o; float2 xy = float2((id << 1) & 2, id & 2); o.pos = float4(xy * 2.0 - 1.0, 0.0, 1.0); o.uv = xy; return o; } float hash(float2 n){ return frac(sin(dot(n, float2(12.9898,78.233)))*43758.5453); } float vnoise(float2 x){ float2 i=floor(x), f=frac(x); f=f*f*(3.0-2.0*f); float a=hash(i), b=hash(i+float2(1,0)), c=hash(i+float2(0,1)), d=hash(i+float2(1,1)); return lerp(lerp(a,b,f.x), lerp(c,d,f.x), f.y); } float4 ps(VSOut v) : SV_Target { float2 uv = v.uv * p.yz * 0.02; float2 q = uv; float acc = 0.0, amp = 0.5; int N = (int)p.x; [loop] for (int i = 0; i < N; ++i) { q += float2(vnoise(q*1.7 + p.w), vnoise(q*1.7 - p.w)) * 0.35; acc += amp * vnoise(q); amp *= 0.6; q *= 1.9; } float3 col = 0.5 + 0.5*cos(6.2831*(acc + float3(0.0,0.33,0.67))); return float4(col, 1.0); } )"; typedef int (*SvrProcessFn)(ID3D11Texture2D*, int, int, int, int, int, ID3D11Texture2D*, int, int, int, int, int, float, float, float, float, float); static ID3D11Texture2D* mkrt(ID3D11Device* d, int w, int h) { D3D11_TEXTURE2D_DESC td = {}; td.Width = w; td.Height = h; td.MipLevels = 1; td.ArraySize = 1; td.Format = DXGI_FORMAT_R8G8B8A8_UNORM; td.SampleDesc.Count = 1; td.Usage = D3D11_USAGE_DEFAULT; td.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; ID3D11Texture2D* t = nullptr; d->CreateTexture2D(&td, nullptr, &t); return t; } int main() { HMODULE svr = LoadLibraryW(L"svr_cuda.dll"); SvrProcessFn svr_process = svr ? (SvrProcessFn)GetProcAddress(svr, "svr_process") : nullptr; if (!svr_process) { printf("svr_cuda.dll svr_process missing\n"); return 1; } ID3D11Device* dev = nullptr; ID3D11DeviceContext* ctx = nullptr; D3D_FEATURE_LEVEL fl; if (FAILED(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &dev, &fl, &ctx))) { printf("device create failed\n"); return 1; } ID3DBlob *vsb=nullptr,*psb=nullptr,*eb=nullptr; D3DCompile(kShader, strlen(kShader), 0,0,0, "vs","vs_5_0",0,0,&vsb,&eb); if (FAILED(D3DCompile(kShader, strlen(kShader), 0,0,0, "ps","ps_5_0",0,0,&psb,&eb))) { printf("ps: %s\n", eb?(char*)eb->GetBufferPointer():"?"); return 1; } ID3D11VertexShader* vs=nullptr; ID3D11PixelShader* ps=nullptr; dev->CreateVertexShader(vsb->GetBufferPointer(), vsb->GetBufferSize(),0,&vs); dev->CreatePixelShader(psb->GetBufferPointer(), psb->GetBufferSize(),0,&ps); D3D11_BUFFER_DESC bd={}; bd.ByteWidth=16; bd.Usage=D3D11_USAGE_DEFAULT; bd.BindFlags=D3D11_BIND_CONSTANT_BUFFER; ID3D11Buffer* cb=nullptr; dev->CreateBuffer(&bd,nullptr,&cb); D3D11_RASTERIZER_DESC rd={}; rd.FillMode=D3D11_FILL_SOLID; rd.CullMode=D3D11_CULL_NONE; ID3D11RasterizerState* rs=nullptr; dev->CreateRasterizerState(&rd,&rs); ctx->RSSetState(rs); ID3D11Query *qd=nullptr,*q0=nullptr,*q1=nullptr; D3D11_QUERY_DESC dqd={D3D11_QUERY_TIMESTAMP_DISJOINT,0}; dev->CreateQuery(&dqd,&qd); D3D11_QUERY_DESC tqd={D3D11_QUERY_TIMESTAMP,0}; dev->CreateQuery(&tqd,&q0); dev->CreateQuery(&tqd,&q1); auto render_two_eyes = [&](ID3D11RenderTargetView* rL, ID3D11RenderTargetView* rR, int w, int h, int oct, float t) { float p[4] = {(float)oct, (float)w, (float)h, t}; ctx->UpdateSubresource(cb,0,nullptr,p,0,0); ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); ctx->IASetInputLayout(nullptr); ctx->VSSetShader(vs,nullptr,0); ctx->VSSetConstantBuffers(0,1,&cb); ctx->PSSetShader(ps,nullptr,0); ctx->PSSetConstantBuffers(0,1,&cb); ctx->RSSetState(rs); D3D11_VIEWPORT vp={0,0,(float)w,(float)h,0,1}; ctx->RSSetViewports(1,&vp); ID3D11RenderTargetView* rts[2]={rL,rR}; for (int e=0;e<2;++e){ ctx->OMSetRenderTargets(1,&rts[e],nullptr); ctx->Draw(3,0); } }; auto gpu_ms = [&](auto&& fn)->double{ // warm for(int i=0;i<3;++i) fn(); ctx->Flush(); double best=1e30; for(int rep=0;rep<12;++rep){ ctx->Begin(qd); ctx->End(q0); fn(); ctx->End(q1); ctx->End(qd); ctx->Flush(); D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj; UINT64 t0,t1; while(ctx->GetData(qd,&dj,sizeof(dj),0)!=S_OK){} while(ctx->GetData(q0,&t0,sizeof(t0),0)!=S_OK){} while(ctx->GetData(q1,&t1,sizeof(t1),0)!=S_OK){} if(dj.Disjoint) continue; double ms = 1000.0*(double)(t1-t0)/(double)dj.Frequency; if(msdouble{ float r1=0.65f*oh, r0=0.55f*r1; auto once=[&]{ svr_process(srcL,0,0,0,iw,ih,dstL,0,0,0,ow,oh,0.46f*ow,0.5f*oh,r0,r1,0.4f); svr_process(srcR,0,0,0,iw,ih,dstR,0,0,0,ow,oh,0.54f*ow,0.5f*oh,r0,r1,0.4f); }; for(int i=0;i<5;++i) once(); // warm + register LARGE_INTEGER f,a,b; QueryPerformanceFrequency(&f); QueryPerformanceCounter(&a); const int N=60; for(int i=0;iCreateRenderTargetView(fullL,nullptr,&fLrtv); dev->CreateRenderTargetView(fullR,nullptr,&fRrtv); printf("== %s %dx%d/eye ==\n", sh.name, sh.w, sh.h); printf("%7s %8s | %9s %9s %8s %8s | %8s %8s\n", "scale","pix%","full ms","scaled ms","kern ms","frame ms","speedup","ceiling"); for (float sc : scales) { int rw=(int)(sh.w*sc+0.5f), rh=(int)(sh.h*sc+0.5f); ID3D11Texture2D* redL=mkrt(dev,rw,rh); ID3D11Texture2D* redR=mkrt(dev,rw,rh); ID3D11RenderTargetView *rLrtv=nullptr,*rRrtv=nullptr; dev->CreateRenderTargetView(redL,nullptr,&rLrtv); dev->CreateRenderTargetView(redR,nullptr,&rRrtv); double pixr = (double)(rw*rh)/(double)(sh.w*sh.h); for (int oct : octaves) { double tf = gpu_ms([&]{ render_two_eyes(fLrtv,fRrtv,sh.w,sh.h,oct,1.3f); }); double ts = gpu_ms([&]{ render_two_eyes(rLrtv,rRrtv,rw,rh,oct,1.3f); }); double tk = kernel_ms(redL,redR,rw,rh,fullL,fullR,sh.w,sh.h); double frame = ts + tk; printf("%6.2f %6.1f%% | %9.3f %9.3f %8.3f %8.3f | %7.2fx %7.2fx (oct %d)\n", sc, 100.0*pixr, tf, ts, tk, frame, tf/frame, 1.0/pixr, oct); } rLrtv->Release(); rRrtv->Release(); redL->Release(); redR->Release(); } fLrtv->Release(); fRrtv->Release(); fullL->Release(); fullR->Release(); printf("\n"); } printf("done\n"); return 0; }