// perf2.cpp — native (HLSL compute) SVR upscale performance, no CUDA/interop. // Renders the expensive scene to eye targets at full res and at renderScale R // (D3D timestamp timed), then reconstructs R -> full with the HLSL compute // port of the kernel (also D3D timestamp timed, same clock). Reports the net // frame speedup against the pixel-count ceiling. This is the in-game path: // everything stays in D3D11, so there is no bridge tax to pay. #include #include #include #include #pragma comment(lib, "d3d11.lib") #pragma comment(lib, "d3dcompiler.lib") static const char* kScene = R"( cbuffer CB : register(b0) { float4 p; } 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,1); o.uv=xy; return o; } float hash(float2 n){ return frac(sin(dot(n,float2(12.9898,78.233)))*43758.5453); } float vn(float2 x){ float2 i=floor(x),f=frac(x); f=f*f*(3-2*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,amp=0.5; int N=(int)p.x; [loop] for(int i=0;iGetBufferPointer() : "?"); return nullptr; } return b; } static char* slurp(const char* path) { FILE* f = fopen(path, "rb"); if (!f) return nullptr; fseek(f, 0, SEEK_END); long n = ftell(f); fseek(f, 0, SEEK_SET); char* s = (char*)malloc(n + 1); fread(s, 1, n, f); s[n] = 0; fclose(f); return s; } struct RT { ID3D11Texture2D* tex = nullptr; ID3D11RenderTargetView* rtv = nullptr; ID3D11ShaderResourceView* srv = nullptr; ID3D11UnorderedAccessView* uav = nullptr; }; static RT mkrt(ID3D11Device* d, int w, int h) { RT r; 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 | D3D11_BIND_UNORDERED_ACCESS; d->CreateTexture2D(&td, nullptr, &r.tex); d->CreateRenderTargetView(r.tex, nullptr, &r.rtv); d->CreateShaderResourceView(r.tex, nullptr, &r.srv); d->CreateUnorderedAccessView(r.tex, nullptr, &r.uav); return r; } struct SvrCB { uint32_t sw, sh, dw, dh; float cx, cy, r0, r1; float sharp, p0, p1, p2; }; int main() { 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 = compile(kScene, "vs", "vs_5_0"); ID3DBlob* psb = compile(kScene, "ps", "ps_5_0"); if (!vsb || !psb) return 1; ID3D11VertexShader* vs = nullptr; ID3D11PixelShader* ps = nullptr; dev->CreateVertexShader(vsb->GetBufferPointer(), vsb->GetBufferSize(), 0, &vs); dev->CreatePixelShader(psb->GetBufferPointer(), psb->GetBufferSize(), 0, &ps); // Resolve the shader from SVR_HLSL, then the repo-relative locations. const char* cands[] = { getenv("SVR_HLSL"), "svr_upscale.hlsl", "..\\game\\svr_upscale.hlsl", "game\\svr_upscale.hlsl" }; char* csrc = nullptr; for (const char* c : cands) if (c && (csrc = slurp(c))) break; if (!csrc) { printf("cannot find svr_upscale.hlsl (set SVR_HLSL)\n"); return 1; } ID3DBlob* csb = compile(csrc, "main", "cs_5_0"); if (!csb) return 1; ID3D11ComputeShader* cs = nullptr; dev->CreateComputeShader(csb->GetBufferPointer(), csb->GetBufferSize(), 0, &cs); D3D11_BUFFER_DESC bd = {}; bd.ByteWidth = 16; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; ID3D11Buffer* scb = nullptr; dev->CreateBuffer(&bd, nullptr, &scb); bd.ByteWidth = sizeof(SvrCB); ID3D11Buffer* ucb = nullptr; dev->CreateBuffer(&bd, nullptr, &ucb); D3D11_RASTERIZER_DESC rd = {}; rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; ID3D11RasterizerState* rs = nullptr; dev->CreateRasterizerState(&rd, &rs); ID3D11Query *qd = nullptr, *q0 = nullptr, *q1 = nullptr; D3D11_QUERY_DESC dd = {D3D11_QUERY_TIMESTAMP_DISJOINT, 0}; dev->CreateQuery(&dd, &qd); D3D11_QUERY_DESC tq = {D3D11_QUERY_TIMESTAMP, 0}; dev->CreateQuery(&tq, &q0); dev->CreateQuery(&tq, &q1); auto scene = [&](RT& L, RT& R, int w, int h, int oct) { float p[4] = {(float)oct, (float)w, (float)h, 1.3f}; ctx->UpdateSubresource(scb, 0, 0, p, 0, 0); ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); ctx->IASetInputLayout(nullptr); ctx->VSSetShader(vs, 0, 0); ctx->VSSetConstantBuffers(0, 1, &scb); ctx->PSSetShader(ps, 0, 0); ctx->PSSetConstantBuffers(0, 1, &scb); ctx->RSSetState(rs); D3D11_VIEWPORT vp = {0, 0, (float)w, (float)h, 0, 1}; ctx->RSSetViewports(1, &vp); RT* e[2] = {&L, &R}; for (int i = 0; i < 2; ++i) { ctx->OMSetRenderTargets(1, &e[i]->rtv, nullptr); ctx->Draw(3, 0); } }; auto upscale = [&](RT& sL, RT& sR, int iw, int ih, RT& dL, RT& dR, int ow, int oh) { SvrCB u = {(uint32_t)iw,(uint32_t)ih,(uint32_t)ow,(uint32_t)oh, 0.5f*ow,0.5f*oh, 0.55f*0.65f*oh, 0.65f*oh, 0.4f, 0,0,0}; ctx->CSSetShader(cs, 0, 0); RT* s[2] = {&sL, &sR}; RT* d[2] = {&dL, &dR}; float cxs[2] = {0.46f, 0.54f}; for (int i = 0; i < 2; ++i) { u.cx = cxs[i] * ow; ctx->UpdateSubresource(ucb, 0, 0, &u, 0, 0); ctx->CSSetConstantBuffers(0, 1, &ucb); ctx->CSSetShaderResources(0, 1, &s[i]->srv); ID3D11UnorderedAccessView* uav = d[i]->uav; ctx->CSSetUnorderedAccessViews(0, 1, &uav, nullptr); ctx->Dispatch((ow + 7) / 8, (oh + 7) / 8, 1); ID3D11UnorderedAccessView* nu = nullptr; ctx->CSSetUnorderedAccessViews(0, 1, &nu, nullptr); } }; auto gpu_ms = [&](auto&& fn) -> double { 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 a, b; while (ctx->GetData(qd, &dj, sizeof(dj), 0) != S_OK) {} while (ctx->GetData(q0, &a, sizeof(a), 0) != S_OK) {} while (ctx->GetData(q1, &b, sizeof(b), 0) != S_OK) {} if (dj.Disjoint) continue; double ms = 1000.0 * (double)(b - a) / (double)dj.Frequency; if (ms < best) best = ms; } return best; }; struct Res { int w, h; const char* name; }; Res shapes[] = { {1440,1600,"Quest3 low"}, {2016,2240,"Quest3 med"}, {2464,2736,"Quest3 high"} }; float scales[] = { 0.90f, 0.77f, 0.67f, 0.59f }; int octs[] = { 8, 16, 24 }; printf("Native HLSL SVR upscale, no CUDA/interop (GPU timestamps, per frame = 2 eyes)\n\n"); for (auto& sh : shapes) { RT fL = mkrt(dev, sh.w, sh.h), fR = mkrt(dev, sh.w, sh.h); printf("== %s %dx%d/eye ==\n", sh.name, sh.w, sh.h); printf("%6s %7s | %8s %9s %8s %8s | %8s %8s\n", "scale","pix%","full ms","scaled ms","upsc ms","frame ms","speedup","ceiling"); for (float sc : scales) { int rw = (int)(sh.w * sc + 0.5f), rh = (int)(sh.h * sc + 0.5f); RT rL = mkrt(dev, rw, rh), rR = mkrt(dev, rw, rh); double pixr = (double)(rw * rh) / (double)(sh.w * sh.h); for (int oct : octs) { double tf = gpu_ms([&]{ scene(fL, fR, sh.w, sh.h, oct); }); double ts = gpu_ms([&]{ scene(rL, rR, rw, rh, oct); }); double tu = gpu_ms([&]{ upscale(rL, rR, rw, rh, fL, fR, sh.w, sh.h); }); double frame = ts + tu; printf("%5.2f %6.1f%% | %8.3f %9.3f %8.3f %8.3f | %7.2fx %7.2fx (oct %d)\n", sc, 100.0 * pixr, tf, ts, tu, frame, tf / frame, 1.0 / pixr, oct); } rL.tex->Release(); rR.tex->Release(); } fL.tex->Release(); fR.tex->Release(); printf("\n"); } printf("done\n"); return 0; }