| |
| |
| |
| |
| |
| |
| #include <d3d11.h> |
| #include <d3dcompiler.h> |
|
|
| #include <cstdint> |
| #include <cstdio> |
|
|
| #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;i<N;i++){ q+=float2(vn(q*1.7+p.w),vn(q*1.7-p.w))*0.35; |
| acc+=amp*vn(q); amp*=0.6; q*=1.9; } |
| return float4(0.5+0.5*cos(6.2831*(acc+float3(0,0.33,0.67))),1); } |
| )"; |
|
|
| static ID3DBlob* compile(const char* src, const char* entry, const char* tgt) { |
| ID3DBlob *b = nullptr, *e = nullptr; |
| if (FAILED(D3DCompile(src, strlen(src), 0, 0, 0, entry, tgt, 0, 0, &b, &e))) { |
| printf("compile %s: %s\n", entry, e ? (char*)e->GetBufferPointer() : "?"); |
| 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); |
|
|
| |
| 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; |
| } |
|
|