mirror of
https://github.com/libretro/parallel-dc.git
synced 2026-11-07 12:37:53 -10:00
HDR: ACES 2.0's tables off the frame; SSAA and the X scaler exact
ACES 2.0's tables (the JMh parameters, the tone scale's LUT and the gamut scales) were made on the frame that changed the peak, the gamut or the surround. They are now made by the HDR worker, like the cube, through the same lock-free hand-over: a slot for each kind of job taken by atomic exchange, a CAS-pushed list of what is done, a stop flag for each job, the worker parked on an eventcount. Nothing waits for it. Until the new tables are done the encode keeps the old ones, and their cube, with the gamut they were made for; before any, the tone scale alone (HDR_DT_ACES2). A fill takes back what the worker finished before it reads the tables, so a block is never half of the old tables and half of the new ones. ACES2_InitSurround() is the reentrant init the worker calls. hdr_dt_finish() builds in place, for the tests. Without threads (TARGET_NO_THREADS) the build is done in place as before. With the write-out off, what SSAA resolved is now encoded from the exact average of its samples, not from the byte the picture rounded it to, and is not dithered. Where something was drawn over the picture after the resolve (the VMUs, the crosshairs), the picture is encoded as before: the encode checks that the picture is the samples' resolve by the shared rule (pvr_resolve_join()). - Vulkan per-triangle and per-strip: the HDR subpass reads the samples as a second input attachment. - Vulkan per-pixel: the last pass also stores each pixel's channel sums (OIT_FINAL_FRAG_S1_SUMS, an R16G16B16A16_UINT image in the OIT buffers' set), which the encode samples. - Vulkan compute: the walk stores the sums too, under a specialisation constant, which is 0 at 24-bit. It does the same for the X scaler's pairs of pixels, at one sample a pixel as well. Renders to a texture have walks of their own that store none. - Direct3D 12 per-triangle: the encode reads the multisampled target (PS_SSAA, hdr_encode_dxbc.inc). The sums are scaled to 16 samples, so one encode pipeline takes any count. Direct3D 12's compute kernels are unchanged: kernels_dx12.sh leaves the PVRC_SUMS blocks out of their source, so their DXIL and sums are as they were. At 24-bit none of this runs. tools/vulkan/vk_hdr.sh gains --exact cases on two new discs built from live_prog.c (live_disc.py --slant and --hscale). The first has a slanted shaded triangle and is run on every renderer at 4x. The second adds the X scaler into a 32-bit framebuffer and runs the compute renderer at one sample a pixel. The old code fails both: it dithers, at most 1.08 of a step off. tools/hdr/hdr_d3d.sh 12ssaa checks Direct3D 12's encode with samples, with an overdrawn strip. tools/hdr/hdr_cube.sh checks the tables: the first fill and a gamut change keep what there is, and both converge on the tables made in place, and no block between is a mix of two sets of tables. vk_sanitize.sh adds the per-pixel and compute renderers with SSAA at scRGB.
This commit is contained in:
1 parent
192c743256
commit
e7cde6e176
45 files changed
+21835
-12356
No files matched your search
@@ -1122,6 +1122,10 @@ void DX12Renderer::EndScreen(bool writeOutPass)
|
||||
FlushBatch();
|
||||
ScreenTarget& target = screenTargets[screenIndex];
|
||||
const bool ssaa = SsaaActive();
|
||||
/* the HDR output takes the samples' exact average where the picture is
|
||||
* their resolve (not on a frame the chip's write-out changes after,
|
||||
* nor where the per-pixel renderer resolved them itself): kept till then */
|
||||
const bool hdrSamples = ssaa && BindsScreen() && context->HdrActive() && !(writeOutPass && writeOutPictures);
|
||||
if (ssaa)
|
||||
{
|
||||
/* The samples resolved into the picture, all of it. Their contents
|
||||
@@ -1141,7 +1145,7 @@ void DX12Renderer::EndScreen(bool writeOutPass)
|
||||
context->SetScissor(whole);
|
||||
SsaaResolve(ssaaColor[0].srv);
|
||||
}
|
||||
for (u32 i = 0; i < SsaaColorImages() && i < 2; i++)
|
||||
for (u32 i = hdrSamples ? 1 : 0; i < SsaaColorImages() && i < 2; i++)
|
||||
{
|
||||
context->Transition(ssaaColor[i], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
context->Cmd()->DiscardResource(ssaaColor[i].resource, nullptr);
|
||||
@@ -1166,8 +1170,14 @@ void DX12Renderer::EndScreen(bool writeOutPass)
|
||||
}
|
||||
context->SetTargets(~0u, ~0u);
|
||||
// as the frontend wants it - or encoded for its HDR output, which it is handed instead - and off to the GPU
|
||||
if (!context->EncodeHdr(target.image, target.image.width, target.image.height))
|
||||
if (!context->EncodeHdr(target.image, target.image.width, target.image.height,
|
||||
hdrSamples ? &ssaaColor[0] : nullptr, ssaaLog2))
|
||||
context->Transition(target.image, context->RequiredState());
|
||||
if (hdrSamples)
|
||||
{
|
||||
context->Transition(ssaaColor[0], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
context->Cmd()->DiscardResource(ssaaColor[0].resource, nullptr);
|
||||
}
|
||||
context->Submit();
|
||||
|
||||
havePicture = true;
|
||||
|
||||
@@ -783,14 +783,17 @@ void DX12Context::SetTargets(u32 rtv, u32 dsv, u32 samples)
|
||||
|
||||
/* ---- The frame ---- */
|
||||
|
||||
bool DX12Context::EncodeHdr(DX12Image& image, u32 width, u32 height)
|
||||
bool DX12Context::EncodeHdr(DX12Image& image, u32 width, u32 height, DX12Image *samples, u32 samplesLog2)
|
||||
{
|
||||
hdrFrame = nullptr;
|
||||
if (hdr == nullptr || !image.resource)
|
||||
return false;
|
||||
Transition(image, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
if (samples != nullptr)
|
||||
Transition(*samples, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
// (signalled by the Submit() that follows)
|
||||
if (!hdr_d3d12_encode(hdr, Cmd(), &hdr_output, image.resource, DX12FrameFormat, width, height, true,
|
||||
samples != nullptr ? samples->resource.get() : nullptr, samples != nullptr ? samplesLog2 : 0,
|
||||
GetPresentIndex(), fenceValue + 1, &hdrFrame))
|
||||
return false;
|
||||
// what the encode bound is not what this has noted
|
||||
|
||||
@@ -322,8 +322,11 @@ public:
|
||||
* @height, encoded into the command list for the frontend's frame and
|
||||
* left in the pixel shader resource state; the next SetFrame() hands
|
||||
* the encoded one over. False without the HDR output: the picture is
|
||||
* then to be left in required_state, as ever. */
|
||||
bool EncodeHdr(DX12Image& image, u32 width, u32 height);
|
||||
* then to be left in required_state, as ever. With SSAA's samples the
|
||||
* picture was resolved from (@samples, 2^@samplesLog2 a pixel), where
|
||||
* the picture is their resolve their exact average is encoded. */
|
||||
bool EncodeHdr(DX12Image& image, u32 width, u32 height, DX12Image *samples = nullptr, u32 samplesLog2 = 0);
|
||||
bool HdrActive() const { return hdr != nullptr; }
|
||||
bool IsHandedOver(const DX12Image *image) const { return v2 && handedOver && image != nullptr && image->resource.get() == frameResource.get(); }
|
||||
/* Just before video_refresh(RETRO_HW_FRAME_BUFFER_VALID) */
|
||||
void Present();
|
||||
|
||||
+36
-11
@@ -66,14 +66,18 @@ static const double Y_b = 20.0;
|
||||
static double surround_1 = 0.59;
|
||||
static double surround_2 = 0.9;
|
||||
|
||||
void ACES2_SetSurround( int mode ) {
|
||||
static void ACES2_SurroundPair( int mode, double *c, double *F ) {
|
||||
switch ( mode ) {
|
||||
case 0: surround_1 = 0.525; surround_2 = 0.8; break; /* dark */
|
||||
case 2: surround_1 = 0.69; surround_2 = 1.0; break; /* average */
|
||||
default: surround_1 = 0.59; surround_2 = 0.9; break; /* dim */
|
||||
case 0: *c = 0.525; *F = 0.8; break; /* dark */
|
||||
case 2: *c = 0.69; *F = 1.0; break; /* average */
|
||||
default: *c = 0.59; *F = 0.9; break; /* dim */
|
||||
}
|
||||
}
|
||||
|
||||
void ACES2_SetSurround( int mode ) {
|
||||
ACES2_SurroundPair( mode, &surround_1, &surround_2 );
|
||||
}
|
||||
|
||||
static const double J_scale = 100.0;
|
||||
static const double cam_nl_Y_reference = 100.0;
|
||||
static const double cam_nl_offset = 0.2713 * cam_nl_Y_reference;
|
||||
@@ -234,7 +238,16 @@ RGB into the cone response space and back, and the scalars the lightness
|
||||
conversion needs.
|
||||
================
|
||||
*/
|
||||
static void ACES2_InitJMh( const double prims[8], double surround_c, double surround_F,
|
||||
aces2JMhParams_t *p );
|
||||
|
||||
void ACES2_InitJMhParams( const double prims[8], aces2JMhParams_t *p ) {
|
||||
ACES2_InitJMh( prims, surround_1, surround_2, p );
|
||||
}
|
||||
|
||||
/* (the surround given, not the one ACES2_SetSurround() keeps) */
|
||||
static void ACES2_InitJMh( const double prims[8], double surround_c, double surround_F,
|
||||
aces2JMhParams_t *p ) {
|
||||
double MATRIX_16[9], RGB_TO_XYZ[9], XYZ_w[3], RGB_w[3];
|
||||
double D_RGB[3], RGB_wc[3], RGB_Aw[3];
|
||||
double cone_to_Aab[9];
|
||||
@@ -250,7 +263,7 @@ void ACES2_InitJMhParams( const double prims[8], aces2JMhParams_t *p ) {
|
||||
int i;
|
||||
|
||||
white[0] = white[1] = white[2] = ref_luminance;
|
||||
model_gamma = surround_1 * ( 1.48 + sqrt( Y_b / ref_luminance ) );
|
||||
model_gamma = surround_c * ( 1.48 + sqrt( Y_b / ref_luminance ) );
|
||||
|
||||
{
|
||||
double XYZ_to_RGB_cam[9];
|
||||
@@ -299,8 +312,8 @@ void ACES2_InitJMhParams( const double prims[8], aces2JMhParams_t *p ) {
|
||||
|
||||
for ( i = 0; i < 3; i++ ) {
|
||||
p->cone_to_Aab[i*3+0] = cone_to_Aab[i*3+0] / A_w;
|
||||
p->cone_to_Aab[i*3+1] = cone_to_Aab[i*3+1] * 43.0 * surround_2;
|
||||
p->cone_to_Aab[i*3+2] = cone_to_Aab[i*3+2] * 43.0 * surround_2;
|
||||
p->cone_to_Aab[i*3+1] = cone_to_Aab[i*3+1] * 43.0 * surround_F;
|
||||
p->cone_to_Aab[i*3+2] = cone_to_Aab[i*3+2] * 43.0 * surround_F;
|
||||
}
|
||||
mat3_invert( p->cone_to_Aab, p->Aab_to_cone );
|
||||
|
||||
@@ -1187,11 +1200,12 @@ double ACES2_GammaInvForHue( const aces2GammaTable_t *table, double hue ) {
|
||||
static const double ACES2_AP0[8] = { 0.7347, 0.2653, 0.0, 1.0, 0.0001, -0.077, 0.32168, 0.33767 };
|
||||
static const double ACES2_AP1[8] = { 0.713, 0.293, 0.165, 0.830, 0.128, 0.044, 0.32168, 0.33767 };
|
||||
|
||||
void ACES2_Init( const double limitPrims[8], double peakLuminance, aces2Params_t *p ) {
|
||||
static void ACES2_InitWith( const double limitPrims[8], double peakLuminance,
|
||||
double surround_c, double surround_F, aces2Params_t *p ) {
|
||||
p->peakLuminance = peakLuminance;
|
||||
ACES2_InitJMhParams( ACES2_AP0, &p->input );
|
||||
ACES2_InitJMhParams( ACES2_AP1, &p->reach );
|
||||
ACES2_InitJMhParams( limitPrims, &p->limit );
|
||||
ACES2_InitJMh( ACES2_AP0, surround_c, surround_F, &p->input );
|
||||
ACES2_InitJMh( ACES2_AP1, surround_c, surround_F, &p->reach );
|
||||
ACES2_InitJMh( limitPrims, surround_c, surround_F, &p->limit );
|
||||
ACES2_InitTSParams( peakLuminance, &p->ts );
|
||||
ACES2_InitChromaParams( &p->input, &p->reach, &p->ts, peakLuminance, &p->chroma );
|
||||
ACES2_InitGamutParams( &p->input, &p->ts, peakLuminance, &p->gamut );
|
||||
@@ -1199,6 +1213,17 @@ void ACES2_Init( const double limitPrims[8], double peakLuminance, aces2Params_t
|
||||
ACES2_BuildUpperHullGammaTable( &p->cusp, &p->gamut, &p->limit, peakLuminance, &p->gamma );
|
||||
}
|
||||
|
||||
void ACES2_Init( const double limitPrims[8], double peakLuminance, aces2Params_t *p ) {
|
||||
ACES2_InitWith( limitPrims, peakLuminance, surround_1, surround_2, p );
|
||||
}
|
||||
|
||||
void ACES2_InitSurround( const double limitPrims[8], double peakLuminance, int surround,
|
||||
aces2Params_t *p ) {
|
||||
double c, F;
|
||||
ACES2_SurroundPair( surround, &c, &F );
|
||||
ACES2_InitWith( limitPrims, peakLuminance, c, F, p );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
ACES2_ClampAP0ToAP1
|
||||
|
||||
@@ -251,6 +251,10 @@ typedef struct {
|
||||
} aces2Params_t;
|
||||
|
||||
void ACES2_Init( const double limitPrims[8], double peakLuminance, aces2Params_t *p );
|
||||
/* The same with @surround (as ACES2_SetSurround()'s mode) rather than the
|
||||
* surround set: touches nothing but @p, so it may run on any thread */
|
||||
void ACES2_InitSurround( const double limitPrims[8], double peakLuminance, int surround,
|
||||
aces2Params_t *p );
|
||||
void ACES2_OutputTransformFwd( const double aces[3], const aces2Params_t *p, double RGB[3] );
|
||||
|
||||
/*
|
||||
|
||||
@@ -101,6 +101,10 @@ cbuffer Params : register(b1)
|
||||
int sdrEotf;
|
||||
int scrgb;
|
||||
int deband;
|
||||
int ssaaLog2; /* HDR_ENCODE_SSAA: the samples', log2 */
|
||||
int pad0;
|
||||
int pad1;
|
||||
int pad2;
|
||||
};
|
||||
|
||||
Texture2D<float4> picture : register(t0);
|
||||
@@ -108,6 +112,22 @@ Texture2D<float4> uDtAces2Lut : register(t1);
|
||||
Texture2D<float4> uDtFilmLut : register(t2);
|
||||
Texture2D<float4> uDtFilmDesat : register(t3);
|
||||
Texture3D<float4> uDtAces2Cube : register(t4);
|
||||
#ifdef HDR_ENCODE_SSAA
|
||||
/* With SSAA (after rend/tile/pvr_lane.h and pvr_resolve.h), the samples
|
||||
* the picture was resolved from, read again: where the picture is their
|
||||
* resolve (pvr_resolve_join(), the rule the resolve wrote it by) their
|
||||
* exact average is encoded, not the byte it was rounded to; where
|
||||
* something was drawn over the picture since (the VMUs, the crosshairs),
|
||||
* the picture. As hdr_encode.frag's with SSAA. */
|
||||
Texture2DMS<float4> samples : register(t5);
|
||||
|
||||
/* (a unorm8 colour's bytes, red lowest, as its picture holds them: exact) */
|
||||
uint hdr_pack_unorm8(float4 v)
|
||||
{
|
||||
const uint4 b = uint4(round(saturate(v) * 255.0));
|
||||
return b.r | (b.g << 8) | (b.b << 16) | (b.a << 24);
|
||||
}
|
||||
#endif
|
||||
SamplerState linearClamp : register(s0);
|
||||
SamplerState linearWrap : register(s1);
|
||||
|
||||
@@ -688,7 +708,23 @@ float3 hdr_deband(float3 rgb, float2 fragcoord)
|
||||
|
||||
float4 main(float4 pos : SV_Position) : SV_Target
|
||||
{
|
||||
float3 rgb = picture.Load(int3((int)pos.x, (int)pos.y, 0)).rgb;
|
||||
const float4 pic = picture.Load(int3((int)pos.x, (int)pos.y, 0));
|
||||
float3 rgb = pic.rgb;
|
||||
#ifdef HDR_ENCODE_SSAA
|
||||
{
|
||||
uint rb = 0u;
|
||||
uint ga = 0u;
|
||||
for (uint s = 0u; s < (1u << (uint)ssaaLog2); s++)
|
||||
{
|
||||
const uint c = hdr_pack_unorm8(samples.Load(int2(pos.xy), s));
|
||||
rb += pvr_resolve_rb(c);
|
||||
ga += pvr_resolve_ga(c);
|
||||
}
|
||||
if (hdr_pack_unorm8(pic) == pvr_resolve_join(rb, ga, (uint)ssaaLog2))
|
||||
rgb = float3((float)(rb & 0xffffu), (float)(ga & 0xffffu), (float)(rb >> 16))
|
||||
/ (255.0 * (float)(1u << (uint)ssaaLog2));
|
||||
}
|
||||
#endif
|
||||
if (deband != 0)
|
||||
rgb = hdr_deband(rgb, pos.xy);
|
||||
return float4(encode_hdr_output(rgb, paperWhite, peak, expandGamut, shoulder, sdrEotf,
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
* and the tables (t0-t4) - b0 in the table rather than at the root, since
|
||||
* vkd3d cannot have a root CBV and static samplers both on drivers with
|
||||
* eight descriptor sets (lavapipe's) */
|
||||
#define HDR_D3D12_SRVS 6
|
||||
#define HDR_D3D12_SRVS 7 /* b0; t0 the picture, t1-t4 the tables, t5 SSAA's samples */
|
||||
|
||||
static const IID iid_root_signature = { 0xc54a6b66, 0x72df, 0x4ee8, { 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14 } };
|
||||
static const IID iid_pipeline_state = { 0x765a30f3, 0xf624, 0x4c6f, { 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45 } };
|
||||
@@ -73,6 +73,7 @@ struct hdr_d3d12
|
||||
D3D12_RESOURCE_STATES handed;
|
||||
ID3D12RootSignature *root;
|
||||
ID3D12PipelineState *pso;
|
||||
ID3D12PipelineState *pso_ssaa; /* with SSAA's samples (hdr_encode.hlsl's HDR_ENCODE_SSAA) */
|
||||
ID3D12DescriptorHeap *srv_heap; /* shader visible: HDR_D3D12_SRVS a slot */
|
||||
ID3D12DescriptorHeap *rtv_heap; /* one an output */
|
||||
UINT srv_step;
|
||||
@@ -274,6 +275,19 @@ static void tables_update(hdr_d3d12_t *e, ID3D12GraphicsCommandList *cmd)
|
||||
e->tables[T_DESAT] = table_make(e, cmd, desat, HDR_DT_DESAT_WIDTH, HDR_DT_DESAT_HEIGHT, 1, 4, false, false);
|
||||
}
|
||||
|
||||
/* SSAA's samples at @place of the heap: @res, multisampled, or a null view of one */
|
||||
static void write_srv_ms(hdr_d3d12_t *e, unsigned place, ID3D12Resource *res, DXGI_FORMAT format)
|
||||
{
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC desc;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE h = heap_cpu(e->srv_heap);
|
||||
h.ptr += (SIZE_T)place * e->srv_step;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.Format = format;
|
||||
desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMS;
|
||||
ID3D12Device_CreateShaderResourceView(e->device, res, &desc, h);
|
||||
}
|
||||
|
||||
static void write_srv(hdr_d3d12_t *e, unsigned place, ID3D12Resource *res,
|
||||
DXGI_FORMAT format, bool three_d)
|
||||
{
|
||||
@@ -384,15 +398,15 @@ static bool make_root(hdr_d3d12_t *e)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool make_pso(hdr_d3d12_t *e)
|
||||
static bool make_pso(hdr_d3d12_t *e, const unsigned char *ps, size_t ps_size, ID3D12PipelineState **out)
|
||||
{
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.pRootSignature = e->root;
|
||||
desc.VS.pShaderBytecode = hdr_encode_dxbc_VS;
|
||||
desc.VS.BytecodeLength = sizeof(hdr_encode_dxbc_VS);
|
||||
desc.PS.pShaderBytecode = hdr_encode_dxbc_PS;
|
||||
desc.PS.BytecodeLength = sizeof(hdr_encode_dxbc_PS);
|
||||
desc.PS.pShaderBytecode = ps;
|
||||
desc.PS.BytecodeLength = ps_size;
|
||||
desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||
desc.SampleMask = 0xffffffffu;
|
||||
desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||
@@ -403,7 +417,7 @@ static bool make_pso(hdr_d3d12_t *e)
|
||||
desc.RTVFormats[0] = e->format;
|
||||
desc.SampleDesc.Count = 1;
|
||||
return SUCCEEDED(ID3D12Device_CreateGraphicsPipelineState(e->device, &desc,
|
||||
&iid_pipeline_state, (void **)&e->pso));
|
||||
&iid_pipeline_state, (void **)out));
|
||||
}
|
||||
|
||||
static ID3D12DescriptorHeap *make_heap(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE type,
|
||||
@@ -446,7 +460,9 @@ hdr_d3d12_t *hdr_d3d12_new(ID3D12Device *device, DXGI_FORMAT format,
|
||||
e->rtv_step = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
none.Begin = 0;
|
||||
none.End = 0;
|
||||
if ( !make_root(e) || !make_pso(e)
|
||||
if ( !make_root(e)
|
||||
|| !make_pso(e, hdr_encode_dxbc_PS, sizeof(hdr_encode_dxbc_PS), &e->pso)
|
||||
|| !make_pso(e, hdr_encode_dxbc_PS_SSAA, sizeof(hdr_encode_dxbc_PS_SSAA), &e->pso_ssaa)
|
||||
|| !(e->srv_heap = make_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
HDR_D3D12_SLOTS * HDR_D3D12_SRVS, true))
|
||||
|| !(e->rtv_heap = make_heap(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, HDR_D3D12_MAX_OUTPUTS, false))
|
||||
@@ -476,6 +492,7 @@ void hdr_d3d12_free(hdr_d3d12_t *e)
|
||||
RELEASE(ID3D12DescriptorHeap, e->rtv_heap);
|
||||
RELEASE(ID3D12DescriptorHeap, e->srv_heap);
|
||||
RELEASE(ID3D12PipelineState, e->pso);
|
||||
RELEASE(ID3D12PipelineState, e->pso_ssaa);
|
||||
RELEASE(ID3D12RootSignature, e->root);
|
||||
RELEASE(ID3D12Fence, e->fence);
|
||||
RELEASE(ID3D12Device, e->device);
|
||||
@@ -485,8 +502,8 @@ void hdr_d3d12_free(hdr_d3d12_t *e)
|
||||
bool hdr_d3d12_encode(hdr_d3d12_t *e, ID3D12GraphicsCommandList *cmd,
|
||||
const struct hdr_output *out, ID3D12Resource *picture,
|
||||
DXGI_FORMAT picture_format, unsigned width, unsigned height,
|
||||
bool unorm8, unsigned index, uint64_t signal,
|
||||
ID3D12Resource **texture)
|
||||
bool unorm8, ID3D12Resource *samples, unsigned samples_log2,
|
||||
unsigned index, uint64_t signal, ID3D12Resource **texture)
|
||||
{
|
||||
hdr_d3d12_slot_t *s;
|
||||
hdr_d3d12_output_t *o;
|
||||
@@ -526,7 +543,14 @@ bool hdr_d3d12_encode(hdr_d3d12_t *e, ID3D12GraphicsCommandList *cmd,
|
||||
/* the cube only once the texture of it is here, whatever the block says */
|
||||
if (!e->tables[T_CUBE])
|
||||
block->gm[2] = 0.0f;
|
||||
hdr_encode_params_fill(¶ms, out, unorm8);
|
||||
/* (the samples' exact average is not 8 bits a channel: no dither) */
|
||||
if (samples && samples_log2)
|
||||
{
|
||||
hdr_encode_params_fill(¶ms, out, false);
|
||||
params.ssaa_log2 = (int32_t)samples_log2;
|
||||
}
|
||||
else
|
||||
hdr_encode_params_fill(¶ms, out, unorm8);
|
||||
|
||||
first = e->slot * HDR_D3D12_SRVS;
|
||||
{
|
||||
@@ -538,6 +562,7 @@ bool hdr_d3d12_encode(hdr_d3d12_t *e, ID3D12GraphicsCommandList *cmd,
|
||||
ID3D12Device_CreateConstantBufferView(e->device, &cbv, h);
|
||||
}
|
||||
write_srv(e, first + 1, picture, picture_format, false);
|
||||
write_srv_ms(e, first + 6, params.ssaa_log2 ? samples : NULL, picture_format);
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
unsigned t = i;
|
||||
@@ -564,7 +589,7 @@ bool hdr_d3d12_encode(hdr_d3d12_t *e, ID3D12GraphicsCommandList *cmd,
|
||||
barrier(cmd, o->texture, e->handed, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
ID3D12GraphicsCommandList_SetDescriptorHeaps(cmd, 1, heaps);
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootSignature(cmd, e->root);
|
||||
ID3D12GraphicsCommandList_SetPipelineState(cmd, e->pso);
|
||||
ID3D12GraphicsCommandList_SetPipelineState(cmd, params.ssaa_log2 ? e->pso_ssaa : e->pso);
|
||||
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(cmd, 0,
|
||||
sizeof(params) / 4, ¶ms, 0);
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(cmd, 1, table);
|
||||
|
||||
@@ -33,14 +33,18 @@ void hdr_d3d12_free(hdr_d3d12_t *e);
|
||||
* state, @picture_format, @width x @height, 8 bits a channel when @unorm8)
|
||||
* encoded into the texture for the frontend's frame @index, which is left
|
||||
* in the state the frontend wants; @signal is the value the fence is
|
||||
* signalled with once @cmd is done. *@texture is that texture, the
|
||||
* encoder's to keep. What @cmd had bound - heaps included - is not put
|
||||
* back. False, nothing recorded, when it could not be. */
|
||||
* signalled with once @cmd is done. With SSAA's samples the picture was
|
||||
* resolved from (@samples, multisampled, of @picture_format, in the pixel
|
||||
* shader resource state, 2^@samples_log2 a pixel; NULL and 0 without),
|
||||
* where the picture is their resolve their exact average is encoded.
|
||||
* *@texture is that texture, the encoder's to keep. What @cmd had bound -
|
||||
* heaps included - is not put back. False, nothing recorded, when it could
|
||||
* not be. */
|
||||
bool hdr_d3d12_encode(hdr_d3d12_t *e, ID3D12GraphicsCommandList *cmd,
|
||||
const struct hdr_output *out, ID3D12Resource *picture,
|
||||
DXGI_FORMAT picture_format, unsigned width, unsigned height,
|
||||
bool unorm8, unsigned index, uint64_t signal,
|
||||
ID3D12Resource **texture);
|
||||
bool unorm8, ID3D12Resource *samples, unsigned samples_log2,
|
||||
unsigned index, uint64_t signal, ID3D12Resource **texture);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+5181
-2400
File diff suppressed because it is too large.
Load diff
@@ -21,4 +21,6 @@ void hdr_encode_params_fill(struct hdr_encode_params *p,
|
||||
p->sdr_eotf = o->sdr_eotf;
|
||||
p->scrgb = o->format == HDR_OUTPUT_SCRGB;
|
||||
p->deband = deband;
|
||||
p->ssaa_log2 = 0;
|
||||
p->pad[0] = p->pad[1] = p->pad[2] = 0;
|
||||
}
|
||||
@@ -48,6 +48,8 @@ struct hdr_encode_params
|
||||
int32_t sdr_eotf;
|
||||
int32_t scrgb;
|
||||
int32_t deband; /* the picture is 8 bits a channel */
|
||||
int32_t ssaa_log2; /* Direct3D 12: SSAA's samples the picture was resolved from, log2 (0: none) */
|
||||
int32_t pad[3]; /* (a constant buffer is whole 16 bytes) */
|
||||
};
|
||||
|
||||
void hdr_encode_params_fill(struct hdr_encode_params *p,
|
||||
|
||||
+327
-136
@@ -23,9 +23,17 @@ static struct hdr_dt_settings dt_set = {
|
||||
|
||||
static unsigned dt_generation = 1;
|
||||
|
||||
/* ACES 2.0 (full)'s tables, as made from their key (dt_aces2_key_t):
|
||||
* the reference's parameters, and the hue LUT and its scales the shader
|
||||
* reads. dt_aces2 is dt_tables' parameters, or NULL while there are none. */
|
||||
typedef struct dt_aces2_tables
|
||||
{
|
||||
aces2Params_t params;
|
||||
uint16_t lut[HDR_DT_ACES2_LUT_WIDTH * 4];
|
||||
double scales[4];
|
||||
} dt_aces2_tables_t;
|
||||
static dt_aces2_tables_t *dt_tables;
|
||||
static aces2Params_t *dt_aces2;
|
||||
static uint16_t dt_aces2_lut[HDR_DT_ACES2_LUT_WIDTH * 4];
|
||||
static double dt_aces2_scales[4];
|
||||
static float dt_aces2_peak;
|
||||
static int dt_aces2_gamut = -1;
|
||||
static int dt_aces2_surround = -1;
|
||||
@@ -294,9 +302,9 @@ static bool dt_panel_prims(const uint16_t xy[8], double out[8])
|
||||
return true;
|
||||
}
|
||||
|
||||
static const double *dt_limit_prims(const uint16_t panel_xy[8], double scratch[8])
|
||||
static const double *dt_limit_prims(int gamut, const uint16_t panel_xy[8], double scratch[8])
|
||||
{
|
||||
switch (dt_set.aces2_gamut)
|
||||
switch (gamut)
|
||||
{
|
||||
case 0: return DT_PRIMS_709;
|
||||
case 1: return DT_PRIMS_P3;
|
||||
@@ -312,39 +320,92 @@ static const double *dt_limit_prims(const uint16_t panel_xy[8], double scratch[8
|
||||
return DT_PRIMS_P3;
|
||||
}
|
||||
|
||||
static bool dt_aces2_build(float peak, const uint16_t panel_xy[8])
|
||||
/* What ACES 2.0 (full)'s tables are made from */
|
||||
typedef struct dt_aces2_key
|
||||
{
|
||||
float peak;
|
||||
int gamut;
|
||||
int surround;
|
||||
uint16_t xy[8];
|
||||
} dt_aces2_key_t;
|
||||
|
||||
static void dt_aces2_key_now(float peak, const uint16_t panel_xy[8], dt_aces2_key_t *k)
|
||||
{
|
||||
k->peak = peak;
|
||||
k->gamut = dt_set.aces2_gamut;
|
||||
k->surround = dt_set.aces2_surround;
|
||||
memcpy(k->xy, panel_xy, sizeof(k->xy));
|
||||
}
|
||||
|
||||
/* Peak arrives every frame; a jittering last bit must not re-solve the
|
||||
* searched tables. The panel's primaries count only with the display's
|
||||
* gamut. */
|
||||
static bool dt_aces2_key_same(const dt_aces2_key_t *a, const dt_aces2_key_t *b)
|
||||
{
|
||||
return fabs((double)a->peak - (double)b->peak) < 0.5
|
||||
&& a->gamut == b->gamut && a->surround == b->surround
|
||||
&& (a->gamut != 3 || memcmp(a->xy, b->xy, sizeof(a->xy)) == 0);
|
||||
}
|
||||
|
||||
/* The tables @t (made from @k) made the ones in use */
|
||||
static void dt_aces2_adopt(dt_aces2_tables_t *t, const dt_aces2_key_t *k)
|
||||
{
|
||||
free(dt_tables);
|
||||
dt_tables = t;
|
||||
dt_aces2 = &t->params;
|
||||
dt_aces2_built++;
|
||||
dt_aces2_peak = k->peak;
|
||||
dt_aces2_gamut = k->gamut;
|
||||
dt_aces2_surround = k->surround;
|
||||
memcpy(dt_aces2_xy, k->xy, sizeof(dt_aces2_xy));
|
||||
dt_generation++;
|
||||
}
|
||||
|
||||
/* The tables for @k, from the limiting primaries @prims: the solve that
|
||||
* costs a few milliseconds (ACES2_Init()'s searched tables). Touches only
|
||||
* what it makes, so it may run on any thread. */
|
||||
static dt_aces2_tables_t *dt_aces2_make(const double prims[8], const dt_aces2_key_t *k)
|
||||
{
|
||||
dt_aces2_tables_t *t = (dt_aces2_tables_t*)calloc(1, sizeof(*t));
|
||||
if (!t)
|
||||
return NULL;
|
||||
ACES2_InitSurround(prims, (double)k->peak, k->surround, &t->params);
|
||||
ACES2_PackHueTables(&t->params, t->lut, t->scales);
|
||||
return t;
|
||||
}
|
||||
|
||||
/* The tables there are already for @k */
|
||||
static bool dt_aces2_current(const dt_aces2_key_t *k)
|
||||
{
|
||||
dt_aces2_key_t have;
|
||||
if (!dt_tables)
|
||||
return false;
|
||||
have.peak = dt_aces2_peak;
|
||||
have.gamut = dt_aces2_gamut;
|
||||
have.surround = dt_aces2_surround;
|
||||
memcpy(have.xy, dt_aces2_xy, sizeof(have.xy));
|
||||
return dt_aces2_key_same(&have, k);
|
||||
}
|
||||
|
||||
/* The tables for @k made here, now */
|
||||
static bool dt_aces2_build_here(const dt_aces2_key_t *k)
|
||||
{
|
||||
double scratch[8];
|
||||
const double *prims;
|
||||
bool same_xy = (memcmp(dt_aces2_xy, panel_xy, sizeof(dt_aces2_xy)) == 0);
|
||||
|
||||
/* Peak arrives every frame; a jittering last bit must not re-solve
|
||||
* the searched tables. */
|
||||
if (dt_aces2 && fabs((double)dt_aces2_peak - (double)peak) < 0.5
|
||||
&& dt_aces2_gamut == dt_set.aces2_gamut
|
||||
&& dt_aces2_surround == dt_set.aces2_surround
|
||||
&& (dt_set.aces2_gamut != 3 || same_xy))
|
||||
dt_aces2_tables_t *t;
|
||||
if (dt_aces2_current(k))
|
||||
return true;
|
||||
|
||||
if (!dt_aces2)
|
||||
{
|
||||
dt_aces2 = (aces2Params_t*)calloc(1, sizeof(*dt_aces2));
|
||||
if (!dt_aces2)
|
||||
return false;
|
||||
}
|
||||
prims = dt_limit_prims(panel_xy, scratch);
|
||||
ACES2_SetSurround(dt_set.aces2_surround);
|
||||
ACES2_Init(prims, (double)peak, dt_aces2);
|
||||
ACES2_PackHueTables(dt_aces2, dt_aces2_lut, dt_aces2_scales);
|
||||
dt_aces2_built++;
|
||||
dt_aces2_peak = peak;
|
||||
dt_aces2_gamut = dt_set.aces2_gamut;
|
||||
dt_aces2_surround = dt_set.aces2_surround;
|
||||
memcpy(dt_aces2_xy, panel_xy, sizeof(dt_aces2_xy));
|
||||
dt_generation++;
|
||||
t = dt_aces2_make(dt_limit_prims(k->gamut, k->xy, scratch), k);
|
||||
if (!t)
|
||||
return dt_tables != NULL;
|
||||
dt_aces2_adopt(t, k);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The tables for @peak and the panel's primaries; with threads, made by
|
||||
* the worker (below) while those there are go on being used. True while
|
||||
* there are any. */
|
||||
static bool dt_aces2_build(float peak, const uint16_t panel_xy[8]);
|
||||
|
||||
/* A CTL 3x3 (row vector times matrix, i.e. GL column-major) into std140. */
|
||||
static void dt_mat3(float dst[12], const double m[9])
|
||||
{
|
||||
@@ -519,81 +580,124 @@ static bool dt_cube_bake_here(unsigned rows, float paper)
|
||||
}
|
||||
|
||||
#ifndef TARGET_NO_THREADS
|
||||
/* The cube is baked on a worker of its own, so that no frame pays for it:
|
||||
* the frame thread hands it a job - a copy of the tables and the paper
|
||||
* white, and a cube to fill - and takes back what it is done with, and
|
||||
* neither ever waits for the other. All of it is atomics: the job handed
|
||||
* over is one pointer (exchanged), what comes back a list pushed to with
|
||||
* a CAS, a superseded job told to stop by a flag of its own. The worker
|
||||
* parks on an eventcount between jobs. Only the frame thread allocates,
|
||||
* frees and reads the cubes; the worker writes the one cube it holds.
|
||||
/* ACES 2.0 (full)'s tables and its cube are made on a worker of its own,
|
||||
* so that no frame pays for them: the frame thread hands it a job - for
|
||||
* the tables, the primaries, peak and surround to solve them for; for the
|
||||
* cube, a copy of the tables and the paper white, and a cube to fill -
|
||||
* and takes back what it is done with, and neither ever waits for the
|
||||
* other. Until new tables are back the ones there are go on being used,
|
||||
* and their cube with them; with none yet, the tone scale alone is drawn.
|
||||
* All of it is atomics: a job handed over is one pointer for each kind
|
||||
* (exchanged), what comes back a list pushed to with a CAS, a superseded
|
||||
* job told to stop by a flag of its own. The worker parks on an
|
||||
* eventcount between jobs. Only the frame thread allocates, frees and
|
||||
* reads what is made; the worker writes only the job it holds.
|
||||
* hdr_dt_free() stops it and joins it, outside any frame. */
|
||||
typedef struct dt_cube_job
|
||||
enum { DT_JOB_TABLES = 0, DT_JOB_CUBE, DT_JOB_KINDS };
|
||||
|
||||
typedef struct dt_job
|
||||
{
|
||||
int kind;
|
||||
retro_atomic_int_t stop; /* superseded: give up (the cube) */
|
||||
int done; /* the worker's, read once the job is back */
|
||||
struct dt_job *next; /* on the list of jobs back */
|
||||
/* the tables: what they are for, made into tables */
|
||||
dt_aces2_key_t key;
|
||||
double prims[8];
|
||||
dt_aces2_tables_t *tables;
|
||||
/* the cube: from a copy of the tables, at paper */
|
||||
aces2Params_t params;
|
||||
float paper;
|
||||
uint16_t *cube;
|
||||
retro_atomic_int_t stop; /* superseded: give up */
|
||||
int baked; /* the worker's, read once the job is back */
|
||||
struct dt_cube_job *next; /* on the list of jobs back */
|
||||
} dt_cube_job_t;
|
||||
} dt_job_t;
|
||||
|
||||
static struct
|
||||
{
|
||||
sthread_t *thread;
|
||||
retro_eventcount_t work; /* the worker parks here */
|
||||
retro_atomic_ptr_t want; /* the job handed over, not yet taken */
|
||||
retro_atomic_ptr_t back; /* the jobs it is done with, newest first */
|
||||
retro_eventcount_t work; /* the worker parks here */
|
||||
retro_atomic_ptr_t want[DT_JOB_KINDS]; /* a job handed over, not yet taken */
|
||||
retro_atomic_ptr_t back; /* the jobs it is done with, newest first */
|
||||
retro_atomic_int_t quit;
|
||||
dt_cube_job_t *current; /* the frame thread's: the job for the cube wanted */
|
||||
dt_job_t *current[DT_JOB_KINDS]; /* the frame thread's: the job for what is wanted */
|
||||
bool ready;
|
||||
bool failed; /* no worker could be had: baked here */
|
||||
bool failed; /* no worker could be had: made here */
|
||||
} dt_baker;
|
||||
|
||||
static void dt_job_free(dt_cube_job_t *job)
|
||||
static void dt_job_free(dt_job_t *job)
|
||||
{
|
||||
if (!job)
|
||||
return;
|
||||
free(job->tables);
|
||||
free(job->cube);
|
||||
free(job);
|
||||
}
|
||||
|
||||
static void dt_baker_thread(void *unused)
|
||||
static void dt_job_run(dt_job_t *job)
|
||||
{
|
||||
const unsigned n = HDR_DT_ACES2_CUBE;
|
||||
unsigned row;
|
||||
if (job->kind == DT_JOB_TABLES)
|
||||
{
|
||||
job->tables = dt_aces2_make(job->prims, &job->key);
|
||||
job->done = job->tables != NULL;
|
||||
return;
|
||||
}
|
||||
for (row = 0; row < n * n; row++)
|
||||
{
|
||||
if (retro_atomic_load_relaxed_int(&job->stop)
|
||||
|| retro_atomic_load_relaxed_int(&dt_baker.quit))
|
||||
break;
|
||||
dt_cube_row(job->cube, row, job->paper, &job->params);
|
||||
}
|
||||
job->done = row == n * n;
|
||||
}
|
||||
|
||||
static dt_job_t *dt_baker_take(void)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < DT_JOB_KINDS; k++)
|
||||
{
|
||||
dt_job_t *job = (dt_job_t*)retro_atomic_exchange_ptr(&dt_baker.want[k], NULL);
|
||||
if (job)
|
||||
return job;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool dt_baker_wanted(void)
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < DT_JOB_KINDS; k++)
|
||||
if (retro_atomic_load_acquire_ptr(&dt_baker.want[k]) != NULL)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dt_baker_thread(void *unused)
|
||||
{
|
||||
(void)unused;
|
||||
for (;;)
|
||||
{
|
||||
dt_cube_job_t *job = (dt_cube_job_t*)retro_atomic_exchange_ptr(&dt_baker.want, NULL);
|
||||
/* (the tables first: the cube is made from them) */
|
||||
dt_job_t *job = dt_baker_take();
|
||||
if (!job)
|
||||
{
|
||||
int key;
|
||||
if (retro_atomic_load_acquire_int(&dt_baker.quit))
|
||||
return;
|
||||
key = retro_eventcount_prepare_wait(&dt_baker.work);
|
||||
if (retro_atomic_load_acquire_ptr(&dt_baker.want) != NULL
|
||||
|| retro_atomic_load_acquire_int(&dt_baker.quit))
|
||||
if (dt_baker_wanted() || retro_atomic_load_acquire_int(&dt_baker.quit))
|
||||
retro_eventcount_cancel_wait(&dt_baker.work);
|
||||
else
|
||||
retro_eventcount_commit_wait(&dt_baker.work, key);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
unsigned row;
|
||||
for (row = 0; row < n * n; row++)
|
||||
{
|
||||
if (retro_atomic_load_relaxed_int(&job->stop)
|
||||
|| retro_atomic_load_relaxed_int(&dt_baker.quit))
|
||||
break;
|
||||
dt_cube_row(job->cube, row, job->paper, &job->params);
|
||||
}
|
||||
job->baked = row == n * n;
|
||||
}
|
||||
/* back, the cube with it (release: the frame thread reads the cube) */
|
||||
dt_job_run(job);
|
||||
/* back, with what it made (release: the frame thread reads it) */
|
||||
for (;;)
|
||||
{
|
||||
void *head = retro_atomic_load_relaxed_ptr(&dt_baker.back);
|
||||
job->next = (dt_cube_job_t*)head;
|
||||
job->next = (dt_job_t*)head;
|
||||
if (retro_atomic_cas_ptr(&dt_baker.back, head, job))
|
||||
break;
|
||||
}
|
||||
@@ -602,6 +706,7 @@ static void dt_baker_thread(void *unused)
|
||||
|
||||
static bool dt_baker_start(void)
|
||||
{
|
||||
int k;
|
||||
if (dt_baker.thread)
|
||||
return true;
|
||||
if (dt_baker.failed)
|
||||
@@ -613,7 +718,8 @@ static bool dt_baker_start(void)
|
||||
dt_baker.failed = true;
|
||||
return false;
|
||||
}
|
||||
retro_atomic_ptr_init(&dt_baker.want, NULL);
|
||||
for (k = 0; k < DT_JOB_KINDS; k++)
|
||||
retro_atomic_ptr_init(&dt_baker.want[k], NULL);
|
||||
retro_atomic_ptr_init(&dt_baker.back, NULL);
|
||||
dt_baker.ready = true;
|
||||
}
|
||||
@@ -624,88 +730,133 @@ static bool dt_baker_start(void)
|
||||
return dt_baker.thread != NULL;
|
||||
}
|
||||
|
||||
/* The job for the cube wanted is no longer wanted */
|
||||
static void dt_baker_drop(void)
|
||||
/* @job, made, handed to the worker as what is wanted of its kind */
|
||||
static void dt_baker_submit(dt_job_t *job)
|
||||
{
|
||||
dt_cube_job_t *job = dt_baker.current;
|
||||
dt_cube_job_t *untaken;
|
||||
dt_baker.current = NULL;
|
||||
retro_atomic_int_init(&job->stop, 0);
|
||||
dt_baker.current[job->kind] = job;
|
||||
/* (empty: a job left in it was dropped and taken back, or taken) */
|
||||
dt_job_free((dt_job_t*)retro_atomic_exchange_ptr(&dt_baker.want[job->kind], job));
|
||||
retro_eventcount_notify(&dt_baker.work);
|
||||
}
|
||||
|
||||
/* The job of @kind for what is wanted is no longer wanted */
|
||||
static void dt_baker_drop(int kind)
|
||||
{
|
||||
dt_job_t *job = dt_baker.current[kind];
|
||||
dt_job_t *untaken;
|
||||
dt_baker.current[kind] = NULL;
|
||||
if (!job)
|
||||
return;
|
||||
retro_atomic_store_release_int(&job->stop, 1);
|
||||
/* still not taken: the worker never sees it */
|
||||
untaken = (dt_cube_job_t*)retro_atomic_load_acquire_ptr(&dt_baker.want);
|
||||
if (untaken == job && retro_atomic_cas_ptr(&dt_baker.want, job, NULL))
|
||||
untaken = (dt_job_t*)retro_atomic_load_acquire_ptr(&dt_baker.want[kind]);
|
||||
if (untaken == job && retro_atomic_cas_ptr(&dt_baker.want[kind], job, NULL))
|
||||
dt_job_free(job);
|
||||
/* else it comes back, and is freed then */
|
||||
}
|
||||
|
||||
/* What the worker is done with: the cube wanted made the one in use, the
|
||||
* rest freed. True when the cube wanted is complete. */
|
||||
static bool dt_baker_collect(void)
|
||||
/* What the worker is done with: the tables and the cube wanted made the
|
||||
* ones in use, the rest freed */
|
||||
static void dt_baker_collect(void)
|
||||
{
|
||||
const unsigned n = HDR_DT_ACES2_CUBE;
|
||||
dt_cube_job_t *job = (dt_cube_job_t*)retro_atomic_exchange_ptr(&dt_baker.back, NULL);
|
||||
bool complete = dt_cube_rows == n * n;
|
||||
dt_job_t *job;
|
||||
if (!dt_baker.ready)
|
||||
return;
|
||||
job = (dt_job_t*)retro_atomic_exchange_ptr(&dt_baker.back, NULL);
|
||||
while (job)
|
||||
{
|
||||
dt_cube_job_t *next = job->next;
|
||||
if (job == dt_baker.current)
|
||||
dt_job_t *next = job->next;
|
||||
if (job == dt_baker.current[job->kind])
|
||||
{
|
||||
dt_baker.current = NULL;
|
||||
if (job->baked)
|
||||
dt_baker.current[job->kind] = NULL;
|
||||
if (job->done && job->kind == DT_JOB_TABLES)
|
||||
{
|
||||
dt_aces2_adopt(job->tables, &job->key);
|
||||
job->tables = NULL;
|
||||
}
|
||||
else if (job->done)
|
||||
{
|
||||
free(dt_cube);
|
||||
dt_cube = job->cube;
|
||||
job->cube = NULL;
|
||||
dt_cube_rows = n * n;
|
||||
dt_generation++;
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
dt_job_free(job);
|
||||
job = next;
|
||||
}
|
||||
return complete;
|
||||
}
|
||||
|
||||
static bool dt_aces2_build(float peak, const uint16_t panel_xy[8])
|
||||
{
|
||||
dt_aces2_key_t k;
|
||||
dt_job_t *job;
|
||||
dt_aces2_key_now(peak, panel_xy, &k);
|
||||
dt_baker_collect();
|
||||
if (dt_aces2_current(&k))
|
||||
{
|
||||
/* (a job for others, wanted before these came back, goes) */
|
||||
dt_baker_drop(DT_JOB_TABLES);
|
||||
return true;
|
||||
}
|
||||
if (!dt_baker_start())
|
||||
return dt_aces2_build_here(&k);
|
||||
job = dt_baker.current[DT_JOB_TABLES];
|
||||
if (job && dt_aces2_key_same(&job->key, &k))
|
||||
return dt_tables != NULL;
|
||||
dt_baker_drop(DT_JOB_TABLES);
|
||||
job = (dt_job_t*)calloc(1, sizeof(*job));
|
||||
if (!job)
|
||||
return dt_tables != NULL;
|
||||
job->kind = DT_JOB_TABLES;
|
||||
job->key = k;
|
||||
{
|
||||
double scratch[8];
|
||||
memcpy(job->prims, dt_limit_prims(k.gamut, k.xy, scratch), sizeof(job->prims));
|
||||
}
|
||||
dt_baker_submit(job);
|
||||
return dt_tables != NULL;
|
||||
}
|
||||
|
||||
/* true once the cube is complete; never waits */
|
||||
static bool dt_cube_bake(unsigned rows, float paper)
|
||||
{
|
||||
const unsigned n = HDR_DT_ACES2_CUBE;
|
||||
dt_job_t *job;
|
||||
if (!dt_aces2)
|
||||
return false;
|
||||
dt_baker_collect();
|
||||
if (dt_cube_rekey(paper))
|
||||
dt_baker_drop();
|
||||
dt_baker_drop(DT_JOB_CUBE);
|
||||
if (!dt_baker_start())
|
||||
return dt_cube_bake_here(rows, paper);
|
||||
if (dt_baker_collect())
|
||||
if (dt_cube_rows == n * n)
|
||||
return true;
|
||||
if (!dt_baker.current)
|
||||
if (dt_baker.current[DT_JOB_CUBE])
|
||||
return false;
|
||||
job = (dt_job_t*)calloc(1, sizeof(*job));
|
||||
if (!job)
|
||||
return false;
|
||||
job->cube = (uint16_t*)malloc(sizeof(uint16_t) * 4 * n * n * n);
|
||||
if (!job->cube)
|
||||
{
|
||||
dt_cube_job_t *job = (dt_cube_job_t*)calloc(1, sizeof(*job));
|
||||
if (!job)
|
||||
return false;
|
||||
job->cube = (uint16_t*)malloc(sizeof(uint16_t) * 4 * n * n * n);
|
||||
if (!job->cube)
|
||||
{
|
||||
free(job);
|
||||
return false;
|
||||
}
|
||||
job->params = *dt_aces2;
|
||||
job->paper = paper;
|
||||
retro_atomic_int_init(&job->stop, 0);
|
||||
dt_baker.current = job;
|
||||
/* (want is empty: a job left in it was dropped and taken back above) */
|
||||
dt_job_free((dt_cube_job_t*)retro_atomic_exchange_ptr(&dt_baker.want, job));
|
||||
retro_eventcount_notify(&dt_baker.work);
|
||||
free(job);
|
||||
return false;
|
||||
}
|
||||
job->kind = DT_JOB_CUBE;
|
||||
job->params = *dt_aces2;
|
||||
job->paper = paper;
|
||||
dt_baker_submit(job);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The worker stopped and joined, and all it held freed: outside a frame */
|
||||
static void dt_baker_free(void)
|
||||
{
|
||||
int k;
|
||||
if (dt_baker.thread)
|
||||
{
|
||||
retro_atomic_store_release_int(&dt_baker.quit, 1);
|
||||
@@ -715,23 +866,31 @@ static void dt_baker_free(void)
|
||||
}
|
||||
if (dt_baker.ready)
|
||||
{
|
||||
dt_job_free((dt_cube_job_t*)retro_atomic_exchange_ptr(&dt_baker.want, NULL));
|
||||
dt_job_t *job;
|
||||
for (k = 0; k < DT_JOB_KINDS; k++)
|
||||
dt_job_free((dt_job_t*)retro_atomic_exchange_ptr(&dt_baker.want[k], NULL));
|
||||
job = (dt_job_t*)retro_atomic_exchange_ptr(&dt_baker.back, NULL);
|
||||
while (job)
|
||||
{
|
||||
dt_cube_job_t *job = (dt_cube_job_t*)retro_atomic_exchange_ptr(&dt_baker.back, NULL);
|
||||
while (job)
|
||||
{
|
||||
dt_cube_job_t *next = job->next;
|
||||
dt_job_free(job);
|
||||
job = next;
|
||||
}
|
||||
dt_job_t *next = job->next;
|
||||
dt_job_free(job);
|
||||
job = next;
|
||||
}
|
||||
retro_eventcount_free(&dt_baker.work);
|
||||
dt_baker.ready = false;
|
||||
}
|
||||
dt_baker.current = NULL;
|
||||
dt_baker.failed = false;
|
||||
for (k = 0; k < DT_JOB_KINDS; k++)
|
||||
dt_baker.current[k] = NULL;
|
||||
dt_baker.failed = false;
|
||||
}
|
||||
#else
|
||||
static bool dt_aces2_build(float peak, const uint16_t panel_xy[8])
|
||||
{
|
||||
dt_aces2_key_t k;
|
||||
dt_aces2_key_now(peak, panel_xy, &k);
|
||||
return dt_aces2_build_here(&k);
|
||||
}
|
||||
|
||||
static bool dt_cube_bake(unsigned rows, float paper)
|
||||
{
|
||||
return dt_cube_bake_here(rows, paper);
|
||||
@@ -743,10 +902,10 @@ void hdr_dt_aces2_cube_finish(float paper_white_nits)
|
||||
if (!dt_aces2)
|
||||
return;
|
||||
#ifndef TARGET_NO_THREADS
|
||||
if (dt_cube_rekey(paper_white_nits))
|
||||
dt_baker_drop();
|
||||
dt_baker_collect();
|
||||
dt_cube_rekey(paper_white_nits);
|
||||
if (dt_cube_rows < HDR_DT_ACES2_CUBE * HDR_DT_ACES2_CUBE)
|
||||
dt_baker_drop();
|
||||
dt_baker_drop(DT_JOB_CUBE);
|
||||
#endif
|
||||
dt_cube_bake_here(HDR_DT_ACES2_CUBE * HDR_DT_ACES2_CUBE, paper_white_nits);
|
||||
}
|
||||
@@ -782,26 +941,52 @@ bool hdr_dt_enabled(void)
|
||||
return dt_set.curve != HDR_DT_KNEE;
|
||||
}
|
||||
|
||||
void hdr_dt_fill(struct hdr_dt_block *b, float paper_white_nits,
|
||||
float peak_nits, float panel_peak_nits, const uint16_t panel_xy[8])
|
||||
/* The peak the curves go to: the frontend's, the panel's own or the set */
|
||||
static float dt_peak(float peak_nits, float panel_peak_nits)
|
||||
{
|
||||
int curve = dt_set.curve;
|
||||
float paper = paper_white_nits > 0.0f ? paper_white_nits : 200.0f;
|
||||
float peak = peak_nits;
|
||||
float H, A, slope, film[2];
|
||||
double S0, S1, C2;
|
||||
|
||||
memset(b, 0, sizeof(*b));
|
||||
float peak = peak_nits;
|
||||
if (dt_set.peak_mode == 1 && panel_peak_nits > 0.0f)
|
||||
peak = panel_peak_nits;
|
||||
else if (dt_set.peak_mode == 2 && dt_set.peak_nits > 0.0f)
|
||||
peak = dt_set.peak_nits;
|
||||
if (!(peak > 0.0f))
|
||||
peak = 1000.0f;
|
||||
return peak;
|
||||
}
|
||||
|
||||
void hdr_dt_finish(float paper_white_nits, float peak_nits,
|
||||
float panel_peak_nits, const uint16_t panel_xy[8], bool cube)
|
||||
{
|
||||
dt_aces2_key_t k;
|
||||
if (dt_set.curve != HDR_DT_ACES2FULL)
|
||||
return;
|
||||
dt_aces2_key_now(dt_peak(peak_nits, panel_peak_nits), panel_xy, &k);
|
||||
#ifndef TARGET_NO_THREADS
|
||||
dt_baker_collect();
|
||||
if (!dt_aces2_current(&k))
|
||||
dt_baker_drop(DT_JOB_TABLES);
|
||||
#endif
|
||||
dt_aces2_build_here(&k);
|
||||
if (cube)
|
||||
hdr_dt_aces2_cube_finish(paper_white_nits > 0.0f ? paper_white_nits : 200.0f);
|
||||
}
|
||||
|
||||
void hdr_dt_fill(struct hdr_dt_block *b, float paper_white_nits,
|
||||
float peak_nits, float panel_peak_nits, const uint16_t panel_xy[8])
|
||||
{
|
||||
int curve = dt_set.curve;
|
||||
float paper = paper_white_nits > 0.0f ? paper_white_nits : 200.0f;
|
||||
float peak = dt_peak(peak_nits, panel_peak_nits);
|
||||
float H, A, slope, film[2];
|
||||
double S0, S1, C2;
|
||||
|
||||
memset(b, 0, sizeof(*b));
|
||||
H = peak / paper;
|
||||
if (H < 1.0f)
|
||||
H = 1.0f;
|
||||
|
||||
/* (with threads the tables are made by the worker, and those there
|
||||
* are drawn with until they are: with none yet, the tone scale alone) */
|
||||
if (curve == HDR_DT_ACES2FULL && !dt_aces2_build(peak, panel_xy))
|
||||
curve = HDR_DT_ACES2; /* no tables: the tone scale alone */
|
||||
|
||||
@@ -832,14 +1017,23 @@ void hdr_dt_fill(struct hdr_dt_block *b, float paper_white_nits,
|
||||
|
||||
if (curve == HDR_DT_ACES2FULL)
|
||||
{
|
||||
const aces2Params_t *p = dt_aces2;
|
||||
const aces2Params_t *p;
|
||||
double scratch[8], m[9];
|
||||
int i;
|
||||
/* Once the cube is baked the shader reads it instead of solving the
|
||||
* transform per pixel. Until then, it is baked (on a worker of its
|
||||
* own where there are threads). First: what it takes back from the
|
||||
* worker can be new tables, which free the ones before, so the
|
||||
* block is of those there are after it. */
|
||||
b->gm[2] = dt_cube_bake(HDR_DT_CUBE_ROWS_PER_FILL, paper) ? 1.0f : 0.0f;
|
||||
p = dt_aces2;
|
||||
dt_mat3(b->in_rgb_to_cam, p->input.RGB_to_CAM16_c);
|
||||
dt_mat3(b->in_cone_to_aab, p->input.cone_to_Aab);
|
||||
dt_mat3(b->lim_aab_to_cone, p->limit.Aab_to_cone);
|
||||
dt_mat3(b->lim_cam_to_rgb, p->limit.CAM16_c_to_RGB);
|
||||
if (!ACES2_PrimariesMatrix(dt_limit_prims(panel_xy, scratch), DT_PRIMS_2020, m))
|
||||
/* (the gamut the tables in use are for, which until the worker's are
|
||||
* back may not be the one set) */
|
||||
if (!ACES2_PrimariesMatrix(dt_limit_prims(dt_aces2_gamut, dt_aces2_xy, scratch), DT_PRIMS_2020, m))
|
||||
for (i = 0; i < 9; i++)
|
||||
m[i] = (i % 4 == 0) ? 1.0 : 0.0;
|
||||
dt_mat3(b->aces2_to_out, m);
|
||||
@@ -865,18 +1059,14 @@ void hdr_dt_fill(struct hdr_dt_block *b, float paper_white_nits,
|
||||
b->cc2[3] = (float)p->gamut.focus_dist;
|
||||
b->gm[0] = (float)p->gamut.lower_hull_gamma_inv;
|
||||
b->gm[1] = (float)p->ts.forward_limit;
|
||||
/* Once the cube is baked the shader reads it instead of solving the
|
||||
* transform per pixel. Until then, it is baked (on a worker
|
||||
* of its own where there are threads). */
|
||||
b->gm[2] = dt_cube_bake(HDR_DT_CUBE_ROWS_PER_FILL, paper) ? 1.0f : 0.0f;
|
||||
for (i = 0; i < 4; i++)
|
||||
b->lut_scale[i] = (float)dt_aces2_scales[i];
|
||||
b->lut_scale[i] = (float)dt_tables->scales[i];
|
||||
}
|
||||
}
|
||||
|
||||
const uint16_t *hdr_dt_aces2_lut(void)
|
||||
{
|
||||
return dt_aces2 ? dt_aces2_lut : NULL;
|
||||
return dt_tables ? dt_tables->lut : NULL;
|
||||
}
|
||||
|
||||
const uint16_t *hdr_dt_film_lut(void)
|
||||
@@ -1001,7 +1191,8 @@ void hdr_dt_free(void)
|
||||
free(dt_cube);
|
||||
dt_cube = NULL;
|
||||
dt_cube_rows = 0;
|
||||
free(dt_aces2);
|
||||
free(dt_tables);
|
||||
dt_tables = NULL;
|
||||
dt_aces2 = NULL;
|
||||
dt_aces2_gamut = -1;
|
||||
dt_aces2_surround = -1;
|
||||
|
||||
@@ -117,6 +117,11 @@ unsigned hdr_dt_generation(void);
|
||||
const uint16_t *hdr_dt_aces2_cube(void);
|
||||
/* Bake the rest of the cube now; for tests. */
|
||||
void hdr_dt_aces2_cube_finish(float paper_white_nits);
|
||||
/* ACES 2.0 (full)'s tables for these, made now if they are not there (and
|
||||
* with @cube, its cube too), where the fills leave them to the worker;
|
||||
* for tests, which want what they draw now. Nothing for other curves. */
|
||||
void hdr_dt_finish(float paper_white_nits, float peak_nits,
|
||||
float panel_peak_nits, const uint16_t panel_xy[8], bool cube);
|
||||
/* The reference the cube is baked from: what dt_aces2() computes, in
|
||||
* double precision. Scene Rec.709 (1.0 = paper white) in, the limiting
|
||||
* primaries (1.0 = 100 nits) out. Valid once hdr_dt_fill ran with
|
||||
|
||||
@@ -430,6 +430,14 @@ layout(constant_id = 1) const uint PVRC_LOG2N = 0u;
|
||||
layout(constant_id = 2) const uint PVRC_KEEP = 4u;
|
||||
layout(constant_id = 3) const uint PVRC_TEST = 0u;
|
||||
layout(constant_id = 4) const uint PVRC_VARIANT = 0u;
|
||||
#if defined(PVRC_SUMS)
|
||||
/* Vulkan's walk, with the HDR output: each pixel's channel sums stored
|
||||
* too, scaled to 16 samples (vulkan/hdr_encode_vk.h's HDR_VK_SUMS_LOG2),
|
||||
* for the encode to have the exact average the picture was rounded from.
|
||||
* (Not in the Direct3D 12 kernels: tools/rend/kernels_dx12.sh leaves
|
||||
* these blocks out.) */
|
||||
layout(constant_id = 5) const uint PVRC_SUMS_ON = 0u;
|
||||
#endif /* PVRC_SUMS */
|
||||
|
||||
#if PVRC_KERNEL == PVRC_K_GPUSRC
|
||||
layout(std430, set = 0, binding = 0) coherent buffer Frame { uint w[]; } frm;
|
||||
@@ -1443,6 +1451,9 @@ layout(local_size_x = 256) in;
|
||||
|
||||
#if defined(PVRC_SHADER_GLSL)
|
||||
layout(set = 0, binding = 3, rgba8) uniform writeonly image2D outImage;
|
||||
#if defined(PVRC_SUMS)
|
||||
layout(set = 0, binding = 13, rgba16ui) uniform writeonly uimage2D sumsImage;
|
||||
#endif /* PVRC_SUMS */
|
||||
layout(set = 0, binding = 4) uniform sampler2D lastPicture;
|
||||
layout(set = 0, binding = 5) uniform sampler2D palette;
|
||||
layout(set = 0, binding = 6) uniform sampler2D textures[PVRC_TEX_SLOTS];
|
||||
@@ -3124,6 +3135,9 @@ void main()
|
||||
uint c;
|
||||
ivec2 at = ivec2(g_px, g_py);
|
||||
bool stores = smp == 0u && g_in;
|
||||
#if defined(PVRC_SUMS)
|
||||
uint sums_rb = pvr_resolve_rb(g_col), sums_ga = pvr_resolve_ga(g_col), sums_log2 = PVRC_LOG2N;
|
||||
#endif /* PVRC_SUMS */
|
||||
if ((frm.w[PVRC_F_FLAGS] & PVRC_FF_HSCALE) != 0u)
|
||||
{
|
||||
uint rb = pvr_resolve_rb(g_col), ga = pvr_resolve_ga(g_col);
|
||||
@@ -3140,6 +3154,11 @@ void main()
|
||||
rb += orb;
|
||||
}
|
||||
c = pvr_resolve_join(rb, ga, PVRC_LOG2N + 1u);
|
||||
#if defined(PVRC_SUMS)
|
||||
sums_rb = rb;
|
||||
sums_ga = ga;
|
||||
sums_log2 = PVRC_LOG2N + 1u;
|
||||
#endif /* PVRC_SUMS */
|
||||
at.x = g_px >> 1;
|
||||
stores = stores && (g_px & 1) == 0;
|
||||
}
|
||||
@@ -3149,6 +3168,23 @@ void main()
|
||||
* it rounds or truncates, and however it divides, gives the byte) */
|
||||
if (stores)
|
||||
imageStore(outImage, at, (vec4(float(c & 255u), float((c >> 8) & 255u), float((c >> 16) & 255u), float(c >> 24)) + 0.25) / 255.0);
|
||||
#if defined(PVRC_SUMS)
|
||||
if (PVRC_SUMS_ON != 0u)
|
||||
{
|
||||
/* (the lanes of a pixel's samples summed as pvr_resolve_lanes()
|
||||
* does, where the X scaler did not sum them above) */
|
||||
if ((frm.w[PVRC_F_FLAGS] & PVRC_FF_HSCALE) == 0u)
|
||||
for (uint m = 1u; m < PVRC_SAMPLES; m <<= 1)
|
||||
{
|
||||
sums_rb += LANE_SHUFFLE_XOR(sums_rb, m);
|
||||
sums_ga += LANE_SHUFFLE_XOR(sums_ga, m);
|
||||
}
|
||||
sums_rb <<= 4u - sums_log2;
|
||||
sums_ga <<= 4u - sums_log2;
|
||||
if (stores)
|
||||
imageStore(sumsImage, at, uvec4(sums_rb & 0xffffu, sums_ga & 0xffffu, sums_rb >> 16, sums_ga >> 16));
|
||||
}
|
||||
#endif /* PVRC_SUMS */
|
||||
if (g_tid == 0u && peels > 1u)
|
||||
atomicMax(bin.w[PVRC_B_STATS(pvrc_runs()) + PVRC_ST_PEELS], peels);
|
||||
if (g_tid == 0u && g_hiz_skipped != 0u)
|
||||
|
||||
@@ -28,10 +28,10 @@ static const int WalkUnsorted = PVRC_KERNELS + 1;
|
||||
* frame's every primitive (4 MiB) */
|
||||
static const u32 PoolEntries = 2u << 20;
|
||||
|
||||
// The bindings of the kernels' one set
|
||||
enum { B_FRAME, B_REC, B_BIN, B_OUT, B_LAST, B_PAL, B_TEX, B_VTX, B_IDX, B_MOD, B_CMD, B_TRD, B_DFRM, B_COUNT };
|
||||
// The bindings of the kernels' one set (B_SUMS: the HDR output's channel sums, pvr_compute.h's PVRC_SUMS)
|
||||
enum { B_FRAME, B_REC, B_BIN, B_OUT, B_LAST, B_PAL, B_TEX, B_VTX, B_IDX, B_MOD, B_CMD, B_TRD, B_DFRM, B_SUMS, B_COUNT };
|
||||
// (the buffers a frame of the GPU's TA decode is read from: B_VTX to B_DFRM)
|
||||
static const int GpuBindings = B_COUNT - B_VTX;
|
||||
static const int GpuBindings = B_SUMS - B_VTX;
|
||||
|
||||
// what PVRC_K_GPUSRC reads of the decode's buffers
|
||||
static_assert(PVRC_TAG_C_WORDS == TAG_C_WORDS && PVRC_TAG_C_COUNT == TAG_C_COUNT && PVRC_TAG_C_FIRST == TAG_C_FIRST
|
||||
@@ -110,8 +110,17 @@ struct ComputeDrawer::Resources
|
||||
vk::UniqueDescriptorSetLayout setLayout;
|
||||
vk::UniquePipelineLayout pipelineLayout;
|
||||
vk::UniquePipeline pipelines[PVRC_KERNELS + 2]; // (and the walk's unsorted variant last: WalkUnsorted)
|
||||
// with SSAA, the kernels for renders to a texture, at one sample a pixel
|
||||
/* with SSAA, the kernels for renders to a texture, at one sample a
|
||||
* pixel; with the HDR output, the walks for them (which store no sums:
|
||||
* the screen's do) - null where they are the screen's */
|
||||
vk::UniquePipeline rttPipelines[PVRC_KERNELS + 2];
|
||||
/* With the HDR output, each pixel's channel sums, which the screen's
|
||||
* walk stores (hdr_encode_vk.h: of HDR_VK_SUMS_SAMPLES); otherwise an
|
||||
* image of one pixel, for the binding */
|
||||
std::unique_ptr<FramebufferAttachment> sums;
|
||||
bool sumsOn = false;
|
||||
bool sumsLayout = false; // in the general layout
|
||||
bool sumsStored = false; // by the frame just recorded (and nothing over them since)
|
||||
vk::UniqueDescriptorPool descriptorPool;
|
||||
std::vector<vk::DescriptorSet> sets;
|
||||
// what each set's texture slots, picture and last picture have
|
||||
@@ -215,6 +224,17 @@ bool ComputeDrawer::Init(vk::Extent2D extent, u32 samples, CommandPool *pool, Sa
|
||||
return fail(e.what());
|
||||
}
|
||||
|
||||
/* (with the HDR output, the walk's channel sums: what was resolved,
|
||||
* SSAA's samples and the X scaler's pairs, has more than 8 bits) */
|
||||
r->sumsOn = context->HdrSumsReady();
|
||||
try {
|
||||
r->sums = std::unique_ptr<FramebufferAttachment>(new FramebufferAttachment(context->GetPhysicalDevice(), device));
|
||||
r->sums->Init(r->sumsOn ? extent.width : 1, r->sumsOn ? extent.height : 1, vk::Format::eR16G16B16A16Uint,
|
||||
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eSampled, false);
|
||||
} catch (const vk::SystemError& e) {
|
||||
return fail(e.what());
|
||||
}
|
||||
|
||||
vk::DescriptorSetLayoutBinding bindings[B_COUNT] = {
|
||||
{ B_FRAME, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute },
|
||||
{ B_REC, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute },
|
||||
@@ -229,6 +249,7 @@ bool ComputeDrawer::Init(vk::Extent2D extent, u32 samples, CommandPool *pool, Sa
|
||||
{ B_CMD, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute },
|
||||
{ B_TRD, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute },
|
||||
{ B_DFRM, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute },
|
||||
{ B_SUMS, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eCompute },
|
||||
};
|
||||
r->setLayout = device.createDescriptorSetLayoutUnique(vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), B_COUNT, bindings));
|
||||
r->pipelineLayout = device.createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &r->setLayout.get()));
|
||||
@@ -236,17 +257,22 @@ bool ComputeDrawer::Init(vk::Extent2D extent, u32 samples, CommandPool *pool, Sa
|
||||
/* every kernel, now, for this many samples, and for one when that is
|
||||
* not one (renders to a texture): none is made while a game runs. The
|
||||
* walk in its two variants (pvr_compute.h: PVRC_V_*), the one for the
|
||||
* tiles without sorted translucent fragments keeping none */
|
||||
for (int set = 0; set < (this->samples > 1 ? 2 : 1); set++)
|
||||
* tiles without sorted translucent fragments keeping none. (With the
|
||||
* HDR output, the screen's walks store the channel sums; at one sample
|
||||
* a pixel, renders to a texture have walks of their own, which do not.) */
|
||||
for (int set = 0; set < (this->samples > 1 || r->sumsOn ? 2 : 1); set++)
|
||||
{
|
||||
const u32 n = set == 0 ? this->samples : 1;
|
||||
for (int k = 1; k <= WalkUnsorted; k++)
|
||||
{
|
||||
const bool walk = k == PVRC_K_WALK || k == WalkUnsorted;
|
||||
const u32 spec[5] = { n, SSAA_LOG2(n), k == WalkUnsorted ? 1u : r->keep, 0,
|
||||
k == WalkUnsorted ? PVRC_V_UNSORTED : k == PVRC_K_WALK ? PVRC_V_SORTED : PVRC_V_ALL };
|
||||
const vk::SpecializationMapEntry entries[5] = { { 0, 0, 4 }, { 1, 4, 4 }, { 2, 8, 4 }, { 3, 12, 4 }, { 4, 16, 4 } };
|
||||
const vk::SpecializationInfo specInfo(5, entries, sizeof(spec), spec);
|
||||
if (set == 1 && this->samples <= 1 && !walk)
|
||||
continue;
|
||||
const u32 spec[6] = { n, SSAA_LOG2(n), k == WalkUnsorted ? 1u : r->keep, 0,
|
||||
k == WalkUnsorted ? PVRC_V_UNSORTED : k == PVRC_K_WALK ? PVRC_V_SORTED : PVRC_V_ALL,
|
||||
set == 0 && r->sumsOn ? 1u : 0u };
|
||||
const vk::SpecializationMapEntry entries[6] = { { 0, 0, 4 }, { 1, 4, 4 }, { 2, 8, 4 }, { 3, 12, 4 }, { 4, 16, 4 }, { 5, 20, 4 } };
|
||||
const vk::SpecializationInfo specInfo(6, entries, sizeof(spec), spec);
|
||||
// (the walk's textures taken in turns where the device cannot index them non-uniformly)
|
||||
const bool waterfall = walk && !context->SupportsNonUniformTextureIndexing();
|
||||
vk::UniqueShaderModule module = device.createShaderModuleUnique(vk::ShaderModuleCreateInfo(vk::ShaderModuleCreateFlags(),
|
||||
@@ -260,7 +286,7 @@ bool ComputeDrawer::Init(vk::Extent2D extent, u32 samples, CommandPool *pool, Sa
|
||||
|
||||
const vk::DescriptorPoolSize sizes[] = {
|
||||
{ vk::DescriptorType::eStorageBuffer, (3u + GpuBindings) * slots },
|
||||
{ vk::DescriptorType::eStorageImage, (u32)slots },
|
||||
{ vk::DescriptorType::eStorageImage, 2u * slots },
|
||||
{ vk::DescriptorType::eCombinedImageSampler, (PVRC_TEX_SLOTS + 2u) * slots },
|
||||
};
|
||||
r->descriptorPool = device.createDescriptorPoolUnique(vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlags(), slots, 3, sizes));
|
||||
@@ -281,6 +307,7 @@ bool ComputeDrawer::Init(vk::Extent2D extent, u32 samples, CommandPool *pool, Sa
|
||||
std::vector<vk::DescriptorBufferInfo> buffers;
|
||||
buffers.reserve((3 + GpuBindings) * slots);
|
||||
std::vector<vk::WriteDescriptorSet> writes;
|
||||
const vk::DescriptorImageInfo sumsInfo(vk::Sampler(), r->sums->GetImageView(), vk::ImageLayout::eGeneral);
|
||||
for (int s = 0; s < slots; s++)
|
||||
{
|
||||
buffers.push_back(vk::DescriptorBufferInfo(*r->ring->buffer, (vk::DeviceSize)s * r->ringWords * 4, (vk::DeviceSize)r->ringWords * 4));
|
||||
@@ -290,11 +317,12 @@ bool ComputeDrawer::Init(vk::Extent2D extent, u32 samples, CommandPool *pool, Sa
|
||||
buffers.push_back(vk::DescriptorBufferInfo(*r->bins->buffer, 0, VK_WHOLE_SIZE));
|
||||
writes.push_back(vk::WriteDescriptorSet(r->sets[s], B_BIN, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &buffers.back()));
|
||||
// (a frame of the parse's reads its vertices, indices and volumes from its own words; Prepare() changes them for the decode's)
|
||||
for (int b = B_VTX; b < B_COUNT; b++)
|
||||
for (int b = B_VTX; b < B_SUMS; b++)
|
||||
{
|
||||
buffers.push_back(vk::DescriptorBufferInfo(*r->ring->buffer, (vk::DeviceSize)s * r->ringWords * 4, (vk::DeviceSize)r->ringWords * 4));
|
||||
writes.push_back(vk::WriteDescriptorSet(r->sets[s], b, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &buffers.back()));
|
||||
}
|
||||
writes.push_back(vk::WriteDescriptorSet(r->sets[s], B_SUMS, 0, 1, vk::DescriptorType::eStorageImage, &sumsInfo));
|
||||
}
|
||||
{
|
||||
std::array<VkBuffer, GpuBindings> ring;
|
||||
@@ -335,6 +363,11 @@ void ComputeDrawer::Term()
|
||||
memset(statWhy, 0, sizeof(statWhy));
|
||||
}
|
||||
|
||||
vk::ImageView ComputeDrawer::Sums() const
|
||||
{
|
||||
return res && res->sumsStored ? res->sums->GetImageView() : vk::ImageView();
|
||||
}
|
||||
|
||||
bool ComputeDrawer::CanDraw() const
|
||||
{
|
||||
if (!ready || pvrrc.isRenderFramebuffer || (pvrrc.gpu && gpuDraw == nullptr))
|
||||
@@ -507,16 +540,26 @@ void ComputeDrawer::Record(vk::Image image, vk::ImageView view, vk::ImageView la
|
||||
* render pass, make them ready for fragment shaders, not these) */
|
||||
const vk::MemoryBarrier toCompute(vk::AccessFlagBits::eMemoryWrite,
|
||||
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eIndirectCommandRead);
|
||||
const vk::ImageMemoryBarrier toGeneral(vk::AccessFlags(), vk::AccessFlagBits::eShaderWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eGeneral,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, image, vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
|
||||
const vk::ImageMemoryBarrier toGeneral[2] = {
|
||||
vk::ImageMemoryBarrier(vk::AccessFlags(), vk::AccessFlagBits::eShaderWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eGeneral,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, image, vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)),
|
||||
// (the sums, the first time: general from then on)
|
||||
vk::ImageMemoryBarrier(vk::AccessFlags(), vk::AccessFlagBits::eShaderWrite, vk::ImageLayout::eUndefined, vk::ImageLayout::eGeneral,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, r.sums->GetImage(), vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)),
|
||||
};
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
|
||||
vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eDrawIndirect, vk::DependencyFlags(), toCompute, nullptr, toGeneral);
|
||||
vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eDrawIndirect, vk::DependencyFlags(), 1, &toCompute, 0, nullptr,
|
||||
r.sumsLayout ? 1 : 2, toGeneral);
|
||||
r.sumsLayout = true;
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, *r.pipelineLayout, 0, 1, &set, 0, nullptr);
|
||||
// (a render to a texture is drawn at one sample a pixel)
|
||||
const vk::UniquePipeline *pipelines = r.rtt && samples > 1 ? r.rttPipelines : r.pipelines;
|
||||
/* (a render to a texture is drawn at one sample a pixel, and stores no
|
||||
* sums: the kernels of its own, where there are) */
|
||||
auto pipeline = [&](int kernel) {
|
||||
return r.rtt && r.rttPipelines[kernel] ? *r.rttPipelines[kernel] : *r.pipelines[kernel];
|
||||
};
|
||||
const u32 n = r.rtt ? 1 : samples;
|
||||
auto step = [&](int kernel, u32 x, u32 y) {
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, *pipelines[kernel]);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline(kernel));
|
||||
if (x != 0 && y != 0)
|
||||
cmd.dispatch(x, y, 1);
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eDrawIndirect,
|
||||
@@ -530,7 +573,7 @@ void ComputeDrawer::Record(vk::Image image, vk::ImageView view, vk::ImageView la
|
||||
/* A frame of the decode's: its numbering, and the dispatches of
|
||||
* the kernels whose sizes are the GPU's, from it */
|
||||
auto indirect = [&](int kernel, u32 at) {
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, *pipelines[kernel]);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline(kernel));
|
||||
cmd.dispatchIndirect(bins, (vk::DeviceSize)(PVRC_B_STATS(r.runs) + at) * 4);
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eDrawIndirect,
|
||||
vk::DependencyFlags(), vk::MemoryBarrier(vk::AccessFlagBits::eShaderWrite,
|
||||
@@ -551,9 +594,9 @@ void ComputeDrawer::Record(vk::Image image, vk::ImageView view, vk::ImageView la
|
||||
}
|
||||
/* (the walk's two variants, each over the coarse tiles of its list,
|
||||
* the sort's: nothing between them) */
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, *pipelines[WalkUnsorted]);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline(WalkUnsorted));
|
||||
cmd.dispatchIndirect(bins, (vk::DeviceSize)(PVRC_B_STATS(r.runs) + PVRC_ST_WALK_U_X) * 4);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, *pipelines[PVRC_K_WALK]);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline(PVRC_K_WALK));
|
||||
cmd.dispatchIndirect(bins, (vk::DeviceSize)(PVRC_B_STATS(r.runs) + PVRC_ST_WALK_S_X) * 4);
|
||||
step(PVRC_K_WALK, 0, 0);
|
||||
/* the Y filter, in place over the picture, where the frame has it */
|
||||
@@ -561,10 +604,14 @@ void ComputeDrawer::Record(vk::Image image, vk::ImageView view, vk::ImageView la
|
||||
pvrc_yfilter_groups(words, &yx, &yy);
|
||||
if (yy != 0)
|
||||
{
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, *pipelines[PVRC_K_YFILTER]);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline(PVRC_K_YFILTER));
|
||||
cmd.dispatch(yx, yy, 1);
|
||||
}
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, *pipelines[PVRC_K_CLEAR]);
|
||||
/* (the sums are the picture's where it was written by the walk alone:
|
||||
* not where the write-out has been over it since; and what they add
|
||||
* is more than 8 bits, which a pixel of one sample does not have) */
|
||||
r.sumsStored = r.sumsOn && !r.rtt && yy == 0 && (n > 1 || (words[PVRC_F_FLAGS] & PVRC_FF_HSCALE) != 0);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline(PVRC_K_CLEAR));
|
||||
cmd.dispatchIndirect(bins, (vk::DeviceSize)(PVRC_B_STATS(r.runs) + PVRC_ST_CLEAR_X) * 4);
|
||||
// the counts, for when this slot comes round
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags(),
|
||||
|
||||
@@ -102,6 +102,10 @@ public:
|
||||
* null). Its own command buffer of the pool's, submitted with the
|
||||
* frame's others. */
|
||||
void Record(vk::Image image, vk::ImageView view, vk::ImageView last);
|
||||
/* With the HDR output, the channel sums of what the screen's frame just
|
||||
* recorded resolved, for the encode (VulkanContext::HdrEncode()); null
|
||||
* when it stored none, or they would add nothing */
|
||||
vk::ImageView Sums() const;
|
||||
|
||||
// a frame left to the raster renderer, and why (ComputeFrame::Why_*)
|
||||
void Fallback(u32 why) { statFallback++; statWhy[why < ComputeFrame::Why_Count ? why : 0]++; }
|
||||
|
||||
+7490
-7375
File diff suppressed because it is too large.
Load diff
@@ -959,7 +959,7 @@ void ScreenDrawer::Init(SamplerManager *samplerManager, ShaderManager *shaderMan
|
||||
dependencies.size(), dependencies.data()));
|
||||
}
|
||||
if (hdr && !hdrPipeline)
|
||||
hdrPipeline = GetContext()->HdrSubpassPipeline(*renderPass, samples > 1 ? 2 : 1);
|
||||
hdrPipeline = GetContext()->HdrSubpassPipeline(*renderPass, samples > 1 ? 2 : 1, samples);
|
||||
size_t size = VulkanContext::Instance()->GetSwapChainSize();
|
||||
if (colorAttachments.size() > size)
|
||||
{
|
||||
@@ -1117,7 +1117,8 @@ void ScreenDrawer::EndRenderPass()
|
||||
hdrAfter = writeOut.Runs(viewport.height);
|
||||
if (!hdrAfter)
|
||||
GetContext()->HdrSubpassDraw(*commandPool, currentCommandBuffer, *hdrPipeline,
|
||||
colorAttachments[GetCurrentImage()]->GetImageView(), viewport);
|
||||
colorAttachments[GetCurrentImage()]->GetImageView(),
|
||||
samples > 1 ? samplesAttachment->GetImageView() : vk::ImageView(), viewport);
|
||||
}
|
||||
else if (hdrPipeline)
|
||||
hdrAfter = true;
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#define B_FILM_LUT 10
|
||||
#define B_DESAT 11
|
||||
#define B_CUBE 12
|
||||
/* with SSAA, the samples the picture was resolved from (hdr_encode.frag) */
|
||||
#define B_SAMPLES 13
|
||||
|
||||
#define HOST_MEMORY (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
|
||||
|
||||
@@ -98,6 +100,9 @@ struct hdr_vk
|
||||
VkPipeline pipeline; /* the pass of its own's */
|
||||
VkShaderModule vert;
|
||||
VkShaderModule frag_subpass;
|
||||
VkShaderModule frag_subpass_ssaa;
|
||||
VkShaderModule frag_sums;
|
||||
VkPipeline pipeline_sums; /* the pass of its own's, with the channel sums (hdr_vk_sums_ready()) */
|
||||
VkDescriptorPool descriptor_pool;
|
||||
VkSampler nearest;
|
||||
VkSampler linear_clamp;
|
||||
@@ -472,7 +477,7 @@ static bool make_render_pass(hdr_vk_t *e)
|
||||
static bool make_layouts(hdr_vk_t *e)
|
||||
{
|
||||
static const uint32_t tables[] = { B_ACES2_LUT, B_FILM_LUT, B_DESAT, B_CUBE };
|
||||
VkDescriptorSetLayoutBinding b[6];
|
||||
VkDescriptorSetLayoutBinding b[7];
|
||||
VkDescriptorSetLayoutCreateInfo set;
|
||||
VkPushConstantRange push;
|
||||
VkPipelineLayoutCreateInfo layout;
|
||||
@@ -494,14 +499,16 @@ static bool make_layouts(hdr_vk_t *e)
|
||||
}
|
||||
b[5].binding = B_DT;
|
||||
b[5].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
for (i = 0; i < 6; i++)
|
||||
b[6].binding = B_SAMPLES;
|
||||
b[6].descriptorType = b[0].descriptorType;
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
b[i].descriptorCount = 1;
|
||||
b[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
}
|
||||
memset(&set, 0, sizeof(set));
|
||||
set.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
set.bindingCount = 6;
|
||||
set.bindingCount = 7;
|
||||
set.pBindings = b;
|
||||
if (vkCreateDescriptorSetLayout(e->device, &set, NULL, &e->set_layout[k]) != VK_SUCCESS)
|
||||
return false;
|
||||
@@ -532,7 +539,7 @@ static VkShaderModule make_module(VkDevice device, const uint32_t *code, size_t
|
||||
|
||||
/* The triangle over the picture into colour attachment 0 of @subpass */
|
||||
static VkPipeline make_pipeline(hdr_vk_t *e, VkShaderModule frag, VkPipelineLayout layout,
|
||||
VkRenderPass render_pass, uint32_t subpass)
|
||||
VkRenderPass render_pass, uint32_t subpass, const VkSpecializationInfo *spec)
|
||||
{
|
||||
static const VkDynamicState dynamic_states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
VkPipelineShaderStageCreateInfo stages[2];
|
||||
@@ -556,6 +563,7 @@ static VkPipeline make_pipeline(hdr_vk_t *e, VkShaderModule frag, VkPipelineLayo
|
||||
stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
stages[1].module = frag;
|
||||
stages[1].pName = "main";
|
||||
stages[1].pSpecializationInfo = spec;
|
||||
memset(&vertex, 0, sizeof(vertex));
|
||||
vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
memset(&assembly, 0, sizeof(assembly));
|
||||
@@ -613,9 +621,9 @@ static bool make_slots(hdr_vk_t *e)
|
||||
unsigned r, i;
|
||||
|
||||
sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
sizes[0].descriptorCount = sets * 9;
|
||||
sizes[0].descriptorCount = sets * 10;
|
||||
sizes[1].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
|
||||
sizes[1].descriptorCount = sets;
|
||||
sizes[1].descriptorCount = sets * 2;
|
||||
sizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
sizes[2].descriptorCount = sets * 2;
|
||||
memset(&pool, 0, sizeof(pool));
|
||||
@@ -672,12 +680,16 @@ hdr_vk_t *hdr_vk_new(const struct retro_hw_render_interface_vulkan *iface,
|
||||
e->linear_wrap = make_sampler(e->device, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT);
|
||||
e->vert = make_module(e->device, code->vert, code->vert_size);
|
||||
e->frag_subpass = make_module(e->device, code->frag_subpass, code->frag_subpass_size);
|
||||
e->frag_subpass_ssaa = make_module(e->device, code->frag_subpass_ssaa, code->frag_subpass_ssaa_size);
|
||||
e->frag_sums = make_module(e->device, code->frag_sums, code->frag_sums_size);
|
||||
frag = make_module(e->device, code->frag, code->frag_size);
|
||||
if ( e->nearest != VK_NULL_HANDLE && e->linear_clamp != VK_NULL_HANDLE
|
||||
&& e->linear_wrap != VK_NULL_HANDLE && e->vert != VK_NULL_HANDLE
|
||||
&& e->frag_subpass != VK_NULL_HANDLE && frag != VK_NULL_HANDLE
|
||||
&& e->frag_subpass != VK_NULL_HANDLE && e->frag_subpass_ssaa != VK_NULL_HANDLE
|
||||
&& e->frag_sums != VK_NULL_HANDLE
|
||||
&& frag != VK_NULL_HANDLE
|
||||
&& make_render_pass(e) && make_layouts(e))
|
||||
e->pipeline = make_pipeline(e, frag, e->pipeline_layout[K_SAMPLED], e->render_pass, 0);
|
||||
e->pipeline = make_pipeline(e, frag, e->pipeline_layout[K_SAMPLED], e->render_pass, 0, NULL);
|
||||
if (frag != VK_NULL_HANDLE)
|
||||
vkDestroyShaderModule(e->device, frag, NULL);
|
||||
if (e->pipeline == VK_NULL_HANDLE || !make_slots(e))
|
||||
@@ -707,6 +719,8 @@ void hdr_vk_free(hdr_vk_t *e)
|
||||
vkDestroyDescriptorPool(e->device, e->descriptor_pool, NULL);
|
||||
if (e->pipeline != VK_NULL_HANDLE)
|
||||
vkDestroyPipeline(e->device, e->pipeline, NULL);
|
||||
if (e->pipeline_sums != VK_NULL_HANDLE)
|
||||
vkDestroyPipeline(e->device, e->pipeline_sums, NULL);
|
||||
for (k = 0; k < K_COUNT; k++)
|
||||
{
|
||||
if (e->pipeline_layout[k] != VK_NULL_HANDLE)
|
||||
@@ -718,6 +732,10 @@ void hdr_vk_free(hdr_vk_t *e)
|
||||
vkDestroyShaderModule(e->device, e->vert, NULL);
|
||||
if (e->frag_subpass != VK_NULL_HANDLE)
|
||||
vkDestroyShaderModule(e->device, e->frag_subpass, NULL);
|
||||
if (e->frag_subpass_ssaa != VK_NULL_HANDLE)
|
||||
vkDestroyShaderModule(e->device, e->frag_subpass_ssaa, NULL);
|
||||
if (e->frag_sums != VK_NULL_HANDLE)
|
||||
vkDestroyShaderModule(e->device, e->frag_sums, NULL);
|
||||
if (e->render_pass != VK_NULL_HANDLE)
|
||||
vkDestroyRenderPass(e->device, e->render_pass, NULL);
|
||||
if (e->nearest != VK_NULL_HANDLE)
|
||||
@@ -765,13 +783,15 @@ void hdr_vk_prepare(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer c
|
||||
block->gm[2] = 0.0f;
|
||||
}
|
||||
|
||||
/* @samples (or SSAA's sums), in @samples_layout */
|
||||
static void write_set(hdr_vk_t *e, hdr_vk_slot_t *s, VkDescriptorSet set,
|
||||
VkDescriptorType picture_type, VkImageView picture)
|
||||
VkDescriptorType picture_type, VkImageView picture, VkImageView samples,
|
||||
VkImageLayout samples_layout)
|
||||
{
|
||||
VkDescriptorImageInfo images[5];
|
||||
VkDescriptorImageInfo images[6];
|
||||
VkDescriptorBufferInfo dt;
|
||||
VkWriteDescriptorSet w[6];
|
||||
static const uint32_t bindings[5] = { B_PICTURE, B_ACES2_LUT, B_FILM_LUT, B_DESAT, B_CUBE };
|
||||
VkWriteDescriptorSet w[7];
|
||||
static const uint32_t bindings[6] = { B_PICTURE, B_ACES2_LUT, B_FILM_LUT, B_DESAT, B_CUBE, B_SAMPLES };
|
||||
unsigned i;
|
||||
|
||||
images[0].sampler = picture_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT ? VK_NULL_HANDLE : e->nearest;
|
||||
@@ -784,27 +804,32 @@ static void write_set(hdr_vk_t *e, hdr_vk_slot_t *s, VkDescriptorSet set,
|
||||
images[3].imageView = table_view(e, T_DESAT);
|
||||
images[4].sampler = e->linear_clamp;
|
||||
images[4].imageView = table_view(e, T_CUBE);
|
||||
/* (the picture where there are no samples: there for the layout, unread) */
|
||||
images[5].sampler = images[0].sampler;
|
||||
images[5].imageView = samples != VK_NULL_HANDLE ? samples : picture;
|
||||
images[5].imageLayout = samples != VK_NULL_HANDLE ? samples_layout : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
dt.buffer = s->dt.buffer;
|
||||
dt.offset = 0;
|
||||
dt.range = sizeof(struct hdr_dt_block);
|
||||
memset(w, 0, sizeof(w));
|
||||
for (i = 0; i < 5; i++)
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
if (i < 5)
|
||||
images[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
w[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
w[i].dstSet = set;
|
||||
w[i].dstBinding = bindings[i];
|
||||
w[i].descriptorCount = 1;
|
||||
w[i].descriptorType = i == 0 ? picture_type : VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
w[i].descriptorType = (i == 0 || i == 5) ? picture_type : VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
w[i].pImageInfo = &images[i];
|
||||
}
|
||||
w[5].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
w[5].dstSet = set;
|
||||
w[5].dstBinding = B_DT;
|
||||
w[5].descriptorCount = 1;
|
||||
w[5].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
w[5].pBufferInfo = &dt;
|
||||
vkUpdateDescriptorSets(e->device, 6, w, 0, NULL);
|
||||
w[6].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
w[6].dstSet = set;
|
||||
w[6].dstBinding = B_DT;
|
||||
w[6].descriptorCount = 1;
|
||||
w[6].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
w[6].pBufferInfo = &dt;
|
||||
vkUpdateDescriptorSets(e->device, 7, w, 0, NULL);
|
||||
}
|
||||
|
||||
/* The triangle, with what it reads bound: in a subpass or a pass of its own */
|
||||
@@ -834,28 +859,74 @@ static void draw(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer cmd,
|
||||
vkCmdDraw(cmd, 3, 1, 0, 0);
|
||||
}
|
||||
|
||||
VkPipeline hdr_vk_subpass_pipeline(hdr_vk_t *e, VkRenderPass render_pass, uint32_t subpass)
|
||||
static unsigned samples_log2(unsigned samples)
|
||||
{
|
||||
return make_pipeline(e, e->frag_subpass, e->pipeline_layout[K_SUBPASS], render_pass, subpass);
|
||||
unsigned k = 0;
|
||||
while ((2u << k) <= samples)
|
||||
k++;
|
||||
return k;
|
||||
}
|
||||
|
||||
/* A pipeline of SSAA's, its constants @samples (pso_key.h's
|
||||
* PSO_SC_SSAA_SAMPLES and PSO_SC_SSAA_LOG2N) */
|
||||
static VkPipeline make_ssaa_pipeline(hdr_vk_t *e, VkShaderModule frag, VkPipelineLayout layout,
|
||||
VkRenderPass render_pass, uint32_t subpass, unsigned samples)
|
||||
{
|
||||
VkSpecializationMapEntry entries[2];
|
||||
VkSpecializationInfo spec;
|
||||
int32_t values[2];
|
||||
values[0] = (int32_t)samples;
|
||||
values[1] = (int32_t)samples_log2(samples);
|
||||
entries[0].constantID = 1;
|
||||
entries[0].offset = 0;
|
||||
entries[0].size = sizeof(int32_t);
|
||||
entries[1].constantID = 2;
|
||||
entries[1].offset = sizeof(int32_t);
|
||||
entries[1].size = sizeof(int32_t);
|
||||
spec.mapEntryCount = 2;
|
||||
spec.pMapEntries = entries;
|
||||
spec.dataSize = sizeof(values);
|
||||
spec.pData = values;
|
||||
return make_pipeline(e, frag, layout, render_pass, subpass, &spec);
|
||||
}
|
||||
|
||||
VkPipeline hdr_vk_subpass_pipeline(hdr_vk_t *e, VkRenderPass render_pass, uint32_t subpass,
|
||||
unsigned samples)
|
||||
{
|
||||
if (samples <= 1)
|
||||
return make_pipeline(e, e->frag_subpass, e->pipeline_layout[K_SUBPASS], render_pass, subpass, NULL);
|
||||
return make_ssaa_pipeline(e, e->frag_subpass_ssaa, e->pipeline_layout[K_SUBPASS], render_pass, subpass, samples);
|
||||
}
|
||||
|
||||
bool hdr_vk_sums_ready(hdr_vk_t *e)
|
||||
{
|
||||
/* (the sums are of HDR_VK_SUMS_SAMPLES, whatever was drawn) */
|
||||
if (e->pipeline_sums == VK_NULL_HANDLE)
|
||||
e->pipeline_sums = make_ssaa_pipeline(e, e->frag_sums, e->pipeline_layout[K_SAMPLED],
|
||||
e->render_pass, 0, HDR_VK_SUMS_SAMPLES);
|
||||
return e->pipeline_sums != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void hdr_vk_subpass_draw(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer cmd,
|
||||
unsigned ring, unsigned slot, VkPipeline pipeline, VkImageView view,
|
||||
unsigned width, unsigned height, bool unorm8)
|
||||
VkImageView samples, unsigned width, unsigned height, bool unorm8)
|
||||
{
|
||||
hdr_vk_slot_t *s = slot_of(e, ring, slot);
|
||||
if (!s || pipeline == VK_NULL_HANDLE)
|
||||
return;
|
||||
write_set(e, s, s->set_subpass, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, view);
|
||||
write_set(e, s, s->set_subpass, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, view, samples,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
draw(e, out, cmd, pipeline, e->pipeline_layout[K_SUBPASS], s->set_subpass, width, height, unorm8);
|
||||
}
|
||||
|
||||
bool hdr_vk_encode(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer cmd,
|
||||
unsigned ring, unsigned slot, uint64_t epoch, unsigned index,
|
||||
VkImage *image, VkImageView *view, unsigned width, unsigned height, bool unorm8)
|
||||
VkImage *image, VkImageView *view, unsigned width, unsigned height, bool unorm8,
|
||||
VkImageView sums)
|
||||
{
|
||||
hdr_vk_slot_t *s = slot_of(e, ring, slot);
|
||||
hdr_vk_image_t *o;
|
||||
VkPipeline pipeline = e->pipeline;
|
||||
VkMemoryBarrier barrier;
|
||||
VkRenderPassBeginInfo rp;
|
||||
|
||||
@@ -871,7 +942,17 @@ bool hdr_vk_encode(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer cm
|
||||
image_destroy(e, o);
|
||||
return false;
|
||||
}
|
||||
write_set(e, s, s->set_sampled, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, *view);
|
||||
/* (the pipeline for the sums made before the frames, by the renderer:
|
||||
* hdr_vk_sums_ready(); none here, the picture alone) */
|
||||
if (sums != VK_NULL_HANDLE && e->pipeline_sums != VK_NULL_HANDLE)
|
||||
{
|
||||
pipeline = e->pipeline_sums;
|
||||
unorm8 = false;
|
||||
}
|
||||
else
|
||||
sums = VK_NULL_HANDLE;
|
||||
write_set(e, s, s->set_sampled, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, *view, sums,
|
||||
VK_IMAGE_LAYOUT_GENERAL);
|
||||
|
||||
/* what drew the picture, earlier in the frame, before it is read; what
|
||||
* read the output last, before it is written again */
|
||||
@@ -892,7 +973,7 @@ bool hdr_vk_encode(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer cm
|
||||
rp.renderArea.extent.width = width;
|
||||
rp.renderArea.extent.height = height;
|
||||
vkCmdBeginRenderPass(cmd, &rp, VK_SUBPASS_CONTENTS_INLINE);
|
||||
draw(e, out, cmd, e->pipeline, e->pipeline_layout[K_SAMPLED], s->set_sampled, width, height, unorm8);
|
||||
draw(e, out, cmd, pipeline, e->pipeline_layout[K_SAMPLED], s->set_sampled, width, height, unorm8);
|
||||
vkCmdEndRenderPass(cmd);
|
||||
|
||||
*image = o->image;
|
||||
|
||||
@@ -35,7 +35,9 @@ struct hdr_output;
|
||||
typedef struct hdr_vk hdr_vk_t;
|
||||
|
||||
/* The shaders' SPIR-V: SSAA_RESOLVE_VERT's triangle, HDR_ENCODE_FRAG
|
||||
* (the picture sampled) and HDR_ENCODE_FRAG_SUBPASS (an input attachment) */
|
||||
* (the picture sampled), HDR_ENCODE_FRAG_SUBPASS (an input attachment),
|
||||
* HDR_ENCODE_FRAG_SUBPASS_SSAA (and SSAA's samples, a second one) and
|
||||
* HDR_ENCODE_FRAG_SUMS (the picture sampled, and SSAA's channel sums) */
|
||||
typedef struct hdr_vk_code
|
||||
{
|
||||
const uint32_t *vert;
|
||||
@@ -44,6 +46,10 @@ typedef struct hdr_vk_code
|
||||
size_t frag_size;
|
||||
const uint32_t *frag_subpass;
|
||||
size_t frag_subpass_size;
|
||||
const uint32_t *frag_subpass_ssaa;
|
||||
size_t frag_subpass_ssaa_size;
|
||||
const uint32_t *frag_sums;
|
||||
size_t frag_sums_size;
|
||||
} hdr_vk_code_t;
|
||||
|
||||
/* @format: what is handed over, VK_FORMAT_A2B10G10R10_UNORM_PACK32 for
|
||||
@@ -71,27 +77,49 @@ void hdr_vk_prepare(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer c
|
||||
|
||||
/* A pipeline for subpass @subpass of @render_pass (and those compatible
|
||||
* with it), which reads the picture as its input attachment 0 and writes
|
||||
* colour attachment 0; the caller's to destroy. VK_NULL_HANDLE when it
|
||||
* colour attachment 0; with @samples above 1, SSAA's samples the picture
|
||||
* was resolved from (rend/tile/pvr_resolve.h's rule) are its input
|
||||
* attachment 1, and where the picture is their resolve their exact
|
||||
* average is encoded. The caller's to destroy. VK_NULL_HANDLE when it
|
||||
* could not be made. */
|
||||
VkPipeline hdr_vk_subpass_pipeline(hdr_vk_t *e, VkRenderPass render_pass, uint32_t subpass);
|
||||
VkPipeline hdr_vk_subpass_pipeline(hdr_vk_t *e, VkRenderPass render_pass, uint32_t subpass,
|
||||
unsigned samples);
|
||||
|
||||
/* Draws it, in that subpass, over @width x @height: the picture is @view,
|
||||
* 8 bits a channel when @unorm8. After hdr_vk_prepare() for the same ring
|
||||
* and slot. */
|
||||
/* Draws it, in that subpass, over @width x @height: the picture is @view
|
||||
* (and the samples @samples, for a pipeline made for them), 8 bits a
|
||||
* channel when @unorm8 (and dithered then). After hdr_vk_prepare() for the
|
||||
* same ring and slot. */
|
||||
void hdr_vk_subpass_draw(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer cmd,
|
||||
unsigned ring, unsigned slot, VkPipeline pipeline, VkImageView view,
|
||||
unsigned width, unsigned height, bool unorm8);
|
||||
VkImageView samples, unsigned width, unsigned height, bool unorm8);
|
||||
|
||||
/* ---- a pass of its own ---- */
|
||||
|
||||
/* What hdr_vk_encode()'s channel sums are of: whatever the samples a
|
||||
* pixel that were resolved (SSAA's, and the X scaler's pair of pixels'),
|
||||
* N of them, a sum is (2^HDR_VK_SUMS_LOG2 / N) times the samples' */
|
||||
#define HDR_VK_SUMS_LOG2 4
|
||||
#define HDR_VK_SUMS_SAMPLES (1 << HDR_VK_SUMS_LOG2)
|
||||
|
||||
/* The pipeline hdr_vk_encode() takes the channel sums with, made now:
|
||||
* before the frames, by a renderer that will hand them over. False when
|
||||
* it could not be. */
|
||||
bool hdr_vk_sums_ready(hdr_vk_t *e);
|
||||
|
||||
/* The picture (@image, @view, in the shader-read layout, 8 bits a channel
|
||||
* when @unorm8), @width x @height, encoded into @cmd, outside a render
|
||||
* pass, into the image for the frontend's frame @index; @image and @view
|
||||
* become that image's, in the same layout. Prepares the frame itself.
|
||||
* False, both as they were, when it could not be. */
|
||||
* With @sums (an R16G16B16A16_UINT image in the general layout: for each
|
||||
* pixel the channel sums of the samples the picture was resolved from by
|
||||
* rend/tile/pvr_resolve.h's rule, scaled to HDR_VK_SUMS_SAMPLES) and
|
||||
* hdr_vk_sums_ready(), their exact average is encoded where the picture
|
||||
* is their resolve, as hdr_vk_subpass_pipeline()'s does. False, both as
|
||||
* they were, when it could not be. */
|
||||
bool hdr_vk_encode(hdr_vk_t *e, const struct hdr_output *out, VkCommandBuffer cmd,
|
||||
unsigned ring, unsigned slot, uint64_t epoch, unsigned index,
|
||||
VkImage *image, VkImageView *view, unsigned width, unsigned height, bool unorm8);
|
||||
VkImage *image, VkImageView *view, unsigned width, unsigned height, bool unorm8,
|
||||
VkImageView sums);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -60,6 +60,19 @@ public:
|
||||
plannedSize = 0;
|
||||
}
|
||||
|
||||
/* With SSAA and the HDR output: an image of each pixel's channel sums,
|
||||
* which the screen's last pass stores (OIT_FINAL_FRAG_S1_SUMS) for the
|
||||
* encode to take the exact average from (VulkanContext::HdrEncode()).
|
||||
* Before the renderer is set up, like SetCompact(), or made again for
|
||||
* a size; made at the next Init(). */
|
||||
void SetSums(bool on)
|
||||
{
|
||||
sums = on;
|
||||
}
|
||||
bool Sums() const { return sums; }
|
||||
// (null without)
|
||||
vk::ImageView GetSumsView() const { return sumsAttachment ? sumsAttachment->GetImageView() : vk::ImageView(); }
|
||||
|
||||
/* The screen's size: the fragment buffer is made for it, at the next
|
||||
* Init(). Renders to a texture larger than the screen are drawn in
|
||||
* more bands rather than the buffer made again while a game runs. */
|
||||
@@ -78,6 +91,8 @@ public:
|
||||
{ 0, vk::DescriptorType::eStorageBuffer, Bindings, vk::ShaderStageFlagBits::eFragment }, // pixel buffer
|
||||
{ 1, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eFragment }, // pixel counter
|
||||
{ 2, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment }, // a-buffer pointers
|
||||
// (SSAA's channel sums, for the HDR output: written only with SetSums(), read by its shader alone)
|
||||
{ 3, vk::DescriptorType::eStorageImage, 1, vk::ShaderStageFlagBits::eFragment },
|
||||
};
|
||||
|
||||
descSetLayout = context->GetDevice().createDescriptorSetLayoutUnique(
|
||||
@@ -100,7 +115,7 @@ public:
|
||||
counts = std::unique_ptr<BufferData>(new BufferData(CountSlots * Counts * sizeof(u32), vk::BufferUsageFlagBits::eTransferDst));
|
||||
std::fill(std::begin(written), std::end(written), 0);
|
||||
}
|
||||
if (width > maxWidth || height > maxHeight || !abufferPointerAttachment)
|
||||
if (width > maxWidth || height > maxHeight || !abufferPointerAttachment || sums != (sumsAttachment != nullptr))
|
||||
{
|
||||
maxWidth = std::max(maxWidth, width);
|
||||
maxHeight = std::max(maxHeight, height);
|
||||
@@ -120,6 +135,15 @@ public:
|
||||
abufferPointerAttachment->Init(maxWidth, maxHeight, vk::Format::eR32Uint,
|
||||
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst);
|
||||
abufferPointerTransitionNeeded = true;
|
||||
if (sumsAttachment)
|
||||
commandPool->DeferDelete(std::move(sumsAttachment));
|
||||
if (sums)
|
||||
{
|
||||
sumsAttachment = std::unique_ptr<FramebufferAttachment>(
|
||||
new FramebufferAttachment(context->GetPhysicalDevice(), context->GetDevice()));
|
||||
sumsAttachment->Init(maxWidth, maxHeight, vk::Format::eR16G16B16A16Uint,
|
||||
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eSampled, false);
|
||||
}
|
||||
firstFrameAfterInit = true;
|
||||
remake = true;
|
||||
}
|
||||
@@ -140,6 +164,9 @@ public:
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*descSet, 1, 0, 1, vk::DescriptorType::eStorageBuffer, nullptr, &pixelCounterBufferInfo, nullptr));
|
||||
vk::DescriptorImageInfo pointerImageInfo(vk::Sampler(), abufferPointerAttachment->GetImageView(), vk::ImageLayout::eGeneral);
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*descSet, 2, 0, 1, vk::DescriptorType::eStorageImage, &pointerImageInfo, nullptr, nullptr));
|
||||
vk::DescriptorImageInfo sumsImageInfo(vk::Sampler(), sumsAttachment ? sumsAttachment->GetImageView() : vk::ImageView(), vk::ImageLayout::eGeneral);
|
||||
if (sumsAttachment)
|
||||
writeDescriptorSets.push_back(vk::WriteDescriptorSet(*descSet, 3, 0, 1, vk::DescriptorType::eStorageImage, &sumsImageInfo, nullptr, nullptr));
|
||||
context->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr);
|
||||
}
|
||||
|
||||
@@ -150,6 +177,18 @@ public:
|
||||
|
||||
void OnNewFrame(vk::CommandBuffer commandBuffer)
|
||||
{
|
||||
if (sumsAttachment)
|
||||
{
|
||||
/* The sums: in the general layout from the first; after that,
|
||||
* the frame before's encode done reading them before this
|
||||
* frame's last pass stores them again */
|
||||
vk::ImageSubresourceRange range(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1);
|
||||
vk::ImageMemoryBarrier barrier(vk::AccessFlags(), vk::AccessFlagBits::eShaderWrite,
|
||||
abufferPointerTransitionNeeded ? vk::ImageLayout::eUndefined : vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral,
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, sumsAttachment->GetImage(), range);
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader, vk::PipelineStageFlagBits::eFragmentShader, {}, nullptr, nullptr,
|
||||
barrier);
|
||||
}
|
||||
if (abufferPointerTransitionNeeded)
|
||||
{
|
||||
abufferPointerTransitionNeeded = false;
|
||||
@@ -262,6 +301,7 @@ public:
|
||||
pixelCounterReset.reset();
|
||||
counts.reset();
|
||||
abufferPointerAttachment.reset();
|
||||
sumsAttachment.reset();
|
||||
descSet.reset();
|
||||
maxWidth = maxHeight = 0;
|
||||
}
|
||||
@@ -322,6 +362,8 @@ private:
|
||||
std::unique_ptr<BufferData> pixelCounter;
|
||||
std::unique_ptr<BufferData> pixelCounterReset;
|
||||
std::unique_ptr<FramebufferAttachment> abufferPointerAttachment;
|
||||
std::unique_ptr<FramebufferAttachment> sumsAttachment;
|
||||
bool sums = false;
|
||||
bool abufferPointerTransitionNeeded = false;
|
||||
bool firstFrameAfterInit = false;
|
||||
int maxWidth = 0;
|
||||
|
||||
@@ -585,7 +585,7 @@ bool OITDrawer::Draw(const Texture *fogTexture, const Texture *paletteTexture)
|
||||
if (finalPass)
|
||||
{
|
||||
cmdBuffer.setViewport(0, vk::Viewport(0.f, 0.f, (float)viewport.extent.width, (float)viewport.extent.height, 0.f, 1.f));
|
||||
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipelineManager->GetFinalPipeline());
|
||||
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipelineManager->GetFinalPipeline(false, true));
|
||||
quadBuffer->Draw(cmdBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
// SSAA's channel sums, when the buffers have them (OITBuffers::SetSums())
|
||||
vk::ImageView GetSumsView() const { return oitBuffers->GetSumsView(); }
|
||||
void Init(SamplerManager *samplerManager, OITPipelineManager *pipelineManager, OITBuffers *oitBuffers)
|
||||
{
|
||||
this->pipelineManager = pipelineManager;
|
||||
@@ -223,7 +225,9 @@ public:
|
||||
timer.End(currentCommandBuffer, commandPool->GetIndex());
|
||||
currentCommandBuffer.end();
|
||||
currentCommandBuffer = nullptr;
|
||||
Present();
|
||||
/* (with SSAA, the samples' channel sums the last pass stored, when
|
||||
* it did: no write-out pass came after it) */
|
||||
Present(screenPipelineManager->Sums() && !writeOut.Runs(viewport.extent.height) ? GetSumsView() : vk::ImageView());
|
||||
}
|
||||
vk::RenderPass GetRenderPass() const { return screenPipelineManager->GetRenderPass(false, true); }
|
||||
/* The chip's write-out (../writeout.h), when the frame has one: the
|
||||
@@ -314,24 +318,25 @@ public:
|
||||
t.last = scaled ? restoredPicture : finalColorAttachments[(GetCurrentImage() + count - 1) % count]->GetImageView();
|
||||
return t;
|
||||
}
|
||||
// ...and once it is recorded, as EndFrame() ends one of this drawer's
|
||||
void ComputeEnd()
|
||||
// ...and once it is recorded, as EndFrame() ends one of this drawer's (@sums: ComputeDrawer::Sums())
|
||||
void ComputeEnd(vk::ImageView sums)
|
||||
{
|
||||
havePicture = true;
|
||||
restoredPicture = nullptr;
|
||||
if (carriedPicture)
|
||||
commandPool->DeferDelete(std::move(carriedPicture));
|
||||
Present();
|
||||
Present(sums);
|
||||
}
|
||||
protected:
|
||||
/* The frame submitted and its picture handed over: with the HDR output,
|
||||
* the picture encoded first, in the same submission (VulkanContext::HdrEncode()) */
|
||||
void Present()
|
||||
* the picture encoded first, in the same submission (VulkanContext::HdrEncode()),
|
||||
* from the channel sums @sums where there are */
|
||||
void Present(vk::ImageView sums)
|
||||
{
|
||||
vk::Image image = finalColorAttachments[GetCurrentImage()]->GetImage();
|
||||
vk::ImageView view = finalColorAttachments[GetCurrentImage()]->GetImageView();
|
||||
const bool hdr = GetContext()->HdrEncode(*commandPool, image, view,
|
||||
vk::Extent2D(viewport.extent.width, viewport.extent.height));
|
||||
vk::Extent2D(viewport.extent.width, viewport.extent.height), sums);
|
||||
commandPool->EndFrame();
|
||||
GetContext()->PresentFrame(image, view, vk::Offset2D(viewport.extent.width, viewport.extent.height), hdr);
|
||||
}
|
||||
|
||||
@@ -250,6 +250,8 @@ void OITPipelineManager::Prepare()
|
||||
{
|
||||
if (i == FIXED_FINAL_PER_SAMPLE && samples <= 1)
|
||||
continue;
|
||||
if (i == FIXED_FINAL_SUMS && !sums)
|
||||
continue;
|
||||
PsoSlot& slot = fixedSlots[i];
|
||||
slot.key = ((u64)KIND_FIXED << KEY_KIND) | i;
|
||||
slot.owner = this;
|
||||
@@ -288,8 +290,8 @@ VkPipeline OITPipelineManager::BuildPipeline(u64 key, vk::PipelineCache cache)
|
||||
return CreateModVolPipeline((ModVolMode)(i / 3), culls[i % 3], cache);
|
||||
if (i < FIXED_FINAL)
|
||||
return CreateTrModVolPipeline((ModVolMode)((i - FIXED_TRMODVOL) / 3), culls[(i - FIXED_TRMODVOL) % 3], cache);
|
||||
if (i == FIXED_FINAL || i == FIXED_FINAL_PER_SAMPLE)
|
||||
return CreateFinalPipeline(i == FIXED_FINAL_PER_SAMPLE, cache);
|
||||
if (i == FIXED_FINAL || i == FIXED_FINAL_PER_SAMPLE || i == FIXED_FINAL_SUMS)
|
||||
return CreateFinalPipeline(i == FIXED_FINAL_PER_SAMPLE, i == FIXED_FINAL_SUMS, cache);
|
||||
if (i == FIXED_CLEAR)
|
||||
return CreateClearPipeline(cache);
|
||||
return VK_NULL_HANDLE;
|
||||
@@ -450,7 +452,7 @@ VkPipeline OITPipelineManager::BuildPoly(u64 key, bool general, vk::PipelineCach
|
||||
return PsoCreate(GetContext()->GetDevice(), cache, graphicsPipelineCreateInfo);
|
||||
}
|
||||
|
||||
VkPipeline OITPipelineManager::CreateFinalPipeline(bool perSample, vk::PipelineCache cache)
|
||||
VkPipeline OITPipelineManager::CreateFinalPipeline(bool perSample, bool sums, vk::PipelineCache cache)
|
||||
{
|
||||
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetQuadInputStateCreateInfo(false);
|
||||
|
||||
@@ -509,7 +511,7 @@ VkPipeline OITPipelineManager::CreateFinalPipeline(bool perSample, vk::PipelineC
|
||||
vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), 2, dynamicStates);
|
||||
|
||||
vk::ShaderModule vertex_module = shaderManager->GetFinalVertexShader();
|
||||
vk::ShaderModule fragment_module = shaderManager->GetFinalShader(perSample);
|
||||
vk::ShaderModule fragment_module = shaderManager->GetFinalShader(perSample, sums);
|
||||
const PsoSpecialization specialization(0, renderPasses->GetSamples());
|
||||
|
||||
vk::PipelineShaderStageCreateInfo stages[] = {
|
||||
|
||||
@@ -280,6 +280,11 @@ public:
|
||||
Reset();
|
||||
renderPasses->SetSamples(samples);
|
||||
}
|
||||
if ((samples > 1 && oitBuffers->Sums()) != sums)
|
||||
{
|
||||
Reset();
|
||||
sums = samples > 1 && oitBuffers->Sums();
|
||||
}
|
||||
renderPasses->MakeAll();
|
||||
|
||||
if (!perFrameLayout)
|
||||
@@ -338,11 +343,15 @@ public:
|
||||
{
|
||||
return vk::Pipeline(fixedSlots[FIXED_TRMODVOL + ModVolIndex(mode, cullMode)].pipeline);
|
||||
}
|
||||
// @perSample: SSAA's for a render pass that is not the last (OITShaderManager::GetFinalShader())
|
||||
vk::Pipeline GetFinalPipeline(bool perSample = false) const
|
||||
/* @perSample: SSAA's for a render pass that is not the last; @sums: the
|
||||
* last one's, which also stores the channel sums, when there is one
|
||||
* (OITShaderManager::GetFinalShader(), Sums()) */
|
||||
vk::Pipeline GetFinalPipeline(bool perSample = false, bool sums = false) const
|
||||
{
|
||||
return vk::Pipeline(fixedSlots[perSample ? FIXED_FINAL_PER_SAMPLE : FIXED_FINAL].pipeline);
|
||||
return vk::Pipeline(fixedSlots[perSample ? FIXED_FINAL_PER_SAMPLE : sums && this->sums ? FIXED_FINAL_SUMS : FIXED_FINAL].pipeline);
|
||||
}
|
||||
// the last pass stores SSAA's channel sums (OITBuffers::SetSums(), with samples)
|
||||
bool Sums() const { return sums; }
|
||||
int GetFinalSubpass() const { return renderPasses->GetFinalSubpass(); }
|
||||
u32 GetSamples() const { return renderPasses->GetSamples(); }
|
||||
vk::Pipeline GetClearPipeline() const
|
||||
@@ -402,11 +411,11 @@ private:
|
||||
VkPipeline BuildPoly(u64 key, bool general, vk::PipelineCache cache);
|
||||
VkPipeline CreateModVolPipeline(ModVolMode mode, int cullMode, vk::PipelineCache cache);
|
||||
VkPipeline CreateTrModVolPipeline(ModVolMode mode, int cullMode, vk::PipelineCache cache);
|
||||
VkPipeline CreateFinalPipeline(bool perSample, vk::PipelineCache cache);
|
||||
VkPipeline CreateFinalPipeline(bool perSample, bool sums, vk::PipelineCache cache);
|
||||
VkPipeline CreateClearPipeline(vk::PipelineCache cache);
|
||||
|
||||
// the fixed pipelines' slots: the modifier volumes' by mode and cull mode, the last subpass's, the lists'
|
||||
enum { FIXED_MODVOL = 0, FIXED_TRMODVOL = 12, FIXED_FINAL = 24, FIXED_FINAL_PER_SAMPLE, FIXED_CLEAR, FIXED_COUNT };
|
||||
enum { FIXED_MODVOL = 0, FIXED_TRMODVOL = 12, FIXED_FINAL = 24, FIXED_FINAL_PER_SAMPLE, FIXED_CLEAR, FIXED_FINAL_SUMS, FIXED_COUNT };
|
||||
// (Xor to Exclusion; cull modes 0 and 1 are both none)
|
||||
static u32 ModVolIndex(ModVolMode mode, int cullMode) { return (u32)mode * 3 + (cullMode < 2 ? 0 : cullMode - 1); }
|
||||
|
||||
@@ -442,6 +451,7 @@ private:
|
||||
PsoTable pipelines; // the polygons' own
|
||||
PsoTable general; // the general ones
|
||||
PsoSlot fixedSlots[FIXED_COUNT] = {};
|
||||
bool sums = false;
|
||||
bool prepared = false;
|
||||
// what the pipelines are made for (one of a kind: all of them work with any)
|
||||
vk::RenderPass renderPass;
|
||||
|
||||
@@ -36,8 +36,11 @@ public:
|
||||
DEBUG_LOG(RENDERER, "OITVulkanRenderer::Init");
|
||||
|
||||
oitBuffers.SetCompact(rend_compute_wanted && ComputeDrawer::DeviceLacks() == nullptr);
|
||||
oitBuffers.Init(0, 0, &texCommandPool);
|
||||
samples = SsaaSamples();
|
||||
/* (with SSAA and the HDR output, the last pass's channel sums, for
|
||||
* the encode: OITBuffers::SetSums()) */
|
||||
oitBuffers.SetSums(samples > 1 && GetContext()->HdrSumsReady());
|
||||
oitBuffers.Init(0, 0, &texCommandPool);
|
||||
oitShaderManager.SetSamples(samples);
|
||||
NOTICE_LOG(RENDERER, "Vulkan per-pixel renderer: with SSAA, a translucent fragment takes the samples %s",
|
||||
GetContext()->postDepthCoverage ? "the depth test passed (VK_EXT_post_depth_coverage)" : "its own depth test passes, at each sample");
|
||||
@@ -72,6 +75,7 @@ public:
|
||||
oitBuffers.SetCompact(rend_compute_wanted && ComputeDrawer::DeviceLacks() == nullptr);
|
||||
const u32 was = samples;
|
||||
samples = SsaaSamples();
|
||||
oitBuffers.SetSums(samples > 1 && GetContext()->HdrSumsReady());
|
||||
if (samples != was)
|
||||
{
|
||||
// (a change of SSAA: the shaders, render passes and pipelines of the other count go)
|
||||
@@ -166,7 +170,7 @@ public:
|
||||
{
|
||||
const OITScreenDrawer::ComputeTarget target = screenDrawer.ComputeBegin(last, scaled);
|
||||
computeDrawer.Record(target.image, target.view, target.last);
|
||||
screenDrawer.ComputeEnd();
|
||||
screenDrawer.ComputeEnd(computeDrawer.Sums());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,10 +98,12 @@ public:
|
||||
}
|
||||
|
||||
/* @perSample: SSAA's, of a render pass that is not the last, which puts
|
||||
* each sample together; else the last one's, which resolves them too */
|
||||
vk::ShaderModule GetFinalShader(bool perSample = false) const
|
||||
* each sample together; else the last one's, which resolves them too,
|
||||
* and with @sums stores their channel sums (OITBuffers::SetSums()) */
|
||||
vk::ShaderModule GetFinalShader(bool perSample = false, bool sums = false) const
|
||||
{
|
||||
return modules.Get(samples <= 1 ? RSPV_OIT_FINAL_FRAG_S0 : perSample ? RSPV_OIT_FINAL_FRAG_S2 : RSPV_OIT_FINAL_FRAG_S1);
|
||||
return modules.Get(samples <= 1 ? RSPV_OIT_FINAL_FRAG_S0 : perSample ? RSPV_OIT_FINAL_FRAG_S2
|
||||
: sums ? RSPV_OIT_FINAL_FRAG_S1_SUMS : RSPV_OIT_FINAL_FRAG_S1);
|
||||
}
|
||||
/* SSAA's samples a pixel (1: off): what the pipelines are specialized
|
||||
* for, and which modules they take */
|
||||
|
||||
@@ -678,11 +678,12 @@ vk::UniqueRenderPass MakeSsaaRenderPass(vk::Format colorFormat, u32 samples, vk:
|
||||
vk::AttachmentReference colorReference(1, vk::ImageLayout::eColorAttachmentOptimal);
|
||||
vk::AttachmentReference depthReference(2, vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
||||
vk::AttachmentReference samplesInput(1, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
const vk::AttachmentReference hdrInputs[] = { pictureInput, samplesInput };
|
||||
vk::SubpassDescription subpasses[] = {
|
||||
vk::SubpassDescription(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, 0, nullptr, 1, &colorReference, nullptr, &depthReference),
|
||||
vk::SubpassDescription(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, 1, &samplesInput, 1, &pictureReference, nullptr, nullptr),
|
||||
// the HDR output: the picture encoded where it is
|
||||
vk::SubpassDescription(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, 1, &pictureInput, 1, &hdrReference, nullptr, nullptr),
|
||||
// the HDR output: the picture encoded where it is, from the samples' exact average where it is their resolve
|
||||
vk::SubpassDescription(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, 2, hdrInputs, 1, &hdrReference, nullptr, nullptr),
|
||||
};
|
||||
const vk::PipelineStageFlags fbStages = vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests
|
||||
| vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eColorAttachmentOutput;
|
||||
@@ -702,9 +703,11 @@ vk::UniqueRenderPass MakeSsaaRenderPass(vk::Format colorFormat, u32 samples, vk:
|
||||
// the picture, to be shown or sampled
|
||||
vk::SubpassDependency(1, VK_SUBPASS_EXTERNAL, fbStages, fbStages | vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::AccessFlagBits::eColorAttachmentWrite, fbAll | vk::AccessFlagBits::eTransferRead),
|
||||
// the HDR output: the picture resolved, then encoded where it is...
|
||||
// the HDR output: the picture resolved, then encoded where it is (with the samples)...
|
||||
vk::SubpassDependency(1, 2, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eInputAttachmentRead, vk::DependencyFlagBits::eByRegion),
|
||||
vk::SubpassDependency(0, 2, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eFragmentShader,
|
||||
vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eInputAttachmentRead, vk::DependencyFlagBits::eByRegion),
|
||||
// ...into the image the frontend was done with...
|
||||
vk::SubpassDependency(VK_SUBPASS_EXTERNAL, 2, vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eTransfer,
|
||||
vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::AccessFlags(), vk::AccessFlagBits::eColorAttachmentWrite),
|
||||
@@ -716,7 +719,7 @@ vk::UniqueRenderPass MakeSsaaRenderPass(vk::Format colorFormat, u32 samples, vk:
|
||||
return context->GetDevice().createRenderPassUnique(vk::RenderPassCreateInfo(vk::RenderPassCreateFlags(),
|
||||
ARRAY_SIZE(attachmentDescriptions) - (hdr ? 0 : 1), attachmentDescriptions,
|
||||
ARRAY_SIZE(subpasses) - (hdr ? 0 : 1), subpasses,
|
||||
ARRAY_SIZE(dependencies) - (hdr ? 0 : 3), dependencies));
|
||||
ARRAY_SIZE(dependencies) - (hdr ? 0 : 4), dependencies));
|
||||
}
|
||||
|
||||
vk::UniqueRenderPass RttPipelineManager::MakeSsaaRenderPass(u32 samples)
|
||||
|
||||
+6863
-2277
File diff suppressed because it is too large.
Load diff
@@ -11,6 +11,25 @@ layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput p
|
||||
layout (set = 0, binding = 0) uniform sampler2D picture;
|
||||
#endif
|
||||
|
||||
#ifdef SSAA
|
||||
/* With SSAA (after pso_key.h and pvr_resolve.h), the samples the picture
|
||||
* was resolved from, read again: where the picture is their resolve
|
||||
* (pvr_resolve_join(), the rule the resolve wrote it by) their exact
|
||||
* average is encoded, not the byte it was rounded to; where something was
|
||||
* drawn over the picture since (the VMUs, the crosshairs), the picture. */
|
||||
layout (constant_id = PSO_SC_SSAA_SAMPLES) const int SSAA_SAMPLES = 4;
|
||||
layout (constant_id = PSO_SC_SSAA_LOG2N) const uint SSAA_LOG2N = 2u;
|
||||
#ifdef SUBPASS
|
||||
layout (input_attachment_index = 1, set = 0, binding = 13) uniform subpassInputMS samples;
|
||||
#else
|
||||
/* (the per-pixel and compute renderers': no samples by the time the
|
||||
* picture is encoded, but their channel sums, stored by the last pass
|
||||
* (oit_final.frag) or the walk (pvr_compute.h), scaled to the constants'
|
||||
* 16 samples - hdr_encode_vk.h's HDR_VK_SUMS_SAMPLES) */
|
||||
layout (set = 0, binding = 13) uniform usampler2D sums;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
layout (push_constant) uniform pushBlock
|
||||
{
|
||||
vec4 toPanel[3]; /* linear Rec.2020 -> the panel's RGB, columns; zero when unknown */
|
||||
@@ -22,6 +41,10 @@ layout (push_constant) uniform pushBlock
|
||||
int sdrEotf;
|
||||
int scrgb;
|
||||
int deband; /* the picture is 8 bits a channel */
|
||||
int ssaaLog2; /* (Direct3D 12's; here a constant: SSAA_LOG2N) */
|
||||
int pad0;
|
||||
int pad1;
|
||||
int pad2;
|
||||
} pc;
|
||||
|
||||
layout (location = 0) out vec4 FragColor;
|
||||
@@ -29,9 +52,28 @@ layout (location = 0) out vec4 FragColor;
|
||||
void main()
|
||||
{
|
||||
#ifdef SUBPASS
|
||||
highp vec3 rgb = subpassLoad(picture).rgb;
|
||||
highp vec4 pic = subpassLoad(picture);
|
||||
#else
|
||||
highp vec3 rgb = texelFetch(picture, ivec2(gl_FragCoord.xy), 0).rgb;
|
||||
highp vec4 pic = texelFetch(picture, ivec2(gl_FragCoord.xy), 0);
|
||||
#endif
|
||||
highp vec3 rgb = pic.rgb;
|
||||
#ifdef SSAA
|
||||
#ifdef SUBPASS
|
||||
uint rb = 0u;
|
||||
uint ga = 0u;
|
||||
for (int s = 0; s < SSAA_SAMPLES; s++)
|
||||
{
|
||||
uint c = packUnorm4x8(subpassLoad(samples, s));
|
||||
rb += pvr_resolve_rb(c);
|
||||
ga += pvr_resolve_ga(c);
|
||||
}
|
||||
#else
|
||||
uvec4 t = texelFetch(sums, ivec2(gl_FragCoord.xy), 0);
|
||||
uint rb = t.r | (t.b << 16);
|
||||
uint ga = t.g | (t.a << 16);
|
||||
#endif
|
||||
if (packUnorm4x8(pic) == pvr_resolve_join(rb, ga, SSAA_LOG2N))
|
||||
rgb = vec3(float(rb & 0xffffu), float(ga & 0xffffu), float(rb >> 16)) / (255.0 * float(SSAA_SAMPLES));
|
||||
#endif
|
||||
if (pc.deband != 0)
|
||||
rgb = hdr_deband(rgb, gl_FragCoord.xy);
|
||||
|
||||
@@ -156,7 +156,12 @@ vec4 blendFragments(int num_frag, vec4 finalColor, uint sampleBit)
|
||||
#if defined(SSAA) && !defined(SSAA_PER_SAMPLE)
|
||||
/* SSAA's last subpass: the list sorted once, put together at each sample,
|
||||
* and the samples resolved by the shared rule (rend/tile/pvr_resolve.h):
|
||||
* each as the unorm8 the attachment holds, (sum + N/2) / N per channel */
|
||||
* each as the unorm8 the attachment holds, (sum + N/2) / N per channel.
|
||||
* With SSAA_SUMS (the HDR output's), the channel sums stored as well, for
|
||||
* the encode to have the exact average (hdr_encode.frag) */
|
||||
#ifdef SSAA_SUMS
|
||||
layout (set = 3, binding = 3, rgba16ui) uniform writeonly restrict uimage2D sums;
|
||||
#endif
|
||||
void main(void)
|
||||
{
|
||||
ivec2 coords = ivec2(gl_FragCoord.xy);
|
||||
@@ -170,6 +175,12 @@ void main(void)
|
||||
ga += pvr_resolve_ga(c);
|
||||
}
|
||||
FragColor = unpackUnorm4x8(pvr_resolve_join(rb, ga, SSAA_LOG2N));
|
||||
#ifdef SSAA_SUMS
|
||||
/* (scaled to 16 samples: hdr_encode_vk.h's HDR_VK_SUMS_LOG2) */
|
||||
rb <<= 4u - SSAA_LOG2N;
|
||||
ga <<= 4u - SSAA_LOG2N;
|
||||
imageStore(sums, coords, uvec4(rb & 0xffffu, ga & 0xffffu, rb >> 16, ga >> 16));
|
||||
#endif
|
||||
}
|
||||
#elif defined(SSAA)
|
||||
/* ...and of a render pass that is not the last: each sample put together
|
||||
|
||||
@@ -482,7 +482,7 @@ bool VulkanContext::Init(retro_hw_render_interface_vulkan *retro_render_if)
|
||||
{ vk::DescriptorType::eSampler, 2 },
|
||||
{ vk::DescriptorType::eCombinedImageSampler, 4000 },
|
||||
{ vk::DescriptorType::eSampledImage, 2 },
|
||||
{ vk::DescriptorType::eStorageImage, 12 },
|
||||
{ vk::DescriptorType::eStorageImage, 24 },
|
||||
{ vk::DescriptorType::eUniformTexelBuffer, 2 },
|
||||
{ vk::DescriptorType::eStorageTexelBuffer, 2 },
|
||||
{ vk::DescriptorType::eUniformBuffer, 36 },
|
||||
@@ -506,6 +506,8 @@ bool VulkanContext::Init(retro_hw_render_interface_vulkan *retro_render_if)
|
||||
code.vert = RasterSpvWords(RSPV_SSAA_RESOLVE_VERT, &code.vert_size);
|
||||
code.frag = RasterSpvWords(RSPV_HDR_ENCODE_FRAG, &code.frag_size);
|
||||
code.frag_subpass = RasterSpvWords(RSPV_HDR_ENCODE_FRAG_SUBPASS, &code.frag_subpass_size);
|
||||
code.frag_subpass_ssaa = RasterSpvWords(RSPV_HDR_ENCODE_FRAG_SUBPASS_SSAA, &code.frag_subpass_ssaa_size);
|
||||
code.frag_sums = RasterSpvWords(RSPV_HDR_ENCODE_FRAG_SUMS, &code.frag_sums_size);
|
||||
hdr = hdr_vk_new(retro_render_if, heap.Raw(), pipelineCache, hdrFormat, (unsigned)swapChainSize, &code);
|
||||
if (hdr == nullptr)
|
||||
ERROR_LOG(RENDERER, "Vulkan: the HDR output could not be set up; the picture goes out as 24-bit");
|
||||
@@ -671,25 +673,33 @@ void VulkanContext::HdrPrepare(CommandPool& pool, vk::CommandBuffer cmd)
|
||||
hdr_vk_prepare(hdr, &hdr_output, (VkCommandBuffer)cmd, HdrRing(pool), (unsigned)pool.GetIndex(), pool.GetFrames());
|
||||
}
|
||||
|
||||
vk::UniquePipeline VulkanContext::HdrSubpassPipeline(vk::RenderPass renderPass, u32 subpass)
|
||||
vk::UniquePipeline VulkanContext::HdrSubpassPipeline(vk::RenderPass renderPass, u32 subpass, u32 samples)
|
||||
{
|
||||
if (hdr == nullptr)
|
||||
return vk::UniquePipeline();
|
||||
const VkPipeline p = hdr_vk_subpass_pipeline(hdr, (VkRenderPass)renderPass, subpass);
|
||||
const VkPipeline p = hdr_vk_subpass_pipeline(hdr, (VkRenderPass)renderPass, subpass, samples);
|
||||
if (p == VK_NULL_HANDLE)
|
||||
ERROR_LOG(RENDERER, "Vulkan: the HDR output's subpass pipeline could not be made");
|
||||
return vk::UniquePipeline(vk::Pipeline(p), vk::ObjectDestroy<vk::Device, vk::DispatchLoaderStatic>(device));
|
||||
}
|
||||
|
||||
void VulkanContext::HdrSubpassDraw(CommandPool& pool, vk::CommandBuffer cmd, vk::Pipeline pipeline, vk::ImageView picture, vk::Extent2D extent)
|
||||
void VulkanContext::HdrSubpassDraw(CommandPool& pool, vk::CommandBuffer cmd, vk::Pipeline pipeline, vk::ImageView picture,
|
||||
vk::ImageView samples, vk::Extent2D extent)
|
||||
{
|
||||
// (every picture is 8 bits a channel)
|
||||
/* (every picture is 8 bits a channel, dithered; with SSAA's samples,
|
||||
* what is encoded is their exact average, which is not) */
|
||||
if (hdr != nullptr)
|
||||
hdr_vk_subpass_draw(hdr, &hdr_output, (VkCommandBuffer)cmd, HdrRing(pool), (unsigned)pool.GetIndex(),
|
||||
(VkPipeline)pipeline, (VkImageView)picture, extent.width, extent.height, true);
|
||||
(VkPipeline)pipeline, (VkImageView)picture, (VkImageView)samples, extent.width, extent.height, !samples);
|
||||
}
|
||||
|
||||
bool VulkanContext::HdrEncode(CommandPool& pool, vk::Image& image, vk::ImageView& view, vk::Extent2D size)
|
||||
bool VulkanContext::HdrSumsReady()
|
||||
{
|
||||
return hdr != nullptr && hdr_vk_sums_ready(hdr);
|
||||
}
|
||||
|
||||
bool VulkanContext::HdrEncode(CommandPool& pool, vk::Image& image, vk::ImageView& view, vk::Extent2D size,
|
||||
vk::ImageView sums)
|
||||
{
|
||||
if (hdr == nullptr)
|
||||
return false;
|
||||
@@ -698,7 +708,8 @@ bool VulkanContext::HdrEncode(CommandPool& pool, vk::Image& image, vk::ImageView
|
||||
vk::CommandBuffer cmd = pool.Allocate();
|
||||
cmd.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit));
|
||||
const bool done = hdr_vk_encode(hdr, &hdr_output, (VkCommandBuffer)cmd, HdrRing(pool), (unsigned)pool.GetIndex(),
|
||||
pool.GetFrames(), (unsigned)GetCurrentImageIndex(), &i, &v, size.width, size.height, true);
|
||||
pool.GetFrames(), (unsigned)GetCurrentImageIndex(), &i, &v, size.width, size.height, true,
|
||||
(VkImageView)sums);
|
||||
cmd.end();
|
||||
if (done)
|
||||
{
|
||||
|
||||
@@ -63,13 +63,23 @@ public:
|
||||
void HdrPrepare(CommandPool& pool, vk::CommandBuffer cmd);
|
||||
/* The encode as subpass @subpass of @renderPass: the picture its input
|
||||
* attachment 0, the HDR image its colour attachment 0 */
|
||||
vk::UniquePipeline HdrSubpassPipeline(vk::RenderPass renderPass, u32 subpass);
|
||||
void HdrSubpassDraw(CommandPool& pool, vk::CommandBuffer cmd, vk::Pipeline pipeline, vk::ImageView picture, vk::Extent2D extent);
|
||||
// (@samples: SSAA's, above 1 when the subpass also has them as its input attachment 1)
|
||||
vk::UniquePipeline HdrSubpassPipeline(vk::RenderPass renderPass, u32 subpass, u32 samples = 1);
|
||||
// (@samples: those the picture was resolved from, with such a pipeline; null without)
|
||||
void HdrSubpassDraw(CommandPool& pool, vk::CommandBuffer cmd, vk::Pipeline pipeline, vk::ImageView picture,
|
||||
vk::ImageView samples, vk::Extent2D extent);
|
||||
/* The picture (@image, @view, shader-readable, @size) encoded in a pass
|
||||
* of its own, in a command buffer of @pool's, before the pool's
|
||||
* EndFrame(); @image and @view become the HDR image's. False, both as
|
||||
* they were, without the HDR output or when it could not be. */
|
||||
bool HdrEncode(CommandPool& pool, vk::Image& image, vk::ImageView& view, vk::Extent2D size);
|
||||
* they were, without the HDR output or when it could not be.
|
||||
* @sums: the channel sums of the samples the picture was resolved
|
||||
* from (hdr_vk_encode()'s: the per-pixel renderer's, OITBuffers, and
|
||||
* the compute renderer's), after HdrSumsReady() */
|
||||
bool HdrEncode(CommandPool& pool, vk::Image& image, vk::ImageView& view, vk::Extent2D size,
|
||||
vk::ImageView sums = vk::ImageView());
|
||||
/* The HDR output, and HdrEncode() able to take the channel sums: made
|
||||
* ready, before the frames */
|
||||
bool HdrSumsReady();
|
||||
|
||||
vk::PhysicalDevice GetPhysicalDevice() const { return physicalDevice; }
|
||||
vk::Device GetDevice() const { return device; }
|
||||
|
||||
+114
-6
@@ -1,6 +1,15 @@
|
||||
/* ACES 2.0 (Full)'s cube baked off the frame (hdr_transform.c): with
|
||||
* threads, hdr_dt_fill() hands the bake to a worker and never waits for
|
||||
* it. This holds the cube it comes back with to the one baked in place
|
||||
/* ACES 2.0 (Full)'s tables and cube made off the frame (hdr_transform.c):
|
||||
* with threads, hdr_dt_fill() hands them to a worker and never waits for
|
||||
* it. The tables:
|
||||
*
|
||||
* - the first fill with none draws the tone scale alone, and the fills
|
||||
* after a change of settings go on with the tables there were, not
|
||||
* the new ones made there and then (as they were before: a frame of
|
||||
* several milliseconds);
|
||||
* - what the fills draw once the worker's are back is what the tables
|
||||
* made in place (hdr_dt_finish()) give, to the byte.
|
||||
*
|
||||
* The cube it comes back with is held to the one baked in place
|
||||
* (hdr_dt_aces2_cube_finish()), byte for byte:
|
||||
*
|
||||
* - baked through, with the frame thread polling as frames do;
|
||||
@@ -77,13 +86,11 @@ static unsigned fill_until_baked(float paper)
|
||||
static uint16_t *reference(int gamut, float paper)
|
||||
{
|
||||
struct hdr_dt_settings s;
|
||||
struct hdr_dt_block b;
|
||||
uint16_t *ref = (uint16_t*)malloc(CUBE_BYTES);
|
||||
hdr_dt_free();
|
||||
settings(&s, gamut);
|
||||
hdr_dt_configure(&s);
|
||||
hdr_dt_fill(&b, paper, 1000.0f, 1000.0f, xy);
|
||||
hdr_dt_aces2_cube_finish(paper);
|
||||
hdr_dt_finish(paper, 1000.0f, 1000.0f, xy, true);
|
||||
if (!ref || !hdr_dt_aces2_cube())
|
||||
{
|
||||
printf("hdr_cube: no reference cube\n");
|
||||
@@ -94,6 +101,106 @@ static uint16_t *reference(int gamut, float paper)
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* The block the fills draw for @gamut at @paper with the tables made in
|
||||
* place, the cube flag aside */
|
||||
static void reference_block(int gamut, float paper, struct hdr_dt_block *b)
|
||||
{
|
||||
struct hdr_dt_settings s;
|
||||
hdr_dt_free();
|
||||
settings(&s, gamut);
|
||||
hdr_dt_configure(&s);
|
||||
hdr_dt_finish(paper, 1000.0f, 1000.0f, xy, false);
|
||||
hdr_dt_fill(b, paper, 1000.0f, 1000.0f, xy);
|
||||
b->gm[2] = 0.0f;
|
||||
hdr_dt_free();
|
||||
}
|
||||
|
||||
#ifndef TARGET_NO_THREADS
|
||||
/* Fills until the block is @want, the cube flag aside: the tables the
|
||||
* worker makes come to it. Each block before is @before's (NULL: one of
|
||||
* no tables, the tone scale alone), never one of two tables: a fill
|
||||
* whose cube bake took new tables back half way through gave that,
|
||||
* reading the ones it had freed. */
|
||||
static void fill_until(float paper, const struct hdr_dt_block *before, const struct hdr_dt_block *want,
|
||||
struct hdr_dt_block *b)
|
||||
{
|
||||
clock_t start = clock();
|
||||
for (;;)
|
||||
{
|
||||
hdr_dt_fill(b, paper, 1000.0f, 1000.0f, xy);
|
||||
b->gm[2] = 0.0f;
|
||||
if (!memcmp(b, want, sizeof(*b)))
|
||||
return;
|
||||
if (before ? memcmp(b, before, sizeof(*b)) != 0 : (int)b->mode[0] != HDR_DT_ACES2)
|
||||
{
|
||||
printf("hdr_cube: a block neither of the tables before nor of the new ones\n");
|
||||
failures++;
|
||||
return;
|
||||
}
|
||||
if ((double)(clock() - start) / CLOCKS_PER_SEC > 60.0)
|
||||
{
|
||||
printf("hdr_cube: not the tables made in place after a minute\n");
|
||||
failures++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void same_block(const char *what, const struct hdr_dt_block *b, const struct hdr_dt_block *ref)
|
||||
{
|
||||
if (memcmp(b, ref, sizeof(*b)))
|
||||
{
|
||||
printf("hdr_cube: %s: the block is not the one the tables made in place give\n", what);
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
printf("hdr_cube: %s: same\n", what);
|
||||
}
|
||||
|
||||
/* The tables: made off the frame, and the same as made in place */
|
||||
static void tables(void)
|
||||
{
|
||||
struct hdr_dt_settings s;
|
||||
struct hdr_dt_block b, ref1, ref2, old;
|
||||
reference_block(1, 200.0f, &ref1);
|
||||
reference_block(2, 200.0f, &ref2);
|
||||
|
||||
settings(&s, 1);
|
||||
hdr_dt_configure(&s);
|
||||
hdr_dt_fill(&b, 200.0f, 1000.0f, 1000.0f, xy);
|
||||
#ifndef TARGET_NO_THREADS
|
||||
/* none yet: the tone scale alone, nothing solved in the fill */
|
||||
if ((int)b.mode[0] != HDR_DT_ACES2 || hdr_dt_aces2_lut())
|
||||
{
|
||||
printf("hdr_cube: the first fill made the tables itself\n");
|
||||
failures++;
|
||||
}
|
||||
fill_until(200.0f, NULL, &ref1, &b);
|
||||
#endif
|
||||
b.gm[2] = 0.0f;
|
||||
same_block("tables made off the frame", &b, &ref1);
|
||||
|
||||
/* another gamut (Rec.2020): the fills go on with these until the new ones are back */
|
||||
old = b;
|
||||
settings(&s, 2);
|
||||
hdr_dt_configure(&s);
|
||||
hdr_dt_fill(&b, 200.0f, 1000.0f, 1000.0f, xy);
|
||||
b.gm[2] = 0.0f;
|
||||
#ifndef TARGET_NO_THREADS
|
||||
if (memcmp(&b, &old, sizeof(b)))
|
||||
{
|
||||
printf("hdr_cube: the fill after a change made the new tables itself\n");
|
||||
failures++;
|
||||
}
|
||||
fill_until(200.0f, &old, &ref2, &b);
|
||||
#endif
|
||||
same_block("another gamut's tables", &b, &ref2);
|
||||
(void)old;
|
||||
hdr_dt_free();
|
||||
}
|
||||
|
||||
static void same(const char *what, const uint16_t *ref)
|
||||
{
|
||||
const uint16_t *cube = hdr_dt_aces2_cube();
|
||||
@@ -125,6 +232,7 @@ int main(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tables();
|
||||
ref200 = reference(1, 200.0f);
|
||||
ref300 = reference(1, 300.0f);
|
||||
refp3 = reference(2, 300.0f);
|
||||
|
||||
+299
-6
@@ -7,12 +7,23 @@
|
||||
* it under wine.
|
||||
*
|
||||
* hdr_d3d 11|12 out.bin
|
||||
* hdr_d3d 12ssaa
|
||||
*
|
||||
* 12ssaa: the Direct3D 12 encoder with SSAA's samples (hdr_encode.hlsl's
|
||||
* HDR_ENCODE_SSAA). Known values are drawn into each sample of a 4x
|
||||
* multisampled picture, the picture is made their resolve by the shared
|
||||
* rule (rend/tile/pvr_resolve.h), but for a strip drawn over (the VMUs'
|
||||
* stand-in); the encode of the two is held to that of the samples' exact
|
||||
* average as a half-float picture - the picture where it was drawn over -
|
||||
* and has to differ from that of the 8-bit picture: the extra bits are
|
||||
* there and are the samples'.
|
||||
*
|
||||
* C89. */
|
||||
#define COBJMACROS
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3d12.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -73,15 +84,14 @@ static void put(void)
|
||||
cases++;
|
||||
}
|
||||
|
||||
/* (a cube case's tables made for its settings, then its cube baked) */
|
||||
/* (ACES 2.0 (full)'s tables made now, which frames leave to a worker,
|
||||
* and a cube case's cube from them) */
|
||||
static void prepare(const struct hdr_dt_settings *dt, const struct hdr_output *o, int cube)
|
||||
{
|
||||
struct hdr_dt_block b;
|
||||
hdr_dt_configure(dt);
|
||||
hdr_dt_finish(o->paper_white_nits, o->max_nits, o->panel_peak_nits, o->panel_xy, cube != 0);
|
||||
if (cube)
|
||||
{
|
||||
hdr_dt_fill(&b, o->paper_white_nits, o->max_nits, o->panel_peak_nits, o->panel_xy);
|
||||
hdr_dt_aces2_cube_finish(o->paper_white_nits);
|
||||
if (!hdr_dt_aces2_cube())
|
||||
{
|
||||
fprintf(stderr, "hdr_d3d: no cube\n");
|
||||
@@ -318,7 +328,7 @@ static void run12(const char *name, const struct hdr_dt_settings *dt, const stru
|
||||
void *map;
|
||||
prepare(dt, o, cube);
|
||||
if (!hdr_d3d12_encode(enc12[scrgb], list, o, pic12, DXGI_FORMAT_R8G8B8A8_UNORM, W, H, deband != 0,
|
||||
cases % 3, fence_value + 1, &texture))
|
||||
NULL, 0, cases % 3, fence_value + 1, &texture))
|
||||
{
|
||||
fprintf(stderr, "hdr_d3d: %s: not encoded\n", name);
|
||||
exit(1);
|
||||
@@ -333,12 +343,295 @@ static void run12(const char *name, const struct hdr_dt_settings *dt, const stru
|
||||
put();
|
||||
}
|
||||
|
||||
/* ---- Direct3D 12 with SSAA's samples ---- */
|
||||
|
||||
#define SSAA_N 4
|
||||
#define SSAA_LOG2 2
|
||||
#define OSD_X 16 /* the columns left of it are "drawn over" */
|
||||
|
||||
/* The byte the filler draws at channel @c of sample @s of (x, y): its PS's arithmetic */
|
||||
static unsigned sample_byte(unsigned x, unsigned y, unsigned s, unsigned c)
|
||||
{
|
||||
unsigned v = (x * 73u + y * 151u + s * 61u + c * 97u) * 2654435761u;
|
||||
/* (a smooth ramp across x, so most samples differ by a few steps, with the hash's low bits) */
|
||||
return ((x + (v >> 30)) * 255u / (W + 3u)) & 255u;
|
||||
}
|
||||
|
||||
static uint16_t to_half(float f)
|
||||
{
|
||||
union { float f; uint32_t u; } v;
|
||||
uint32_t sign, mant;
|
||||
int exp;
|
||||
v.f = f;
|
||||
sign = (v.u >> 16) & 0x8000u;
|
||||
exp = (int)((v.u >> 23) & 0xff) - 127 + 15;
|
||||
mant = v.u & 0x7fffffu;
|
||||
if (exp <= 0)
|
||||
return (uint16_t)sign;
|
||||
if (exp >= 31)
|
||||
return (uint16_t)(sign | 0x7bffu);
|
||||
{
|
||||
uint32_t h = ((uint32_t)exp << 10) | (mant >> 13);
|
||||
if ((mant & 0x1fffu) > 0x1000u || ((mant & 0x1fffu) == 0x1000u && (h & 1u)))
|
||||
h++;
|
||||
return (uint16_t)(sign | h);
|
||||
}
|
||||
}
|
||||
|
||||
static ID3D12Resource *texture12(DXGI_FORMAT format, unsigned samples, D3D12_RESOURCE_FLAGS flags,
|
||||
D3D12_RESOURCE_STATES state)
|
||||
{
|
||||
D3D12_HEAP_PROPERTIES hp;
|
||||
D3D12_RESOURCE_DESC rd;
|
||||
ID3D12Resource *r = NULL;
|
||||
memset(&hp, 0, sizeof(hp));
|
||||
hp.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
memset(&rd, 0, sizeof(rd));
|
||||
rd.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
rd.Width = W;
|
||||
rd.Height = H;
|
||||
rd.DepthOrArraySize = 1;
|
||||
rd.MipLevels = 1;
|
||||
rd.Format = format;
|
||||
rd.SampleDesc.Count = samples;
|
||||
rd.Flags = flags;
|
||||
if (FAILED(ID3D12Device_CreateCommittedResource(d12, &hp, D3D12_HEAP_FLAG_NONE, &rd, state, NULL,
|
||||
&IID_ID3D12Resource, (void**)&r)))
|
||||
exit(2);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* @data (W x H of @bpp bytes) into a new texture of @format, in the pixel shader resource state */
|
||||
static ID3D12Resource *uploaded12(const void *data, DXGI_FORMAT format, unsigned bpp)
|
||||
{
|
||||
ID3D12Resource *t = texture12(format, 1, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
ID3D12Resource *up = buffer12(D3D12_HEAP_TYPE_UPLOAD, (UINT64)W * H * bpp, D3D12_RESOURCE_STATE_GENERIC_READ);
|
||||
void *map;
|
||||
ID3D12Resource_Map(up, 0, NULL, &map);
|
||||
memcpy(map, data, (size_t)W * H * bpp);
|
||||
ID3D12Resource_Unmap(up, 0, NULL);
|
||||
copy12(t, up, format, bpp, 1);
|
||||
barrier12(t, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
submit12();
|
||||
ID3D12Resource_Release(up);
|
||||
return t;
|
||||
}
|
||||
|
||||
static ID3DBlob *compile(const char *src, const char *target)
|
||||
{
|
||||
pD3DCompile fn = (pD3DCompile)GetProcAddress(LoadLibraryA("d3dcompiler_47.dll"), "D3DCompile");
|
||||
ID3DBlob *code = NULL, *err = NULL;
|
||||
if (!fn || FAILED(fn(src, strlen(src), NULL, NULL, NULL, "main", target, 0, 0, &code, &err)))
|
||||
{
|
||||
fprintf(stderr, "hdr_d3d: the filler did not compile: %s\n", err ? (const char*)ID3D10Blob_GetBufferPointer(err) : "");
|
||||
exit(2);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
/* Each sample of @ms drawn with sample_byte()'s values: a draw for each,
|
||||
* the pipeline's sample mask picking it and a root constant saying which
|
||||
* (SV_SampleIndex is not in every compiler wine has) */
|
||||
static void fill_samples(ID3D12Resource *ms)
|
||||
{
|
||||
static const char vs[] =
|
||||
"float4 main(uint id : SV_VertexID) : SV_Position {"
|
||||
" float2 p = float2((id << 1) & 2, id & 2); return float4(p * float2(2, -2) + float2(-1, 1), 0, 1); }";
|
||||
static const char ps[] =
|
||||
"uint b(uint x, uint y, uint s, uint c) { uint v = (x * 73u + y * 151u + s * 61u + c * 97u) * 2654435761u;"
|
||||
" return ((x + (v >> 30)) * 255u / (256u + 3u)) & 255u; }"
|
||||
"cbuffer S : register(b0) { uint s; };"
|
||||
"float4 main(float4 pos : SV_Position) : SV_Target {"
|
||||
" uint x = (uint)pos.x, y = (uint)pos.y;"
|
||||
" return float4(b(x, y, s, 0u), b(x, y, s, 1u), b(x, y, s, 2u), b(x, y, s, 3u)) / 255.0; }";
|
||||
D3D12_ROOT_SIGNATURE_DESC rsd;
|
||||
D3D12_ROOT_PARAMETER rp;
|
||||
ID3DBlob *rsb = NULL, *rse = NULL, *vsb = compile(vs, "vs_5_0"), *psb = compile(ps, "ps_5_0");
|
||||
ID3D12RootSignature *root = NULL;
|
||||
ID3D12PipelineState *pso[SSAA_N];
|
||||
unsigned n;
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC pd;
|
||||
D3D12_DESCRIPTOR_HEAP_DESC hd;
|
||||
ID3D12DescriptorHeap *rtv_heap;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv;
|
||||
D3D12_VIEWPORT vp;
|
||||
D3D12_RECT sc;
|
||||
memset(&rp, 0, sizeof(rp));
|
||||
rp.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
|
||||
rp.Constants.Num32BitValues = 1;
|
||||
rp.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||
memset(&rsd, 0, sizeof(rsd));
|
||||
rsd.NumParameters = 1;
|
||||
rsd.pParameters = &rp;
|
||||
if (FAILED(D3D12SerializeRootSignature(&rsd, D3D_ROOT_SIGNATURE_VERSION_1, &rsb, &rse))
|
||||
|| FAILED(ID3D12Device_CreateRootSignature(d12, 0, ID3D10Blob_GetBufferPointer(rsb), ID3D10Blob_GetBufferSize(rsb),
|
||||
&IID_ID3D12RootSignature, (void**)&root)))
|
||||
exit(2);
|
||||
memset(&pd, 0, sizeof(pd));
|
||||
pd.pRootSignature = root;
|
||||
pd.VS.pShaderBytecode = ID3D10Blob_GetBufferPointer(vsb);
|
||||
pd.VS.BytecodeLength = ID3D10Blob_GetBufferSize(vsb);
|
||||
pd.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(psb);
|
||||
pd.PS.BytecodeLength = ID3D10Blob_GetBufferSize(psb);
|
||||
pd.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||
pd.SampleMask = 0xffffffffu;
|
||||
pd.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||
pd.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
|
||||
pd.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
pd.NumRenderTargets = 1;
|
||||
pd.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
pd.SampleDesc.Count = SSAA_N;
|
||||
for (n = 0; n < SSAA_N; n++)
|
||||
{
|
||||
pd.SampleMask = 1u << n;
|
||||
if (FAILED(ID3D12Device_CreateGraphicsPipelineState(d12, &pd, &IID_ID3D12PipelineState, (void**)&pso[n])))
|
||||
exit(2);
|
||||
}
|
||||
memset(&hd, 0, sizeof(hd));
|
||||
hd.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||
hd.NumDescriptors = 1;
|
||||
if (FAILED(ID3D12Device_CreateDescriptorHeap(d12, &hd, &IID_ID3D12DescriptorHeap, (void**)&rtv_heap)))
|
||||
exit(2);
|
||||
rtv_heap->lpVtbl->GetCPUDescriptorHandleForHeapStart(rtv_heap, &rtv);
|
||||
ID3D12Device_CreateRenderTargetView(d12, ms, NULL, rtv);
|
||||
vp.TopLeftX = 0.0f; vp.TopLeftY = 0.0f; vp.Width = (float)W; vp.Height = (float)H; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f;
|
||||
sc.left = 0; sc.top = 0; sc.right = W; sc.bottom = H;
|
||||
ID3D12GraphicsCommandList_SetGraphicsRootSignature(list, root);
|
||||
ID3D12GraphicsCommandList_RSSetViewports(list, 1, &vp);
|
||||
ID3D12GraphicsCommandList_RSSetScissorRects(list, 1, &sc);
|
||||
ID3D12GraphicsCommandList_OMSetRenderTargets(list, 1, &rtv, FALSE, NULL);
|
||||
ID3D12GraphicsCommandList_IASetPrimitiveTopology(list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
for (n = 0; n < SSAA_N; n++)
|
||||
{
|
||||
ID3D12GraphicsCommandList_SetPipelineState(list, pso[n]);
|
||||
ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstant(list, 0, n, 0);
|
||||
ID3D12GraphicsCommandList_DrawInstanced(list, 3, 1, 0, 0);
|
||||
}
|
||||
barrier12(ms, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
submit12();
|
||||
}
|
||||
|
||||
/* What @picture (of @format, 8 bits a channel when @unorm8; SSAA's @samples or NULL) encodes to, as floats */
|
||||
static void encode12(hdr_d3d12_t *e, const struct hdr_output *o, ID3D12Resource *picture, DXGI_FORMAT format,
|
||||
bool unorm8, ID3D12Resource *samples, float *dst)
|
||||
{
|
||||
const int scrgb = o->format == HDR_OUTPUT_SCRGB;
|
||||
const DXGI_FORMAT out = scrgb ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
const unsigned bpp = scrgb ? 8 : 4;
|
||||
ID3D12Resource *texture = NULL;
|
||||
void *map;
|
||||
if (!hdr_d3d12_encode(e, list, o, picture, format, W, H, unorm8, samples, samples ? SSAA_LOG2 : 0,
|
||||
cases % 3, fence_value + 1, &texture))
|
||||
{
|
||||
fprintf(stderr, "hdr_d3d: not encoded\n");
|
||||
exit(1);
|
||||
}
|
||||
barrier12(texture, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
copy12(readback, texture, out, bpp, 0);
|
||||
barrier12(texture, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
submit12();
|
||||
ID3D12Resource_Map(readback, 0, NULL, &map);
|
||||
to_floats((const unsigned char*)map, (size_t)W * bpp, out);
|
||||
ID3D12Resource_Unmap(readback, 0, NULL);
|
||||
memcpy(dst, pixels, sizeof(pixels));
|
||||
cases++;
|
||||
}
|
||||
|
||||
static float ssaa_out[W * H * 4], exact_out[W * H * 4], byte_out[W * H * 4];
|
||||
|
||||
static int ssaa12(void)
|
||||
{
|
||||
static unsigned char pic8[W * H * 4];
|
||||
static uint16_t exact16[W * H * 4];
|
||||
struct hdr_dt_settings dt;
|
||||
struct hdr_output o;
|
||||
ID3D12Resource *ms, *pic, *exact;
|
||||
unsigned x, y, c, i, k;
|
||||
|
||||
setup12();
|
||||
ms = texture12(DXGI_FORMAT_R8G8B8A8_UNORM, SSAA_N, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
fill_samples(ms);
|
||||
for (y = 0; y < H; y++)
|
||||
for (x = 0; x < W; x++)
|
||||
for (c = 0; c < 4; c++)
|
||||
{
|
||||
const size_t at = ((size_t)y * W + x) * 4 + c;
|
||||
unsigned sum = 0, s;
|
||||
for (s = 0; s < SSAA_N; s++)
|
||||
sum += sample_byte(x, y, s, c);
|
||||
if (x < OSD_X)
|
||||
{
|
||||
/* drawn over: not the resolve (a byte it cannot be: off by 7) */
|
||||
pic8[at] = (unsigned char)(((sum + SSAA_N / 2) / SSAA_N + 7u) & 255u);
|
||||
exact16[at] = to_half((float)pic8[at] / 255.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
pic8[at] = (unsigned char)((sum + SSAA_N / 2) / SSAA_N); /* pvr_resolve_join() */
|
||||
exact16[at] = to_half((float)sum / (255.0f * SSAA_N));
|
||||
}
|
||||
}
|
||||
pic = uploaded12(pic8, DXGI_FORMAT_R8G8B8A8_UNORM, 4);
|
||||
exact = uploaded12(exact16, DXGI_FORMAT_R16G16B16A16_FLOAT, 8);
|
||||
|
||||
memset(&dt, 0, sizeof(dt));
|
||||
dt.aces2_surround = 1;
|
||||
dt.gt_toe = 0.22f;
|
||||
dt.gt_linear = 0.40f;
|
||||
dt.filmic_contrast = 3;
|
||||
dt.filmic_max_ev = 4.026068811f;
|
||||
memset(&o, 0, sizeof(o));
|
||||
o.paper_white_nits = 200.0f;
|
||||
o.max_nits = 1000.0f;
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
unsigned differ = 0, osd_differ = 0;
|
||||
double worst = 0.0;
|
||||
dt.curve = (k & 2) ? HDR_DT_AGX : HDR_DT_KNEE;
|
||||
o.format = (k & 1) ? HDR_OUTPUT_SCRGB : HDR_OUTPUT_HDR10;
|
||||
hdr_dt_configure(&dt);
|
||||
hdr_dt_finish(o.paper_white_nits, o.max_nits, o.panel_peak_nits, o.panel_xy, false);
|
||||
encode12(enc12[k & 1], &o, pic, DXGI_FORMAT_R8G8B8A8_UNORM, true, ms, ssaa_out);
|
||||
encode12(enc12[k & 1], &o, exact, DXGI_FORMAT_R16G16B16A16_FLOAT, false, NULL, exact_out);
|
||||
encode12(enc12[k & 1], &o, pic, DXGI_FORMAT_R8G8B8A8_UNORM, false, NULL, byte_out);
|
||||
for (i = 0; i < W * H * 4; i++)
|
||||
{
|
||||
const double a = ssaa_out[i], b = exact_out[i];
|
||||
/* the half-float picture's rounding and the output's: a 10-bit code (the two
|
||||
* on either side of a rounding, both quantized), or a half float's */
|
||||
const double tol = (o.format == HDR_OUTPUT_SCRGB) ? 2e-3 * (fabs(b) > 1.0 ? fabs(b) : 1.0) : 1.001 / 1023.0;
|
||||
const double d = fabs(a - b) / tol;
|
||||
if (d > worst)
|
||||
worst = d;
|
||||
if (i % 4 != 3 && fabs(ssaa_out[i] - byte_out[i]) > 1e-6)
|
||||
{
|
||||
if ((i / 4) % W < OSD_X)
|
||||
osd_differ++;
|
||||
else
|
||||
differ++;
|
||||
}
|
||||
}
|
||||
printf("hdr_d3d: SSAA %s %s: within %.2f of the tolerance of the exact average's; %u channels not the 8-bit picture's, %u drawn over\n",
|
||||
(k & 2) ? "agx" : "knee", (k & 1) ? "scRGB" : "HDR10", worst, differ, osd_differ);
|
||||
if (!(worst <= 1.0) || differ < 1000 || osd_differ != 0)
|
||||
failures++;
|
||||
}
|
||||
hdr_d3d12_free(enc12[0]);
|
||||
hdr_d3d12_free(enc12[1]);
|
||||
hdr_dt_free();
|
||||
printf("hdr_d3d: Direct3D 12 with SSAA's samples%s\n", failures ? ": failed" : ": the samples' exact average");
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int api;
|
||||
if (argc == 2 && !strcmp(argv[1], "12ssaa"))
|
||||
return ssaa12();
|
||||
if (argc != 3 || (strcmp(argv[1], "11") && strcmp(argv[1], "12")))
|
||||
{
|
||||
fprintf(stderr, "usage: hdr_d3d 11|12 out.bin\n");
|
||||
fprintf(stderr, "usage: hdr_d3d 11|12 out.bin | 12ssaa\n");
|
||||
return 2;
|
||||
}
|
||||
api = atoi(argv[1]);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
# (rend/hdr/hdr_encode_d3d11.c, hdr_encode_d3d12.c) and the DXBC committed
|
||||
# for them - built with mingw-w64 and run under wine (wined3d and vkd3d,
|
||||
# on a Vulkan driver: lavapipe will do), over every case hdr_hlsl.sh
|
||||
# draws, and held to the Vulkan renderer's GLSL (hdr_hlsl --against).
|
||||
# draws, and held to the Vulkan renderer's GLSL (hdr_hlsl --against);
|
||||
# and Direct3D 12's with SSAA's samples to their exact average (12ssaa).
|
||||
#
|
||||
# sh tools/hdr/hdr_d3d.sh
|
||||
#
|
||||
@@ -29,4 +30,6 @@ for api in 11 12; do
|
||||
wine "$WORK/hdr_d3d.exe" $api "Z:$WORK/d3d$api.bin"
|
||||
HDR_HLSL_AGAINST="$WORK/d3d$api.bin" sh tools/vulkan/hdr_hlsl.sh
|
||||
done
|
||||
# Direct3D 12's encode with SSAA's samples: their exact average
|
||||
env -u TMPDIR DISPLAY=$DISPLAY_NO WINEDEBUG=-all wine "$WORK/hdr_d3d.exe" 12ssaa
|
||||
echo "hdr_d3d.sh: passed"
|
||||
@@ -210,8 +210,9 @@ compute_source_of() {
|
||||
fi
|
||||
shift 2
|
||||
for d in "$@"; do echo "$d"; done
|
||||
# (and without the blocks for Vulkan's HDR output, PVRC_SUMS: not in these)
|
||||
for h in core/rend/tile/pvr_lane.h core/rend/tile/pvr_tile.h core/rend/tile/pvr_modvol.h core/rend/tile/pvr_resolve.h core/rend/tile/pvr_scaler.h core/rend/ssaa_pattern.h $PVRC_SRC; do
|
||||
sed '/^#include/d' $h
|
||||
sed -e '/^#include/d' -e '/^#if defined(PVRC_SUMS)$/,/^#endif \/\* PVRC_SUMS \*\/$/d' $h
|
||||
done | sed -e 's/\b\(frm\|rec\|bin\|vtx\|idx\|mvt\|dcmd\|dtrd\|dfrm\)\.w\[/\1_w[/g' \
|
||||
-e 's/^layout(local_size_x = \(.*\)) in;$/#define PVRC_THREADS \1/' \
|
||||
-e 's/^\(\(uint\|int\|bool\|float\|uvec4\|vec2\) [A-Za-z_0-9]*\( = [A-Za-z_0-9]*\)\?\(, [A-Za-z_0-9]*\( = [A-Za-z_0-9]*\)\?\)*;\)/static \1/' \
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
# the HDR output's encode, one for Direct3D 11
|
||||
# and 12 both (rend/hdr/hdr_encode.hlsl with
|
||||
# HDR_ENCODE_VS or HDR_ENCODE_PS;
|
||||
# hdr/hdr_encode_d3d11.c, hdr_encode_d3d12.c)
|
||||
# hdr/hdr_encode_d3d11.c, hdr_encode_d3d12.c),
|
||||
# and Direct3D 12's with SSAA's samples too
|
||||
# (HDR_ENCODE_SSAA, after rend/tile/pvr_lane.h
|
||||
# and pvr_resolve.h: PS_SSAA)
|
||||
#
|
||||
# sh tools/rend/kernels_dxbc.sh update all made again from their sources
|
||||
# sh tools/rend/kernels_dxbc.sh update-hdr only the HDR output's made again
|
||||
@@ -38,7 +41,7 @@ INC_HDR=core/rend/hdr/hdr_encode_dxbc.inc
|
||||
# kernel: profile
|
||||
KERNELS="1:cs_5_0 2:cs_5_0 3:vs_5_0 4:ps_5_0"
|
||||
KERNELS9="1:vs_3_0 2:ps_3_0"
|
||||
KERNELS_HDR="VS:vs_5_0 PS:ps_5_0"
|
||||
KERNELS_HDR="VS:vs_5_0 PS:ps_5_0 PS_SSAA:ps_5_0"
|
||||
CC_WIN=${CC_WIN:-x86_64-w64-mingw32-gcc}
|
||||
WINE=${WINE-wine}
|
||||
|
||||
@@ -50,8 +53,16 @@ source_of() {
|
||||
echo "#define TEXD_SHADER_HLSL"; echo "#define TEXD_KERNEL_D3D $1"; cat core/rend/texdecode.h
|
||||
}
|
||||
|
||||
# (PS_SSAA: the pixel shader with SSAA's samples, after the shared rules it resolves by)
|
||||
source_hdr_of() {
|
||||
echo "#define HDR_ENCODE_$1"; cat core/rend/hdr/hdr_encode.hlsl
|
||||
case $1 in
|
||||
PS_SSAA)
|
||||
echo "#define HDR_ENCODE_PS"; echo "#define HDR_ENCODE_SSAA"
|
||||
echo "#define PVR_SHADER_HLSL"; echo "#define PVR_LANE_NONE"
|
||||
cat core/rend/tile/pvr_lane.h core/rend/tile/pvr_resolve.h | grep -v "^#include" ;;
|
||||
*) echo "#define HDR_ENCODE_$1" ;;
|
||||
esac
|
||||
cat core/rend/hdr/hdr_encode.hlsl
|
||||
}
|
||||
|
||||
source9_of() {
|
||||
@@ -121,8 +132,10 @@ make_inc() {
|
||||
# (included by C89, so no C++ comments)
|
||||
make_inc_hdr() {
|
||||
echo "/* DXBC of the HDR output's encode for Direct3D 11 and 12"
|
||||
echo " * (rend/hdr/hdr_encode.hlsl with HDR_ENCODE_VS or HDR_ENCODE_PS): made by"
|
||||
echo " * tools/rend/kernels_dxbc.sh update from it. Not to be edited."
|
||||
echo " * (rend/hdr/hdr_encode.hlsl with HDR_ENCODE_VS or HDR_ENCODE_PS, and"
|
||||
echo " * PS_SSAA with HDR_ENCODE_SSAA, after rend/tile/pvr_lane.h and"
|
||||
echo " * pvr_resolve.h): made by tools/rend/kernels_dxbc.sh update from it."
|
||||
echo " * Not to be edited."
|
||||
echo " * d3dcompiler_47 $(compiler_sum)"
|
||||
sums_hdr
|
||||
echo " */"
|
||||
|
||||
@@ -111,6 +111,8 @@ compute_source() {
|
||||
echo "#version 450"; echo "#define PVR_SHADER_GLSL"; echo "#define PVRC_SHADER_GLSL"; echo "#define PVRC_KERNEL $1"
|
||||
if [ "$2" = waterfall ]; then echo "#define PVRC_TEX_WATERFALL"; fi
|
||||
if [ "$1" = "$PVRC_K_WALK" ]; then echo "#define PVR_LANE_COUNT 8"; echo "#define PVR_LANE_GROUP_SIZE 256"; else echo "#define PVR_LANE_NONE"; fi
|
||||
# (the HDR output's channel sums, which the walk stores with its constant PVRC_SUMS_ON)
|
||||
echo "#define PVRC_SUMS"
|
||||
for h in core/rend/tile/pvr_lane.h core/rend/tile/pvr_tile.h core/rend/tile/pvr_modvol.h core/rend/tile/pvr_resolve.h core/rend/tile/pvr_scaler.h core/rend/ssaa_pattern.h core/rend/tile/pvr_compute.h; do
|
||||
sed '/^#include/d' $h
|
||||
done
|
||||
@@ -314,11 +316,15 @@ raster_list() {
|
||||
done
|
||||
echo "OIT_FINAL_FRAG_S0 frag - key oit_header.glsl oit_final.frag"
|
||||
echo "OIT_FINAL_FRAG_S1 frag SSAA=1 key resolve oit_header.glsl oit_final.frag"
|
||||
echo "OIT_FINAL_FRAG_S1_SUMS frag SSAA=1,SSAA_SUMS=1 key resolve oit_header.glsl oit_final.frag"
|
||||
echo "OIT_FINAL_FRAG_S2 frag SSAA=1,SSAA_PER_SAMPLE=1 key resolve oit_header.glsl oit_final.frag"
|
||||
echo "OIT_FINAL_VERT vert - oit_final.vert"
|
||||
# (the HDR output's encode, drawn by SSAA_RESOLVE_VERT's triangle: on its own, and as a render pass's last subpass)
|
||||
echo "HDR_ENCODE_FRAG frag HDR_DT=1 hdr hdr_encode.frag"
|
||||
echo "HDR_ENCODE_FRAG_SUBPASS frag HDR_DT=1,SUBPASS=1 hdr hdr_encode.frag"
|
||||
# (...and SSAA's: the samples' exact average where the picture is their resolve)
|
||||
echo "HDR_ENCODE_FRAG_SUBPASS_SSAA frag HDR_DT=1,SUBPASS=1,SSAA=1 key resolve hdr hdr_encode.frag"
|
||||
echo "HDR_ENCODE_FRAG_SUMS frag HDR_DT=1,SSAA=1 key resolve hdr hdr_encode.frag"
|
||||
}
|
||||
|
||||
# a raster module's text: @1 its defines, then what it is made of
|
||||
|
||||
+827
-3
@@ -2,14 +2,16 @@
|
||||
"""Write a bootable GD-ROM image (GDI + three track files) around the
|
||||
bare-metal test program in live_prog.c, for tools/threads/live.sh.
|
||||
|
||||
Usage: live_disc.py out.gdi [--no-region-array | --mmu-align]
|
||||
Usage: live_disc.py out.gdi [--no-region-array | --mmu-align | --slant | --hscale]
|
||||
live_disc.py out.elf
|
||||
|
||||
The program is carried here already compiled, so the test needs no SH-4
|
||||
compiler; live_prog.c says how PROGRAM was produced. --no-region-array
|
||||
takes the build of it that renders without ever writing a region array;
|
||||
--mmu-align the build whose MMU test also asks for address errors on
|
||||
misaligned accesses.
|
||||
misaligned accesses; --slant the build with a slanted shaded triangle
|
||||
over the picture; --hscale that with the screen's renders through the X
|
||||
scaler as well.
|
||||
The image is the least the core's HLE BIOS needs to boot it: an IP.BIN
|
||||
whose bootstrap jumps to the boot file, and an ISO 9660 volume holding
|
||||
1ST_READ.BIN.
|
||||
@@ -822,6 +824,824 @@ ffffffff000020440000000017b7d1380000803f00000000ffffffff00000000
|
||||
0000f04317b7d138000000000000803fffffffff
|
||||
""")
|
||||
|
||||
# The program built with -DLIVE_SLANT (live_prog.c): a shaded triangle
|
||||
# whose edges slant across the pixels over the middle of the picture, for
|
||||
# the tests SSAA's resolve matters to (tools/vulkan/vk_hdr.sh --exact).
|
||||
PROGRAM_SLANT = bytes.fromhex("""
|
||||
01df02d02b40090000f0008c240e018c020005d119206b200e40543402004227
|
||||
01170b0009000900fefcffff020005d119205b200e4044340200422601160b00
|
||||
09000900fefcffff1b4429000b0009000344422642605a200224074402000116
|
||||
42160b00090002000b0009000e440b0009006a446a000b00090066446a004225
|
||||
0b0009006a000b000900020101e00b000e4100e00b000900034f01e00b00074f
|
||||
00e00b0009000900000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000000004d105d002600221420002704e402b00090009004440018c
|
||||
240000ff00000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000000016d0026116d229211ad208e522633031128908721045f98b
|
||||
13d33031068913d3392113d33b210be402a009000dd10ae411d33b2103a00900
|
||||
215109e45834111004510ed33921184408444b2114100cd22263017332223800
|
||||
2b000900000000ff00f0ffff00000010000000e000f0ff000000000c0040018c
|
||||
76010000ff03ffff4040018c220203d12e41fdff2e420b0009000900a800018c
|
||||
8df09df19df29df39df49df59df69df7830410f020f030f040f050f060f070f0
|
||||
3df05a000b0009005a440df24df21df25a000b00090048f44cf55af50b000900
|
||||
48f00b0009000af40b0009000dd10ed2222104710dd2222104710dd222210471
|
||||
0cd2222101e10cd212220cd200e3322204721222f0720ad33222147212220b00
|
||||
0900090000e000ac0100008000e1000c0920000100000001e86c5fa0106c5fa0
|
||||
00e0000c43631843436128411b234b23136418444b2304d210e132221041fc8f
|
||||
04720b0009000900000000a409d112610f92292108d307d42365336242661367
|
||||
636159217231028b10431042f68b0b000900ff030c815fa080841e0002d11260
|
||||
01910b001920ff030c815fa0862f962f224f436804d90b4909008230fb8b264f
|
||||
f6690b00f66809003c06018cf47ff361319221214d6229444c602d9323673927
|
||||
7b2011812c60128100e013815d6229455c6029233b2014812c6015810fd101e2
|
||||
20211871a0e220210dd20ed1206008c8018f1041fa8b0ad1106008c80989f362
|
||||
09d706e1256331271041fb8f01e00b000c7ffcaf00e0302000ff090084705fa0
|
||||
18705fa0a086010080705fa027d100e220210c71602163621942047120210871
|
||||
a0e2202122d223d1206008c8018f1041fa8b1fd1106008c8348d06e11ed34562
|
||||
21231041fb8b1ad21ad1206008c8018f1041fa8b16d1106008c8258d68261d8d
|
||||
536400e014d70174180063610a3101416362017202e33232078d017105a001e1
|
||||
194224041041098d027071622d62036301736233f48f2405f5af104107d11061
|
||||
0b0001e00b0000e00b0000e084705fa018705fa0a086010080705fa09c705fa0
|
||||
862f962fa62fb62f224f907f43680ae6f36572d472d00b400c750820018bbba0
|
||||
09e0fc840fc903886c8f01e0f3600c7002840188668f01e0f3600c7003840288
|
||||
608f01e0f3620c7225840c63284326840c6118613b2127840c600b21b9931c33
|
||||
b8922633018b9ea001e08828488d83605cd222621032018b97a002e00ee6f365
|
||||
59d457d00b400c750820018b8fa009e0f3600c700184118801898aa003e0f360
|
||||
0c7004840188018985a003e0f3600c7005840288018980a003e0f3620c722b84
|
||||
0c6328432c840c6118613b212d840c622b217e922c317d922631018b6fa003e0
|
||||
64e6f36541d43ed00b400c750820688df365f36a107af36800eb6c9414a00ce9
|
||||
38d2122248a0090010420a8d0177346040c8f98d7b6043610c416f841b20f3af
|
||||
6f801049088d087ab0280178a36300e78366f076ebaf08e200e12dd64c940ca0
|
||||
0ae01c311042068dff736821f9891c314a21f7af1d611040068954622c621842
|
||||
2a217363f1af7362f06001882b8bf36001840288298b1fd22a21f362fa840c62
|
||||
136319433032228ff3622b840c621c611032ffe00a600840707f264ff66bf66a
|
||||
f6690b00f668f7af0900f5af0900f3af0900f1af0900efaf0900edaf0900ebaf
|
||||
0900e9af09e0e7af04e0e5af04e0e3af04e0a8fd2b018000211009008031018c
|
||||
ec06018c1480018c7431018c6831018c00800000ffff00000ad1422104715221
|
||||
01e109d21222087212220472122207d1226001c8018d1041fa8b05d1126001c8
|
||||
0b00290004745fa00c745fa000093d0018745fa0626113671947014725922821
|
||||
ffe22a62436300432903136001402444136019407a2001c8108943605c302a23
|
||||
063429073a2773611841236318433c333b21203729022b210b00122643605830
|
||||
2a2346302907eeaf3a27000249d1126249d11032048d00e248d122210b0000e0
|
||||
47d148d2122248d221521032718b47d112600188028d11e00b00090044d345d1
|
||||
3111047144d2292144d645d772166c921b222316726230325d8f00e341d23222
|
||||
736301e77223226360922033558b39d2215337d22033df8f13e03bd23bd33112
|
||||
3bd334d733173bd773123bd226164e921b22271639d222623032cd8f16e038d2
|
||||
2dd3392243932b23371624d305e7722332d332672fd33037318b32d32fd73227
|
||||
29d7735730372c8b22d3335728d33037b28f18e02cd778162a977b2119162bd1
|
||||
01e332212ad1126321d11033a48f19e025d338167b22291624d102e2222124d1
|
||||
126220d110320e8f00e220d122210b0001e00b0011e00b0012e00b0013e00b00
|
||||
17e00b0018e00b001ae01601c0003601340109000000001044332211100000ff
|
||||
88776655040000100050018c4040018c5555aaaafc5f018c00f0ff1f0040018c
|
||||
001000104440018cfc6f018c0df0ad0bb0b0b0b0c0c0c0c00030001008300010
|
||||
0070018cc1c1c1c100400010000000ff08400010862f962ff45110d2222210d8
|
||||
422810d0522010d4122410d5622510d6722610d7122710d3f25992238302f359
|
||||
9222122800e11220122412251226122712238302f6690b00f6680900000000e0
|
||||
040000e0080000e00c0000e0100000e0140000e0180000e01c0000e0862f962f
|
||||
a62fb62fc62fd62fe62f224ff07f536b636a7369fd5e2ad11b24431f29dd422d
|
||||
00e829d1822129d282220871822108728222087182210872822208718221830d
|
||||
e21f611f722f22dcfc575366a3650b4cb364e21ffc52211f922f2367b366a365
|
||||
0b4c93641bdee21fa11f922ffc57b366a3650b4cb364f351122d17d112d21222
|
||||
12d182210872822208718221087282220871822108728222830de21ffc51111f
|
||||
922f1367b366a3650b4c9364107f264ff66ef66df66cf66bf66af6690b00f668
|
||||
00000081000000e0040000e0080000e0b40b018c0000803e00000024224ff87f
|
||||
f351111f722f6367536643650cd10b4100e40cd200e112220bd3122304731223
|
||||
04731223047312230473122304731223047312238302087f264f0b0009000900
|
||||
1c0c018c000000e0040000e0862f962fa62fb62fc62fd62fe62ff75cf85bf95e
|
||||
24d14b2124d2122224da25d1122a25d9522925d8622825d000e1122024d51225
|
||||
24d6122624d312238302436d2b2dd222b22ae229c22812201225722612238302
|
||||
d222b22afb5bb229c22812201bdbb225722612238302d222fa5dd22ae229c228
|
||||
b220122572261223830215dddb244222fa54422afb5dd229c228b220b2257226
|
||||
12238302f66ef66df66cf66bf66af6690b00f66800000080000000e0040000e0
|
||||
000000c0080000e00c0000e0100000e0140000e0180000e01c0000e00000803f
|
||||
000000f0862f962fa62fb62fc62fd62fe62f224fbc7fc07f9bd112619bd22665
|
||||
266622679ad2266322625b216b217b213b212b2144e0160f96d11060fec90021
|
||||
ffe295d322230473222300e204732123106001cb002191d1126091d3392005cb
|
||||
022118718fd33221f471222110718ed222216c718dd222219c718dd222210471
|
||||
8cd2222110718cd222218cd18cd212228cd212228cd18dd222218dd600e38dd8
|
||||
8dd412e745330a02094223611c3113652c355c353369583953609c3008408e01
|
||||
122601731047ed8f047684d184d2222184d185d22221047184d22221047184d2
|
||||
222184d1c59222210471c392222104711fe222210471be9222217fd27fd310e1
|
||||
32221041fc8f04727dd1b59222213c717cd222210871077222217bd27bd3ac91
|
||||
32221041fc8f047279d17ad77ad310e27221a3961c3632261042f98f047177d1
|
||||
77d2222104719a92222176d276d310e132221041fc8f04721fe174d2122274d2
|
||||
122274d100e002ea00e973d807e41fe58697869317e6d62f019d230df66df420
|
||||
1043058d017726657035f989f8af63616ad227536ad22033648d48e001e1160f
|
||||
10e168d212220472122267d267d30ce132221041fc8f047200e163d212220472
|
||||
122263d163d2222163d164d2222164d12e4164d1ffe700e308e2722131111042
|
||||
fb8f08715fd360d1122360d260d1292148977b2111135fd1122200e111125ed2
|
||||
12225ed212225ed105e222215dd00b40090040e7fc3700175bd1eee233932021
|
||||
5ad71c3720275ad71c37202759d71c3720271043f38f017157d458d00b4005e5
|
||||
082001ee028de61fb4a0090054d00b40090054d454d10b41092454dcc36dc51f
|
||||
bda200ee52d2205335d22033978996af01e1007ce003ff7f8001800000101f7c
|
||||
e00700f836010048846c5fa0f46c5fa0c0785fa00400d8ff0800d8ff44805fa0
|
||||
000080003f7d1700000020000401150000007f020000df0177df270000001000
|
||||
20805fa028815fa08c805fa0000000030c0010a5f831018cabaaaaaa88805fa0
|
||||
17b7d138000010a500000002000080200000003004905fa0001000a403030303
|
||||
74805fa000ff000000825fa080800000002006a4050505050606060614905fa0
|
||||
1ffc0000000006a4070707071c985fa01c9c5fa0004006a4ffff0000c040018c
|
||||
11111111380000ff000018a500000080180018a54c0e00a02c805fa000001800
|
||||
a800018c0040018c000000100050018c00f0ff1f443322114040018c000000ff
|
||||
100000ff2c0a018c000023ac0000ffff0000feff0000fdff5eb000006c06018c
|
||||
6600018cff7fffff6c00018cc031018c0041018cbd9562d462d00b4009000820
|
||||
028fe61f42af09005fd460d00b4005e50820018ba3a002ee5dd8ab9b59da5dd9
|
||||
b3650b4a83640820018b9aa002eea1900c389038f58fb36553d454d00b4008e5
|
||||
0820018b8fa003ee959553d44dd00b4009000820028f10e187a003ee4fd650d2
|
||||
20677c6764633c633037028d10417ea004eef58f01724bd17b9210677c674ad3
|
||||
1c3330633c633037028d1042a8a005eef38f017145d16c9210677c6744d31c33
|
||||
30633c633037028d10429ba006eef38f017135d435d00b4002e50820018b93a0
|
||||
08ee3cd13cd2222104715592222101e13ad21222087212220472122238d12260
|
||||
01c8018d1041fa8b36d1126001c8028ffc717ba009ee00e222210471126001c8
|
||||
018975a00aee30d1379202a009000c8d017110677c672dd31c3330633c633037
|
||||
f58d10420beeb1aee61f29d110611c61249220315e8f0cee26d110611c612031
|
||||
5a8f07ee24d110611c612031568b23d110611c612031538b00ee97aee61f95ae
|
||||
e61f93aee61f91aee61f8faee61f8daee61f00280004004000180010ee000900
|
||||
0000200c9809018c5eb000006c06018c0000210c0028210c0000220ce831018c
|
||||
000020ac000021ac0000ffff000022ac0000feff04745fa00000230c0c745fa0
|
||||
801a060018745fa0000023ac0000fdff001023ac002820ac002821ac004022ac
|
||||
54aee61f52aee61f50aee61f4eaee61f4caee61f4aaee61f48aee61f46aee61f
|
||||
44aee61f017993600888038f936800a1017e936807e00d4846911928936001c9
|
||||
0b2870e0860fd26af553326bf3667076b3651ed70b47a364071ff36778778366
|
||||
b3651bd00b40a36440e2fc322e51f7501030318f70e02f5127922921fe022031
|
||||
028de82ed1a001eecc8ff366860f7076a3650ed70b47a364036bf36678768365
|
||||
0cd00b40a36440e2fc322e51103b0189bda002ee2f51089339212c522031b28d
|
||||
017902ee0aa0e51f00030103d409018c1000018c2c00018c01eee51f59d10b41
|
||||
00e859d00b400900036158d956db0b4b136aa230058f0361a030ffe22a381049
|
||||
f58b63e1163801ee028fef1f07a209004fd850d1122850d10b41090082624fd3
|
||||
4ad1326001c8018d1041fa8b4bd11261136001c9081f136001c8018910a202e0
|
||||
43d1126343d11033018b0ba203e040d1126040d11032038dff88018904a201e0
|
||||
3bd11260ff885e893ad222213cd13dd2222104713cd222210471629222213bd1
|
||||
3bd22221147101e2222113622fd1226001c8018d1041fa8b2dd112611c611360
|
||||
0688018909a204e029d22260294019403088028d747202a204e022632dd22033
|
||||
0189fea105e022d222d3322224d22ad33222047224d33222047228d332220472
|
||||
27d33222047227d3322227d727d320e2322701731042fb8f04771cd21cd33222
|
||||
147201e33222236310d2326001c8018d1042fa8b0ed22260ff88048922600c60
|
||||
07880089181fa0a1090057afe51f55afe51ff5500470051fe3600a882889f8ae
|
||||
00e902200c06018c3c06018c80841e0000e100ac785634128c05018c186c5fa0
|
||||
00e000ac0000008000e1000c046c5fa000e0000c56657273220000800c010022
|
||||
000000020000006414e000ac0000dec0047d73d1103d018912adc51f71d8836c
|
||||
057cf36a547a70db84600c69ab80f3640b4b5f74036168e0982929022031028d
|
||||
160f19a103eeab840c61c8909b201030028dc03812a103eee68b64d8836e147e
|
||||
63dd64dc64db65da0b4d0900051f8669f36678769365f3640b4c747440e3fc33
|
||||
3e52f361707110320189f9a004eef3617471a490fe0210320189f3a004ee3c52
|
||||
f5512a219a21b9213f533a22a9222b211821028de038e7a004eed58b50d00b40
|
||||
f36b036a4fd9936e187e4fdd6c7b4fdc96680b4d83640038028d02e0d6a005ee
|
||||
0a2868e0860fb365f3640b4c68740038028d40e2cca006eefc322b51b031028d
|
||||
903ec7a006eee38b41d1181241d1191241d93dd80b48936440dbf3640b4b6074
|
||||
3fd40b4807eef3640b4b64740b489364f3643cd10b41687440e7fc377a527851
|
||||
1032478fe51f36d11a17f3656c75f3642ed00b406874f36432d10b41687440e1
|
||||
fc311a521951103208ee338fe51f2ed00b4009ee01882d8fe51f2cd00b400aee
|
||||
0188278fe51f2ad483600b400bee20d428d00b40090028d110301b8fe51f27d4
|
||||
24d00b4009000188148fe51f24d140e0fc30181000e11a10f3656875f36421d1
|
||||
0b41607440e3fc333a52385110320cee028de51f42ae0900a36435a083608000
|
||||
e831018cb831018c4800018ca431018c6600018c5000018cf2830070f3830070
|
||||
8400018c8c31018c7200018c7a00018c0000803f00000040010004008005018c
|
||||
010024008605018c8a00018c9800018c01000c006805018c000080bf01000080
|
||||
785634127605018c0b40090044d800e1122844d10b41090082627e9110320dee
|
||||
088fe51ff36440d00b4068740788138f00eee51ff2ad0900f0ade51feeade51f
|
||||
ecade51feaade51fe8ade51fe6ade51fe4ade51fe2ade51f0eeedfade51f33d9
|
||||
926833d10b41090064e1122931d120e22221136230d1226020c8018f1041fa8b
|
||||
2ed00b40090029d182212ad120e2222103619c7102e2263129011c31d8ad1f1f
|
||||
03a0081f01a0081f081f25d1126425d125d22363136600e020e7336528354075
|
||||
5026017600231047f78f01731cd31fd77223dc7300e772231dd7122704772227
|
||||
047710e662271997722323651075136000eee71f01e808a010e3d6af081fd4af
|
||||
081fd2af081f1043248924666c6604677c677036f789f6af871f800111540900
|
||||
4440018c2c05018c4005018cc8805fa00c06018c00695fa080841e003c06018c
|
||||
4000a0ff9040018c7040018c018200001000a0ff6ed220622822038901922302
|
||||
09003e166bd2226210711032228df75ee82e018f03eee71f67d268d112220171
|
||||
111267d100e332213111321133113411351164d732275fd32223136504731223
|
||||
047304e66223a893322710715bd004e813a004e35cd112615031d98ff75e5bd1
|
||||
12611821d48ff75e56d1126002c8d38fe82eceaf090010430789f75ee82efa8f
|
||||
56660036f789f6af871f4dd334533823048ff75e47d3326330322589e82e2a8d
|
||||
05ee00e247d122212471422148d149d33b2149d3222349d249d7222732632033
|
||||
1b8d00e244d3222341d3222345d222213263203301ee248fea1f126241d11032
|
||||
1b8ff3611fa0787137d222621032d58ff75ed7af00e2d4afe71f726337d22033
|
||||
ffe22a622a1f00e233d3222330d3222334d2222132632033df89fa5eeb610271
|
||||
1a1ff3617871399221213890118158e012810fe0138133901481329015812ad1
|
||||
00e220211871a0e2202128d228d1206008c8018f1041fa8b24d1106008c81a8d
|
||||
09eef362787223d306e1256771231041fb8b21d10fe2222120d1139222210471
|
||||
f072222100e11ed30d940d950d961dd80c994aa000e2ecafe61f314420010002
|
||||
000383001f0fff0077772c01a10f09008040018c1000a0ff6840018c0100feca
|
||||
5040018c1c00a0ff1400a0ff1800a0ff4c40018c000000e0000014a50df0ad0b
|
||||
000014e52143341284705fa018705fa0a086010080705fa0002870a0402070a0
|
||||
000081a04b1714060a071360783001400c37f5e00d4797071a0013670837d59e
|
||||
ec3771230172027361714632ec8f85315123017202736032f78f617100e16cd2
|
||||
1222047212220472c193322204721fe332220472bc9332220472122204721222
|
||||
0472122263d1b4922221047160e2222161d100e0ae9500e6ad97ad935fd25630
|
||||
d62f019d230df66d0814612101707030f58f027100e15ad21222047212220472
|
||||
9993322204721fe3322204729093322204721222047212220472122204728c93
|
||||
3222047248e3322288924ed32223047322230473222304732223047322234ad2
|
||||
12220472122249d17992222148d600e7769048d47598759373620922236106e5
|
||||
5d412c311c312c3145310a021365283501455c321942094287021a022831629e
|
||||
ec31112601771043e68f027600e13ad212220472122204724d93322204721fe3
|
||||
322204724493322204724d933222047212220472122231d13b922221047160e2
|
||||
2221d87141922221f65007e11d401fcb40e2fc32061200eeeb1fee1fed1fffee
|
||||
ec1f00eee91f92a700e8188d5a884d8f648823d12a9222210190230083609012
|
||||
20d10b4102e4ffa109001ed10b4103e4faa109001bd10b4104e4f5a109001ad1
|
||||
15922221019023008360641230f800011f3c1f0fff07001070170f0f00190242
|
||||
ff0fcf07011019fc00780342e003e07f040070a0240070a0000082a090e80000
|
||||
840070a0ac0070a0c00070a0800070a0000083a06b6f4606040170a0240170a0
|
||||
1c985fa0e405018c10905fa002890c911038138b06d107d2222183606488178b
|
||||
05d10392222113a00900c8001f7c0900000070a001c200001c9c5fa0e7911038
|
||||
0389019023008360b01173d173d2222173d174dc122c74d1126340e2fc323312
|
||||
72dee2644412c265551201e2222120e1122e6fd1122c6fd16fd612266fd71227
|
||||
6fd170d0122070d1141f131f00e9921f911f6ed2222f6eddba9700e66dd50b4d
|
||||
00e46ddbb41fb31f921f911f6bd1122f6bd700e667d50b4d00e46ada922a6ad3
|
||||
92236ad492246ad592256ad692266ad792276ad092206ad19221830affe369d2
|
||||
322210e1122e68d1122c68d152d4122452d5122552d753d67226b41fb31f921f
|
||||
911f52dee22f62d700e652d50b4d00e4922a55d0922055d1922155d2922255d3
|
||||
922355d4922455d5922555d69226830affee54d7e22757d112611821018b5ca1
|
||||
01e255d1126177e22631028f01717ba1090051d2122251d112600820018bd9a1
|
||||
090009e11630018b1ca20a8801704bd102212dd14ce0fe044221047150e0fe05
|
||||
5221147154e0fe066221087144d22221047144d2222144d111600d6043d11161
|
||||
1f88028f1d6114a2090041d641d240e1236740e361271043fc8f027729901041
|
||||
f68f0c322691163829023bd1088f222119d13ad222211e911038018b38d11061
|
||||
18d117d2222134d112611821018902a2ffe718de33dcc41f13d1131f32dbb21f
|
||||
32ddd11f11daa22f11d961a0ffe7a0000080000103010601000070a001820000
|
||||
0000200060805fa048805fa04c805fa00000700100007f0068805fa06c805fa0
|
||||
0000008044815fa0000000430000003f4c0d018c00008020000080429a99193f
|
||||
ff0000ff000000e0040000e0080000e00c0000e0100000e0140000e0180000e0
|
||||
1c0000e014805fa00000740100003f0000ff00ff2480018c2080018c1880018c
|
||||
00007f020000df01140a70a4c80a70a400f80000804070a42880018c0000c700
|
||||
010071a00000dc4200008c420000004200e6c3940b49e365c41f61d1131fb21f
|
||||
60d1111fa22f60d760d5b7940b4900e6c41f5fd1131fb21f5ed1111fa22fffe7
|
||||
5dd6ac940b49e3655cd1141f5cd1131f5cd1121fd11fa22fffe700e65ad50b49
|
||||
00e45ad1141f5ad1131f5ad1121f5ad1111fa22fffe759d659d50b4908e459d1
|
||||
59d2222159d25ad332220472e222047200e33222047257d33222047232220472
|
||||
322204723222830100e048dd52dc13634edb52da52d953d400e253d563a104e1
|
||||
1638018b43a7836050d151d2222151d1ffe2222150d10b41090050d110600fc9
|
||||
0688018b34a509004dd1126118211f894cd1126118211b8f0820028d09e198a5
|
||||
01e240e4fc341e141f1447d1126004e700e600e5f3640b40787478e0fe011821
|
||||
028d01e241d1222141d222610171122213a583603fd12cae09003fd122213fd2
|
||||
222c32d132d22221b41fb31f921f911f2bd1122f3ad700e63ad50b4d00e4922a
|
||||
22d29222047292220472922204729222047292220472922204729222830a25d1
|
||||
ffe2222187ae09002fd111611d612fd00031f7892ed101e27dae222180008800
|
||||
0000304300001043ffffff800000908000009043000040430002003000005c42
|
||||
0000c0420000f0410000002000002f43000096430000fa4200007a4300000e0c
|
||||
24008020000000e020000080040000e0000000c00000803f000043430c0000e0
|
||||
0000003f100000e0180000e044815fa00000008014805fa08c05018c8c705fa0
|
||||
1080018c0880018cbc00008c0080018c0c80018c000020002480018c00007801
|
||||
ff00ffff00008020280a78a41ff800001c80018c54daa26c54d1cb21122a54d1
|
||||
10e22221147153d2222153d153d212220472122252d153d2222153de53dbb41f
|
||||
53d1131f00e9921f911f52d1122f52dd869700e6e3650b4d00e4b41fb31f921f
|
||||
911f4ed1122f4ed700e6e3650b4d00e44cd192214cd292220472922204729222
|
||||
04729222047292220472922204729222830146d1ffe22221c22a45d101e22221
|
||||
e7ad0900fc8b43d111600d60407111611f88078d1d6140d101e222213cd10be2
|
||||
d7ad22214d922c313cd33821f689f2af090046977c3139dee821068b36d11261
|
||||
1821058936d6e1ad090035d6dead09003896dbad090033d1141f33d1131f33d1
|
||||
121f33d1111f33d1122f00e61ed522d10b4100e4edad090029071ceeed473b27
|
||||
722340e7fc377357722b2bd76227922a22240c77222729dee225087722278303
|
||||
1041518d017002c840e6fc36d3160089c31601c822d6df8d038822d6ddaf2907
|
||||
00802004e0070900f4805fa0000001004c805fa000007c0100003f0068805fa0
|
||||
44815fa0000000800000802000008042000000430000003f4c0d018c9a99193f
|
||||
ff0000ff000000e0040000e014805fa01880018c200a7ca41c80018cdfff0000
|
||||
00f800000000484300809f4300007042000052436666663f080000e00000803f
|
||||
0000574300006b4385daa41f85d1131f85d9921f85d1111f85dee22fffe785d6
|
||||
85d586d00b4008e4a41f85d1131f921f84d1111fe22fffe783d684d57fd10b41
|
||||
08e483da83d4422a83dd84d2222d84db84d1122b84dc85d6622c00e984d39223
|
||||
84d5922584d7922784d09220830ab22a83d1122d83d7722be22c92239225ffe2
|
||||
087322239220830ab22a122d7ed3322be22cfc7592257dd1f870122008752225
|
||||
08709220830ab22a79d0022d722be22cf8751225047592250475222504759225
|
||||
830a74d5522a022d322be22c68d01220047012200470222004709220830a422a
|
||||
5ed4422d6cd4422b622c61d69226f870922061d492240c769226830ab22a67d6
|
||||
622d722be22cfc709220fc7492240870222008749224830ab22a622d322be22c
|
||||
53d69226fc701220fc7422240c769226830ab22a5ad6622d722be22c4cd71227
|
||||
9220222408709220830a522a622d322be22c122747d3122322249220830a51d2
|
||||
241f131f621f50d1111fe22fffe737d5559432de0b4e00e64cd1122a37d0022d
|
||||
32d1122b4ad1122c30d339d232222ed538d4522438d6922638d79227830a00e3
|
||||
00e2c36b636affe9736421a004e5236740d141dc236641dddb2725dd722d26de
|
||||
022e27d0c2201ad7722b29dc122c29d76227922a2224830d122d622e9220222b
|
||||
222c2227222a2224830d10456c8d017302e1336002c8028d3921c0a401c801c8
|
||||
01897da403882ed01821d08f13672adcd1af13662ad027d12adcccaf13668000
|
||||
00006b430000f04100005743000020410000003f00c00034002080204c0d018c
|
||||
00005c4200000c4200c0003600008020000000e008000080040000e0000000c0
|
||||
080000e0002480200c0000e000c80088100000e0140000e0180000e01c0000e0
|
||||
0000f0420000e041000050420000004300002043080000f00004802000002443
|
||||
000040430000604300008042c8000080000200300000803f00005643c80000e0
|
||||
0000484300006c43d36abdd1122de36dbcd1122e036cbcdee220bcdb00e9922b
|
||||
087092209227bad29222bade922e830aa22ab9d1122db9d1122cb9d1122b9220
|
||||
9227b8d2b2d42224922e830aa22ab6d2222db6d2222c122b92209227b4d22224
|
||||
922e830ab3d2222ab3d2222db3d2222c122b92209227b2d11224922e830a922a
|
||||
922d922c922b922092279224922e830aacd5add6611fadd1122fadd75366add0
|
||||
0b4000e4a8d1111fabd1122fabd7acd6acd5a8d20b4200e4abd1122a922d922c
|
||||
922b02e2a9d3222306e1a9d4122490d52225122e830a9cd6611fa2d7722fa5d7
|
||||
a5d6a6d5a6d49bd00b400900922a922d922c922b9dd192219dd2922284d39223
|
||||
922e830a9fd4441f9fd1131f9fd5521f9fd6611f9fd7722f9fd6a0d5a0d4a1d0
|
||||
0b40ffe797d1141f9fd1131f97d2221f9ed1111f97d3322f9dd698d598d499d0
|
||||
0b40ffe7922a922d922c922b87d1922187d292226ed39223922e830a95d4441f
|
||||
8bd5531f94d6621f94d7711f94d0022f94d795d595d48bd10b4100e68dd2241f
|
||||
93d3331f8cd4421f92d5511f92d6622f92d78dd58dd483d00b4000e6922a922d
|
||||
922c922b71d1922171d2922258d39223922e830a8ad18bd222218bd1141f8bd1
|
||||
131f8bd1121f8bd1111f8bd1122f8bd700e64dd573d00b4000e461d1141f88d1
|
||||
131f7bd2221f87d1111f6ad3322f86d786d582946bd00b4000e6922a922d922c
|
||||
922b5ad192215ad2922241d39223922e830a7fd4422f7fd77fd680d580d481d0
|
||||
0b4009007ad180d780d681d581d47dd20b42122f4ad3341f55d4431f64d5521f
|
||||
5ed6611f5ed7722f5ed75fd55fd455d00b4000e642d1141f5dd2231f221f5dd3
|
||||
311f5dd4422f5dd757d558d44dd00b4000e6922a922d922c922b3cd192213cd2
|
||||
922223d39223922e830a6bd1ffe22221349110380189adab090068d268d12260
|
||||
01c8018d1041fa8b66d167d2222167d167d22221047167d22221047166d22221
|
||||
047142d22221047164d2222164d365d220e1222301721041fb8f047362d163d2
|
||||
2221147101e22221136255d1226001c8018d1041fa8b80ab0900800096000900
|
||||
02000080000000c0000080200c0000e0180000e01c0000e0333321426666e742
|
||||
1f856b3f1010e0ff9a19164366e64d4310e010ff000000f0cd4c914333330243
|
||||
e01010ff0000a0420000403f0000c842000070431c0c018c00006f4300007443
|
||||
0000524300005c4300000020100000e0140000e0000000430000444300008042
|
||||
0000020000005c42000068430000f041000048430000003f00c4003000009020
|
||||
080000044c0d018c00008d4300007a4300c6003000002a430000024300000c43
|
||||
9a99193fff0000800000909400000002000034430000f0429a99993e0000ff80
|
||||
60815fa0000000800000d84200008c420000be42000020423333333fffff00ff
|
||||
0000964300008043ffffff80000090806666663f0000d442000082420000c242
|
||||
00003442fc0c018c00004d4300009143000039430000874314805fa0186c5fa0
|
||||
80841e0000e100ac7856341200e000ac2200008000e1000c0c01002200000065
|
||||
14e000ac0001dec0046c5fa000e0000c63d222610171122283603c88028f4288
|
||||
a9a00900048ffb5ee82e018ba8a009005cd10b4109005cd10b4110e45bd11262
|
||||
83639c73aa911633028ff951c6a009002831fc5e163e008b1c1ffd5e123e0089
|
||||
1d1ffe5e1c3eee1f291f00e148e0fe022822038d1821018922a10900028d3fe1
|
||||
12a1fd521638018bc2a08360017883603c88028f3ce17da809001638018b64a8
|
||||
46881e88028f2d886aa80900028f0f886ba8090001899fa183603dd10b4101e4
|
||||
836208422c3208428c32184209428c326591192283603fc9036108410c311841
|
||||
34d33c3134d321211043fc8f027151aa090032d1222100e131d210220c720ae3
|
||||
3022047210222fd1a0e220212ed22fd1206008c8018f1041fa8b2bd1106008c8
|
||||
238d13e26871212100e221210ae3312121212121212124d224d1206008c8018f
|
||||
1041fa8b20d1106008c811896871116211601162116211611ad220620fc91840
|
||||
1c610b211ad257af12221ad1faaf090018d1f7af090018d00b4000e404a00b1f
|
||||
15d00b4001e40b1f06d10b41090006d10b4110e405d1126267af291f9500ff7f
|
||||
1080018c0c06018c4c06018c0c00d8ffe405018c000000a500a000000880018c
|
||||
84705fa09c705fa018705fa0a08601000480018cffff0000a007018caa911038
|
||||
1f8ff55ee82e1c8956d1a493322156d1ec31291f55d2122255d112611821078d
|
||||
8360226253d11032038f01c8c2a00ae201c8018be1a009004fd150d2122236af
|
||||
017887911038b78fce71fd53fc5ee8331633268dfe5e4ad3ec337d911633268d
|
||||
44e0fe000820278df65e3ed175933221291ffe5e42d2ec326e9116325e8d44e0
|
||||
fe0008205d8ff65ee82e5d8f48e0fe0008205c8fff5ee82e278df85039d1b9af
|
||||
ec3130d15a93322137d1b3af291f2dd155933221ddaf291fe82e0e8d58e029d1
|
||||
fe000221291ffd52fc5ee832449116322dd19f8dfe5ecdaf0900291fd6ae01e1
|
||||
20d13d922221efaffd520820038df75e26d18faf0c31e82e028925d18aafec31
|
||||
fa5ee82e028923d184afec31fb5ee82e038d40e020d17dafec3101e1fe021732
|
||||
038f40e01dd175af2c31fe000188028910d16faf09001ad16caf090019d169af
|
||||
090019d166af090018d163af090018d160af0900fa00e003c8001f7c007cff03
|
||||
007e090010905fa00001d0ba4840018c1080018c0d600d600000400050805fa0
|
||||
43c721fe0008d0ba0200d0ba0009d0ba000ad0ba000bd0ba000dd0ba0007d0ba
|
||||
4d4d0d600300d0ba0400d0ba0500d0ba0600d0ba5bd11261c971263112895ad1
|
||||
12611821138959d11262a9911032028957d108a0090057d1126118210a8956d1
|
||||
01a0090055d156d2122221af836055d1f9af090054d1f6af090054d11daf0900
|
||||
29071ce61821028d6d4783ab090050d050dc51d64fab090003c903880189bfa8
|
||||
3fe13fe11638028d83605aae836201c8018befa8090049d1019c230c090034ee
|
||||
47d222621071203102ee068fe71f45d11261503102ee048de71f019223020900
|
||||
b8e9019123010900f6e93360038829071ce11d473cd038d136dc1cab1366f48f
|
||||
182139d041ab09004121017002715630058f20c8d62f019d230df66deeebf38f
|
||||
2364f1af336401a093628362212101700271a630f78f0388f78d46302c8f6630
|
||||
2c8b312101705888f38f027127d12892222127d227d1292127d33b2113662367
|
||||
e07726d518e352271043fc8f047724d30ce77223fc7310e7722322d708e37221
|
||||
01771043fb8f047183061ed700e101e60195230508e3b0dec8af5362c6af7362
|
||||
280680000c80018c0880018c0480018c030cd0ba0080018c040cd0ba010cd0ba
|
||||
4840018c020cd0ba9d5a0d60000020000000484300006c430000803f00004000
|
||||
1000a0ff1400a0ff000070431c815fa0e040018ce0ffff03000000e011111111
|
||||
3c0000ffe0ffc000400000006400000000000000400100000e00000000000000
|
||||
100000000a0000000000000001000400000004000300040001000c0001002400
|
||||
01000400010000000200000000010000000200000303000000017f80ff000000
|
||||
000000000100000002000000ffffff7f0000008001000080ffffffff78563412
|
||||
efbeadde000001005345474120534547414b4154414e41200000000000000000
|
||||
17b7d1380000000000000000ffffffff000020440000000017b7d1380000803f
|
||||
00000000ffffffff000000000000f04317b7d138000000000000803fffffffff
|
||||
""")
|
||||
|
||||
# The program built with -DLIVE_SLANT -DLIVE_HSCALE (live_prog.c): the
|
||||
# slanted triangle, and the screen's renders through the X scaler, each
|
||||
# pixel written the average of a pair drawn (tools/vulkan/vk_hdr.sh --exact).
|
||||
PROGRAM_HSCALE = bytes.fromhex("""
|
||||
01df02d02b40090000f0008c240e018c020005d119206b200e40543402004227
|
||||
01170b0009000900fefcffff020005d119205b200e4044340200422601160b00
|
||||
09000900fefcffff1b4429000b0009000344422642605a200224074402000116
|
||||
42160b00090002000b0009000e440b0009006a446a000b00090066446a004225
|
||||
0b0009006a000b000900020101e00b000e4100e00b000900034f01e00b00074f
|
||||
00e00b0009000900000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000000004d105d002600221420002704e402b00090009004440018c
|
||||
240000ff00000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000000016d0026116d229211ad208e522633031128908721045f98b
|
||||
13d33031068913d3392113d33b210be402a009000dd10ae411d33b2103a00900
|
||||
215109e45834111004510ed33921184408444b2114100cd22263017332223800
|
||||
2b000900000000ff00f0ffff00000010000000e000f0ff000000000c0040018c
|
||||
76010000ff03ffff4040018c220203d12e41fdff2e420b0009000900a800018c
|
||||
8df09df19df29df39df49df59df69df7830410f020f030f040f050f060f070f0
|
||||
3df05a000b0009005a440df24df21df25a000b00090048f44cf55af50b000900
|
||||
48f00b0009000af40b0009000dd10ed2222104710dd2222104710dd222210471
|
||||
0cd2222101e10cd212220cd200e3322204721222f0720ad33222147212220b00
|
||||
0900090000e000ac0100008000e1000c0920000100000001e86c5fa0106c5fa0
|
||||
00e0000c43631843436128411b234b23136418444b2304d210e132221041fc8f
|
||||
04720b0009000900000000a409d112610f92292108d307d42365336242661367
|
||||
636159217231028b10431042f68b0b000900ff030c815fa080841e0002d11260
|
||||
01910b001920ff030c815fa0862f962f224f436804d90b4909008230fb8b264f
|
||||
f6690b00f66809003c06018cf47ff361319221214d6229444c602d9323673927
|
||||
7b2011812c60128100e013815d6229455c6029233b2014812c6015810fd101e2
|
||||
20211871a0e220210dd20ed1206008c8018f1041fa8b0ad1106008c80989f362
|
||||
09d706e1256331271041fb8f01e00b000c7ffcaf00e0302000ff090084705fa0
|
||||
18705fa0a086010080705fa027d100e220210c71602163621942047120210871
|
||||
a0e2202122d223d1206008c8018f1041fa8b1fd1106008c8348d06e11ed34562
|
||||
21231041fb8b1ad21ad1206008c8018f1041fa8b16d1106008c8258d68261d8d
|
||||
536400e014d70174180063610a3101416362017202e33232078d017105a001e1
|
||||
194224041041098d027071622d62036301736233f48f2405f5af104107d11061
|
||||
0b0001e00b0000e00b0000e084705fa018705fa0a086010080705fa09c705fa0
|
||||
862f962fa62fb62f224f907f43680ae6f36572d472d00b400c750820018bbba0
|
||||
09e0fc840fc903886c8f01e0f3600c7002840188668f01e0f3600c7003840288
|
||||
608f01e0f3620c7225840c63284326840c6118613b2127840c600b21b9931c33
|
||||
b8922633018b9ea001e08828488d83605cd222621032018b97a002e00ee6f365
|
||||
59d457d00b400c750820018b8fa009e0f3600c700184118801898aa003e0f360
|
||||
0c7004840188018985a003e0f3600c7005840288018980a003e0f3620c722b84
|
||||
0c6328432c840c6118613b212d840c622b217e922c317d922631018b6fa003e0
|
||||
64e6f36541d43ed00b400c750820688df365f36a107af36800eb6c9414a00ce9
|
||||
38d2122248a0090010420a8d0177346040c8f98d7b6043610c416f841b20f3af
|
||||
6f801049088d087ab0280178a36300e78366f076ebaf08e200e12dd64c940ca0
|
||||
0ae01c311042068dff736821f9891c314a21f7af1d611040068954622c621842
|
||||
2a217363f1af7362f06001882b8bf36001840288298b1fd22a21f362fa840c62
|
||||
136319433032228ff3622b840c621c611032ffe00a600840707f264ff66bf66a
|
||||
f6690b00f668f7af0900f5af0900f3af0900f1af0900efaf0900edaf0900ebaf
|
||||
0900e9af09e0e7af04e0e5af04e0e3af04e0a8fd2b01800021100900ac31018c
|
||||
ec06018c1480018ca031018c9431018c00800000ffff00000ad1422104715221
|
||||
01e109d21222087212220472122207d1226001c8018d1041fa8b05d1126001c8
|
||||
0b00290004745fa00c745fa000093d0018745fa0626113671947014725922821
|
||||
ffe22a62436300432903136001402444136019407a2001c8108943605c302a23
|
||||
063429073a2773611841236318433c333b21203729022b210b00122643605830
|
||||
2a2346302907eeaf3a27000249d1126249d11032048d00e248d122210b0000e0
|
||||
47d148d2122248d221521032718b47d112600188028d11e00b00090044d345d1
|
||||
3111047144d2292144d645d772166c921b222316726230325d8f00e341d23222
|
||||
736301e77223226360922033558b39d2215337d22033df8f13e03bd23bd33112
|
||||
3bd334d733173bd773123bd226164e921b22271639d222623032cd8f16e038d2
|
||||
2dd3392243932b23371624d305e7722332d332672fd33037318b32d32fd73227
|
||||
29d7735730372c8b22d3335728d33037b28f18e02cd778162a977b2119162bd1
|
||||
01e332212ad1126321d11033a48f19e025d338167b22291624d102e2222124d1
|
||||
126220d110320e8f00e220d122210b0001e00b0011e00b0012e00b0013e00b00
|
||||
17e00b0018e00b001ae01601c0003601340109000000001044332211100000ff
|
||||
88776655040000100050018c4040018c5555aaaafc5f018c00f0ff1f0040018c
|
||||
001000104440018cfc6f018c0df0ad0bb0b0b0b0c0c0c0c00030001008300010
|
||||
0070018cc1c1c1c100400010000000ff08400010862f962ff45110d2222210d8
|
||||
422810d0522010d4122410d5622510d6722610d7122710d3f25992238302f359
|
||||
9222122800e11220122412251226122712238302f6690b00f6680900000000e0
|
||||
040000e0080000e00c0000e0100000e0140000e0180000e01c0000e0862f962f
|
||||
a62fb62fc62fd62fe62f224ff07f536b636a7369fd5e2ad11b24431f29dd422d
|
||||
00e829d1822129d282220871822108728222087182210872822208718221830d
|
||||
e21f611f722f22dcfc575366a3650b4cb364e21ffc52211f922f2367b366a365
|
||||
0b4c93641bdee21fa11f922ffc57b366a3650b4cb364f351122d17d112d21222
|
||||
12d182210872822208718221087282220871822108728222830de21ffc51111f
|
||||
922f1367b366a3650b4c9364107f264ff66ef66df66cf66bf66af6690b00f668
|
||||
00000081000000e0040000e0080000e0b40b018c0000803e00000024224ff87f
|
||||
f351111f722f6367536643650cd10b4100e40cd200e112220bd3122304731223
|
||||
04731223047312230473122304731223047312238302087f264f0b0009000900
|
||||
1c0c018c000000e0040000e0862f962fa62fb62fc62fd62fe62ff75cf85bf95e
|
||||
24d14b2124d2122224da25d1122a25d9522925d8622825d000e1122024d51225
|
||||
24d6122624d312238302436d2b2dd222b22ae229c22812201225722612238302
|
||||
d222b22afb5bb229c22812201bdbb225722612238302d222fa5dd22ae229c228
|
||||
b220122572261223830215dddb244222fa54422afb5dd229c228b220b2257226
|
||||
12238302f66ef66df66cf66bf66af6690b00f66800000080000000e0040000e0
|
||||
000000c0080000e00c0000e0100000e0140000e0180000e01c0000e00000803f
|
||||
000000f0862f962fa62fb62fc62fd62fe62f224fbc7fc07f6bd112616bd22665
|
||||
266622676ad2266322625b216b217b213b212b2144e0160f66d11060fec90021
|
||||
ffe265d322230473222300e204732123106001cb002161d1126061d7792005cb
|
||||
022160d360d6622360d6222660d261d662226c7260d662229c7260d662220472
|
||||
5fd662225fd662625fd55b2222265fd206e6622204728c966222126079200dcb
|
||||
02215bd112235bd15bd222215bd15cd212225cd212225cd15cd222215cd600e3
|
||||
5cd85dd412e745330a02094223611c3113652c355c353369583953609c300840
|
||||
8e01122601731047ed8f047653d154d2222154d154d22221047154d222210471
|
||||
53d2222153d15592222104715392222104711fe2222104714e9222214ed24fd3
|
||||
10e132221041fc8f04724dd1459222213c714cd222210871077222214ad24bd3
|
||||
3c9132221041fc8f047249d149d74ad310e2722133961c3632261042f98f0471
|
||||
46d147d2222104712a92222145d246d310e132221041fc8f04721fe143d21222
|
||||
43d2122243d100e002ea00e942d807e41fe51697169317e6d62f019d230df66d
|
||||
fe2010437a8d017726657035f989f8af63614001007ce003ff7f800180000010
|
||||
1f7ce00700f80900846c5fa0f46c5fa0c0785fa00400d8ff0800d8ff44805fa0
|
||||
000080005c805fa03f7d170050805fa060805fa0000020000401150000007f02
|
||||
0000df01f4805fa00000010048805fa07f7e17007c805fa077df270000001000
|
||||
20805fa028815fa08c805fa0000000030c0010a52432018cabaaaaaa88805fa0
|
||||
17b7d138000010a500000002000080200000003004905fa0001000a403030303
|
||||
74805fa000ff000000825fa080800000002006a4050505050606060614905fa0
|
||||
1ffc0000000006a4070707071c985fa01c9c5fa0004006a4ffff000080d22753
|
||||
80d22033628d48e001e1160f10e17ed21222047212227dd27dd30ce132221041
|
||||
fc8f047200e179d212220472122279d179d2222179d17ad222217ad12e417ad1
|
||||
ffe700e308e2722131111042fb8f087175d376d1122376d276d12921c8977b21
|
||||
111375d1122200e1111274d2122274d2122274d105e2222173d00b40090040e7
|
||||
fc37001771d1eee2b393202170d71c37202770d71c3720276fd71c3720271043
|
||||
f38f01716dd46ed00b4005e5082001ee138fe61f6bd00b4009006bd46bd10b41
|
||||
09246bdcc36dc51f4fa200ee69d220534cd22033998998af01e18b9566d467d0
|
||||
0b4009000820e58de61f5cd45cd00b4005e50820018b03a102ee61d87b9b5fda
|
||||
60d9b3650b4a83640820018bfaa002ee71900c389038f58fb36550d450d00b40
|
||||
08e50820018befa003ee659556d453d00b4009000820028f10e1e7a003ee53d6
|
||||
53d220677c6764633c633037028d1041dea004eef58f01724ed14b9210677c67
|
||||
3bd31c3330633c633037028d1042d1a005eef38f017148d13c9210677c6735d3
|
||||
1c3330633c633037028d1042c4a006eef38f017131d432d00b4002e50820018b
|
||||
bca008ee3dd13ed2222104712592222101e13cd2122208721222047212223ad1
|
||||
226001c8018d1041fa8b38d1126001c8028ffc71a4a009ee00e2222104711260
|
||||
01c801899ea00aee18d1079262a0090036010048002800040040001800100900
|
||||
c040018c11111111380000ff000018a500000080180018a54c0e00a02c805fa0
|
||||
00001800a800018c0040018c000000100050018c00f0ff1f443322114040018c
|
||||
000000ff100000ff2c0a018c000023ac0000ffff0000feff0000fdff5eb00000
|
||||
6c06018c6600018cff7fffff6c00018cec31018c0041018c0000200c9809018c
|
||||
0000210c0028210c0000220c1432018c000020ac000021ac000022ac04745fa0
|
||||
0000230c0c745fa0801a060018745fa00c8d017110677c674ad31c3330633c63
|
||||
3037f58d10420beef4aee61f46d110611c6183922031278f0cee44d110611c61
|
||||
2031238f07ee42d110611c6120311f8b40d110611c6120311c8b00eedaaee61f
|
||||
d8aee61fd6aee61fd4aee61fd2aee61fd0aee61fceaee61fccaee61fcaaee61f
|
||||
c8aee61fc6aee61fc4aee61fc2aee61fc0aee61fbeaee61f017993600888038f
|
||||
93680ca1017e936807e00d4847911928936001c90b2870e0860fd26af553326b
|
||||
f3667076b36524d70b47a364071ff36778778366b36521d00b40a36440e2fc32
|
||||
2e51f75010303d8f70e02f5128922921fe022031028de82edda001eecc8ff366
|
||||
860f7076a36514d70b47a364036bf3667876836512d00b40a36440e2fc322e51
|
||||
103b0189c9a002ee2f51099339212c522031b28d017902ee16a0e51fee000003
|
||||
010309000000fdff001023ac002820ac002821ac004022acd409018c1000018c
|
||||
2c00018c01eee51f59d10b4100e859d00b400900036158d956db0b4b136aa230
|
||||
058f0361a030ffe22a381049f58b63e1163801ee028fef1f07a209004fd850d1
|
||||
122850d10b41090082624fd34ad1326001c8018d1041fa8b4bd11261136001c9
|
||||
081f136001c8018910a202e043d1126343d11033018b0ba203e040d1126040d1
|
||||
1032038dff88018904a201e03bd11260ff885e893ad222213cd13dd222210471
|
||||
3cd222210471629222213bd13bd22221147101e2222113622fd1226001c8018d
|
||||
1041fa8b2dd112611c6113600688018909a204e029d22260294019403088028d
|
||||
747202a204e022632dd220330189fea105e022d222d3322224d22ad332220472
|
||||
24d33222047228d33222047227d33222047227d3322227d727d320e232270173
|
||||
1042fb8f04771cd21cd33222147201e33222236310d2326001c8018d1042fa8b
|
||||
0ed22260ff88048922600c6007880089181fa0a1090057afe51f55afe51ff550
|
||||
0470051fe3600a882889ecae00e902200c06018c3c06018c80841e0000e100ac
|
||||
785634128c05018c186c5fa000e000ac0000008000e1000c046c5fa000e0000c
|
||||
56657273220000800c010022000000020000006414e000ac0000dec0047d73d1
|
||||
103d018980adc51f71d8836c057cf36a547a70db84600c69ab80f3640b4b5f74
|
||||
036168e0982929022031028d160f19a103eeab840c61c8909b201030028dc038
|
||||
12a103eee68b64d8836e147e63dd64dc64db65da0b4d0900051f8669f3667876
|
||||
9365f3640b4c747440e3fc333e52f361707110320189f9a004eef3617471a490
|
||||
fe0210320189f3a004ee3c52f5512a219a21b9213f533a22a9222b211821028d
|
||||
e038e7a004eed58b50d00b40f36b036a4fd9936e187e4fdd6c7b4fdc96680b4d
|
||||
83640038028d02e0d6a005ee0a2868e0860fb365f3640b4c68740038028d40e2
|
||||
cca006eefc322b51b031028d903ec7a006eee38b41d1181241d1191241d93dd8
|
||||
0b48936440dbf3640b4b60743fd40b4807eef3640b4b64740b489364f3643cd1
|
||||
0b41687440e7fc377a5278511032478fe51f36d11a17f3656c75f3642ed00b40
|
||||
6874f36432d10b41687440e1fc311a521951103208ee338fe51f2ed00b4009ee
|
||||
01882d8fe51f2cd00b400aee0188278fe51f2ad483600b400bee20d428d00b40
|
||||
090028d110301b8fe51f27d424d00b4009000188148fe51f24d140e0fc301810
|
||||
00e11a10f3656875f36421d10b41607440e3fc333a52385110320cee028de51f
|
||||
42ae0900a36435a0836080001432018ce431018c4800018cd031018c6600018c
|
||||
5000018cf2830070f38300708400018cb831018c7200018c7a00018c0000803f
|
||||
00000040010004008005018c010024008605018c8a00018c9800018c01000c00
|
||||
6805018c000080bf01000080785634127605018c0b40090044d800e1122844d1
|
||||
0b41090082627e9110320dee088fe51ff36440d00b4068740788138f00eee51f
|
||||
f2ad0900f0ade51feeade51fecade51feaade51fe8ade51fe6ade51fe4ade51f
|
||||
e2ade51f0eeedfade51f33d9926833d10b41090064e1122931d120e222211362
|
||||
30d1226020c8018f1041fa8b2ed00b40090029d182212ad120e2222103619c71
|
||||
02e2263129011c31d8ad1f1f03a0081f01a0081f081f25d1126425d125d22363
|
||||
136600e020e73365283540755026017600231047f78f01731cd31fd77223dc73
|
||||
00e772231dd7122704772227047710e662271997722323651075136000eee71f
|
||||
01e808a010e3d6af081fd4af081fd2af081f1043248924666c6604677c677036
|
||||
f789f6af871f8001115409004440018c2c05018c4005018cc8805fa00c06018c
|
||||
00695fa080841e003c06018c4000a0ff9040018c7040018c018200001000a0ff
|
||||
6ed22062282203890192230209003e166bd2226210711032228df75ee82e018f
|
||||
03eee71f67d268d112220171111267d100e332213111321133113411351164d7
|
||||
32275fd32223136504731223047304e66223a893322710715bd004e813a004e3
|
||||
5cd112615031d98ff75e5bd112611821d48ff75e56d1126002c8d38fe82eceaf
|
||||
090010430789f75ee82efa8f56660036f789f6af871f4dd334533823048ff75e
|
||||
47d3326330322589e82e2a8d05ee00e247d122212471422148d149d33b2149d3
|
||||
222349d249d72227326320331b8d00e244d3222341d3222345d2222132632033
|
||||
01ee248fea1f126241d110321b8ff3611fa0787137d222621032d58ff75ed7af
|
||||
00e2d4afe71f726337d22033ffe22a622a1f00e233d3222330d3222334d22221
|
||||
32632033df89fa5eeb6102711a1ff3617871399221213890118158e012810fe0
|
||||
138133901481329015812ad100e220211871a0e2202128d228d1206008c8018f
|
||||
1041fa8b24d1106008c81a8d09eef362787223d306e1256771231041fb8b21d1
|
||||
0fe2222120d1139222210471f072222100e11ed30d940d950d961dd80c994aa0
|
||||
00e2ecafe61f314420010002000383001f0fff0077772c01a10f09008040018c
|
||||
1000a0ff6840018c0100feca5040018c1c00a0ff1400a0ff1800a0ff4c40018c
|
||||
000000e0000014a50df0ad0b000014e52143341284705fa018705fa0a0860100
|
||||
80705fa0002870a0402070a0000081a04b1714060a071360783001400c37f5e0
|
||||
0d4797071a0013670837d59eec3771230172027361714632ec8f853151230172
|
||||
02736032f78f617100e16cd21222047212220472c193322204721fe332220472
|
||||
bc93322204721222047212220472122263d1b4922221047160e2222161d100e0
|
||||
ae9500e6ad97ad935fd25630d62f019d230df66d0814612101707030f58f0271
|
||||
00e15ad212220472122204729993322204721fe3322204729093322204721222
|
||||
047212220472122204728c933222047248e3322288924ed32223047322230473
|
||||
222304732223047322234ad212220472122249d17992222148d600e7769048d4
|
||||
7598759373620922236106e55d412c311c312c3145310a021365283501455c32
|
||||
1942094287021a022831629eec31112601771043e68f027600e13ad212220472
|
||||
122204724d93322204721fe3322204724493322204724d933222047212220472
|
||||
122231d13b922221047160e22221d87141922221f65007e11d401fcb40e2fc32
|
||||
061200eeeb1fee1fed1fffeeec1f00eee91f92a700e8188d5a884d8f648823d1
|
||||
2a922221019023008360901220d10b4102e4ffa109001ed10b4103e4faa10900
|
||||
1bd10b4104e4f5a109001ad115922221019023008360641230f800011f3c1f0f
|
||||
ff07001070170f0f00190242ff0fcf07011019fc00780342e003e07f040070a0
|
||||
240070a0000082a090e80000840070a0ac0070a0c00070a0800070a0000083a0
|
||||
6b6f4606040170a0240170a01c985fa0e405018c10905fa002890c911038138b
|
||||
06d107d2222183606488178b05d10392222113a00900c8001f7c0900000070a0
|
||||
01c200001c9c5fa0e79110380389019023008360b01173d173d2222173d174dc
|
||||
122c74d1126340e2fc32331272dee2644412c265551201e2222120e1122e6fd1
|
||||
122c6fd16fd612266fd712276fd170d0122070d1141f131f00e9921f911f6ed2
|
||||
222f6eddba9700e66dd50b4d00e46ddbb41fb31f921f911f6bd1122f6bd700e6
|
||||
67d50b4d00e46ada922a6ad392236ad492246ad592256ad692266ad792276ad0
|
||||
92206ad19221830affe369d2322210e1122e68d1122c68d152d4122452d51225
|
||||
52d753d67226b41fb31f921f911f52dee22f62d700e652d50b4d00e4922a55d0
|
||||
922055d1922155d2922255d3922355d4922455d5922555d69226830affee54d7
|
||||
e22757d112611821018b5ca101e255d1126177e22631028f01717ba1090051d2
|
||||
122251d112600820018bd9a1090009e11630018b1ca20a8801704bd102212dd1
|
||||
4ce0fe044221047150e0fe055221147154e0fe066221087144d22221047144d2
|
||||
222144d111600d6043d111611f88028f1d6114a2090041d641d240e1236740e3
|
||||
61271043fc8f027729901041f68f0c322691163829023bd1088f222119d13ad2
|
||||
22211e911038018b38d1106118d117d2222134d112611821018902a2ffe718de
|
||||
33dcc41f13d1131f32dbb21f32ddd11f11daa22f11d961a0ffe7a00000800001
|
||||
03010601000070a0018200000000200060805fa048805fa04c805fa000007001
|
||||
00007f0068805fa06c805fa00000008044815fa0000000430000003f4c0d018c
|
||||
00008020000080429a99193fff0000ff000000e0040000e0080000e00c0000e0
|
||||
100000e0140000e0180000e01c0000e014805fa00000740100003f0000ff00ff
|
||||
2480018c2080018c1880018c00007f020000df01140a70a4c80a70a400f80000
|
||||
804070a42880018c0000c700010071a00000dc4200008c420000004200e6c394
|
||||
0b49e365c41f61d1131fb21f60d1111fa22f60d760d5b7940b4900e6c41f5fd1
|
||||
131fb21f5ed1111fa22fffe75dd6ac940b49e3655cd1141f5cd1131f5cd1121f
|
||||
d11fa22fffe700e65ad50b4900e45ad1141f5ad1131f5ad1121f5ad1111fa22f
|
||||
ffe759d659d50b4908e459d159d2222159d25ad332220472e222047200e33222
|
||||
047257d33222047232220472322204723222830100e048dd52dc13634edb52da
|
||||
52d953d400e253d563a104e11638018b43a7836050d151d2222151d1ffe22221
|
||||
50d10b41090050d110600fc90688018b34a509004dd1126118211f894cd11261
|
||||
18211b8f0820028d09e198a501e240e4fc341e141f1447d1126004e700e600e5
|
||||
f3640b40787478e0fe011821028d01e241d1222141d222610171122213a58360
|
||||
3fd12cae09003fd122213fd2222c32d132d22221b41fb31f921f911f2bd1122f
|
||||
3ad700e63ad50b4d00e4922a22d2922204729222047292220472922204729222
|
||||
0472922204729222830a25d1ffe2222187ae09002fd111611d612fd00031f789
|
||||
2ed101e27dae2221800088000000304300001043ffffff800000908000009043
|
||||
000040430002003000005c420000c0420000f0410000002000002f4300009643
|
||||
0000fa4200007a4300000e0c24008020000000e020000080040000e0000000c0
|
||||
0000803f000043430c0000e00000003f100000e0180000e044815fa000000080
|
||||
14805fa08c05018c8c705fa01080018c0880018cbc00008c0080018c0c80018c
|
||||
000020002480018c00007801ff00ffff00008020280a78a41ff800001c80018c
|
||||
54daa26c54d1cb21122a54d110e22221147153d2222153d153d2122204721222
|
||||
52d153d2222153de53dbb41f53d1131f00e9921f911f52d1122f52dd869700e6
|
||||
e3650b4d00e4b41fb31f921f911f4ed1122f4ed700e6e3650b4d00e44cd19221
|
||||
4cd29222047292220472922204729222047292220472922204729222830146d1
|
||||
ffe22221c22a45d101e22221e7ad0900fc8b43d111600d60407111611f88078d
|
||||
1d6140d101e222213cd10be2d7ad22214d922c313cd33821f689f2af09004697
|
||||
7c3139dee821068b36d112611821058936d6e1ad090035d6dead09003896dbad
|
||||
090033d1141f33d1131f33d1121f33d1111f33d1122f00e61ed522d10b4100e4
|
||||
edad090029071ceeed473b27722340e7fc377357722b2bd76227922a22240c77
|
||||
222729dee2250877222783031041518d017002c840e6fc36d3160089c31601c8
|
||||
22d6df8d038822d6ddaf290700802004e0070900f4805fa0000001004c805fa0
|
||||
00007c0100003f0068805fa044815fa000000080000080200000804200000043
|
||||
0000003f4c0d018c9a99193fff0000ff000000e0040000e014805fa01880018c
|
||||
200a7ca41c80018cdfff000000f800000000484300809f430000704200005243
|
||||
6666663f080000e00000803f0000574300006b4385daa41f85d1131f85d9921f
|
||||
85d1111f85dee22fffe785d685d586d00b4008e4a41f85d1131f921f84d1111f
|
||||
e22fffe783d684d57fd10b4108e483da83d4422a83dd84d2222d84db84d1122b
|
||||
84dc85d6622c00e984d3922384d5922584d7922784d09220830ab22a83d1122d
|
||||
83d7722be22c92239225ffe2087322239220830ab22a122d7ed3322be22cfc75
|
||||
92257dd1f87012200875222508709220830ab22a79d0022d722be22cf8751225
|
||||
047592250475222504759225830a74d5522a022d322be22c68d0122004701220
|
||||
0470222004709220830a422a5ed4422d6cd4422b622c61d69226f870922061d4
|
||||
92240c769226830ab22a67d6622d722be22cfc709220fc749224087022200874
|
||||
9224830ab22a622d322be22c53d69226fc701220fc7422240c769226830ab22a
|
||||
5ad6622d722be22c4cd712279220222408709220830a522a622d322be22c1227
|
||||
47d3122322249220830a51d2241f131f621f50d1111fe22fffe737d5559432de
|
||||
0b4e00e64cd1122a37d0022d32d1122b4ad1122c30d339d232222ed538d45224
|
||||
38d6922638d79227830a00e300e2c36b636affe9736421a004e5236740d141dc
|
||||
236641dddb2725dd722d26de022e27d0c2201ad7722b29dc122c29d76227922a
|
||||
2224830d122d622e9220222b222c2227222a2224830d10456c8d017302e13360
|
||||
02c8028d3921c0a401c801c801897da403882ed01821d08f13672adcd1af1366
|
||||
2ad027d12adcccaf1366800000006b430000f04100005743000020410000003f
|
||||
00c00034002080204c0d018c00005c4200000c4200c0003600008020000000e0
|
||||
08000080040000e0000000c0080000e0002480200c0000e000c80088100000e0
|
||||
140000e0180000e01c0000e00000f0420000e041000050420000004300002043
|
||||
080000f00004802000002443000040430000604300008042c800008000020030
|
||||
0000803f00005643c80000e00000484300006c43d36abdd1122de36dbcd1122e
|
||||
036cbcdee220bcdb00e9922b087092209227bad29222bade922e830aa22ab9d1
|
||||
122db9d1122cb9d1122b92209227b8d2b2d42224922e830aa22ab6d2222db6d2
|
||||
222c122b92209227b4d22224922e830ab3d2222ab3d2222db3d2222c122b9220
|
||||
9227b2d11224922e830a922a922d922c922b922092279224922e830aacd5add6
|
||||
611fadd1122fadd75366add00b4000e4a8d1111fabd1122fabd7acd6acd5a8d2
|
||||
0b4200e4abd1122a922d922c922b02e2a9d3222306e1a9d4122490d52225122e
|
||||
830a9cd6611fa2d7722fa5d7a5d6a6d5a6d49bd00b400900922a922d922c922b
|
||||
9dd192219dd2922284d39223922e830a9fd4441f9fd1131f9fd5521f9fd6611f
|
||||
9fd7722f9fd6a0d5a0d4a1d00b40ffe797d1141f9fd1131f97d2221f9ed1111f
|
||||
97d3322f9dd698d598d499d00b40ffe7922a922d922c922b87d1922187d29222
|
||||
6ed39223922e830a95d4441f8bd5531f94d6621f94d7711f94d0022f94d795d5
|
||||
95d48bd10b4100e68dd2241f93d3331f8cd4421f92d5511f92d6622f92d78dd5
|
||||
8dd483d00b4000e6922a922d922c922b71d1922171d2922258d39223922e830a
|
||||
8ad18bd222218bd1141f8bd1131f8bd1121f8bd1111f8bd1122f8bd700e64dd5
|
||||
73d00b4000e461d1141f88d1131f7bd2221f87d1111f6ad3322f86d786d58294
|
||||
6bd00b4000e6922a922d922c922b5ad192215ad2922241d39223922e830a7fd4
|
||||
422f7fd77fd680d580d481d00b4009007ad180d780d681d581d47dd20b42122f
|
||||
4ad3341f55d4431f64d5521f5ed6611f5ed7722f5ed75fd55fd455d00b4000e6
|
||||
42d1141f5dd2231f221f5dd3311f5dd4422f5dd757d558d44dd00b4000e6922a
|
||||
922d922c922b3cd192213cd2922223d39223922e830a6bd1ffe2222134911038
|
||||
0189adab090068d268d1226001c8018d1041fa8b66d167d2222167d167d22221
|
||||
047167d22221047166d22221047142d22221047164d2222164d365d220e12223
|
||||
01721041fb8f047362d163d22221147101e22221136255d1226001c8018d1041
|
||||
fa8b80ab090080009600090002000080000000c0000080200c0000e0180000e0
|
||||
1c0000e0333321426666e7421f856b3f1010e0ff9a19164366e64d4310e010ff
|
||||
000000f0cd4c914333330243e01010ff0000a0420000403f0000c84200007043
|
||||
1c0c018c00006f43000074430000524300005c4300000020100000e0140000e0
|
||||
0000004300004443000080420000020000005c42000068430000f04100004843
|
||||
0000003f00c4003000009020080000044c0d018c00008d4300007a4300c60030
|
||||
00002a430000024300000c439a99193fff000080000090940000000200003443
|
||||
0000f0429a99993e0000ff8060815fa0000000800000d84200008c420000be42
|
||||
000020423333333fffff00ff0000964300008043ffffff80000090806666663f
|
||||
0000d442000082420000c24200003442fc0c018c00004d430000914300003943
|
||||
0000874314805fa0186c5fa080841e0000e100ac7856341200e000ac22000080
|
||||
00e1000c0c0100220000006514e000ac0001dec0046c5fa000e0000c63d22261
|
||||
0171122283603c88028f4288a9a00900048ffb5ee82e018ba8a009005cd10b41
|
||||
09005cd10b4110e45bd1126283639c73aa911633028ff951c6a009002831fc5e
|
||||
163e008b1c1ffd5e123e00891d1ffe5e1c3eee1f291f00e148e0fe022822038d
|
||||
1821018922a10900028d3fe112a1fd521638018bc2a08360017883603c88028f
|
||||
3ce17da809001638018b64a846881e88028f2d886aa80900028f0f886ba80900
|
||||
01899fa183603dd10b4101e4836208422c3208428c32184209428c3265911922
|
||||
83603fc9036108410c31184134d33c3134d321211043fc8f027151aa090032d1
|
||||
222100e131d210220c720ae33022047210222fd1a0e220212ed22fd1206008c8
|
||||
018f1041fa8b2bd1106008c8238d13e26871212100e221210ae3312121212121
|
||||
212124d224d1206008c8018f1041fa8b20d1106008c811896871116211601162
|
||||
116211611ad220620fc918401c610b211ad257af12221ad1faaf090018d1f7af
|
||||
090018d00b4000e404a00b1f15d00b4001e40b1f06d10b41090006d10b4110e4
|
||||
05d1126267af291f9500ff7f1080018c0c06018c4c06018c0c00d8ffe405018c
|
||||
000000a500a000000880018c84705fa09c705fa018705fa0a08601000480018c
|
||||
ffff0000a007018caa9110381f8ff55ee82e1c8956d1a493322156d1ec31291f
|
||||
55d2122255d112611821078d8360226253d11032038f01c8c2a00ae201c8018b
|
||||
e1a009004fd150d2122236af017887911038b78fce71fd53fc5ee8331633268d
|
||||
fe5e4ad3ec337d911633268d44e0fe000820278df65e3ed175933221291ffe5e
|
||||
42d2ec326e9116325e8d44e0fe0008205d8ff65ee82e5d8f48e0fe0008205c8f
|
||||
ff5ee82e278df85039d1b9afec3130d15a93322137d1b3af291f2dd155933221
|
||||
ddaf291fe82e0e8d58e029d1fe000221291ffd52fc5ee832449116322dd19f8d
|
||||
fe5ecdaf0900291fd6ae01e120d13d922221efaffd520820038df75e26d18faf
|
||||
0c31e82e028925d18aafec31fa5ee82e028923d184afec31fb5ee82e038d40e0
|
||||
20d17dafec3101e1fe021732038f40e01dd175af2c31fe000188028910d16faf
|
||||
09001ad16caf090019d169af090019d166af090018d163af090018d160af0900
|
||||
fa00e003c8001f7c007cff03007e090010905fa00001d0ba4840018c1080018c
|
||||
0d600d600000400050805fa043c721fe0008d0ba0200d0ba0009d0ba000ad0ba
|
||||
000bd0ba000dd0ba0007d0ba4d4d0d600300d0ba0400d0ba0500d0ba0600d0ba
|
||||
5bd11261c971263112895ad112611821138959d11262a9911032028957d108a0
|
||||
090057d1126118210a8956d101a0090055d156d2122221af836055d1f9af0900
|
||||
54d1f6af090054d11daf090029071ce61821028d6d4783ab090050d050dc51d6
|
||||
4fab090003c903880189bfa83fe13fe11638028d83605aae836201c8018befa8
|
||||
090049d1019c230c090034ee47d222621071203102ee068fe71f45d112615031
|
||||
02ee048de71f019223020900b8e9019123010900f6e93360038829071ce11d47
|
||||
3cd038d136dc1cab1366f48f182139d041ab09004121017002715630058f20c8
|
||||
d62f019d230df66deeebf38f2364f1af336401a093628362212101700271a630
|
||||
f78f0388f78d46302c8f66302c8b312101705888f38f027127d12892222127d2
|
||||
27d1292127d33b2113662367e07726d518e352271043fc8f047724d30ce77223
|
||||
fc7310e7722322d708e3722101771043fb8f047183061ed700e101e601952305
|
||||
08e3a6dec8af5362c6af7362280680000c80018c0880018c0480018c030cd0ba
|
||||
0080018c040cd0ba010cd0ba4840018c020cd0ba9d5a0d600000200000004843
|
||||
00006c430000803f000040001000a0ff1400a0ff000070431c815fa0e040018c
|
||||
e0ffff03000000e0111111113c0000ffe0ffc000400000006400000000000000
|
||||
400100000e00000000000000100000000a000000000000000100040000000400
|
||||
0300040001000c00010024000100040001000000020000000001000000020000
|
||||
0303000000017f80ff000000000000000100000002000000ffffff7f00000080
|
||||
01000080ffffffff78563412efbeadde000001005345474120534547414b4154
|
||||
414e4120000000000000000017b7d1380000000000000000ffffffff00002044
|
||||
0000000017b7d1380000803f00000000ffffffff000000000000f04317b7d138
|
||||
000000000000803fffffffff
|
||||
""")
|
||||
|
||||
# The same program built with -DLIVE_MMU_ALIGN: its MMU test also asks for
|
||||
# the address errors a misaligned access raises (live_prog.c). For a core
|
||||
# that keeps translations in a table, which they all do: it is the build
|
||||
@@ -1380,7 +2200,7 @@ def main():
|
||||
if len(sys.argv) == 2 and sys.argv[1].endswith('.elf'):
|
||||
write_elf(sys.argv[1])
|
||||
return 0
|
||||
if len(sys.argv) not in (2, 3) or sys.argv[2:] not in ([], ['--no-region-array'], ['--mmu-align']):
|
||||
if len(sys.argv) not in (2, 3) or sys.argv[2:] not in ([], ['--no-region-array'], ['--mmu-align'], ['--slant'], ['--hscale']):
|
||||
sys.stderr.write(__doc__)
|
||||
return 2
|
||||
out = sys.argv[1]
|
||||
@@ -1389,6 +2209,10 @@ def main():
|
||||
program = PROGRAM_NO_REGION_ARRAY
|
||||
elif sys.argv[2:] == ['--mmu-align']:
|
||||
program = PROGRAM_MMU_ALIGN
|
||||
elif sys.argv[2:] == ['--slant']:
|
||||
program = PROGRAM_SLANT
|
||||
elif sys.argv[2:] == ['--hscale']:
|
||||
program = PROGRAM_HSCALE
|
||||
d = os.path.dirname(out) or '.'
|
||||
|
||||
ip = bytearray(16 * 2048)
|
||||
|
||||
@@ -25,8 +25,9 @@
|
||||
* sh4-linux-gnu-objcopy -O binary live_prog.elf live_prog.bin
|
||||
*
|
||||
* and paste the bytes of live_prog.bin into PROGRAM; the same again with
|
||||
* -DNO_REGION_ARRAY for PROGRAM_NO_REGION_ARRAY, and with -DLIVE_MMU_ALIGN
|
||||
* for PROGRAM_MMU_ALIGN. */
|
||||
* -DNO_REGION_ARRAY for PROGRAM_NO_REGION_ARRAY, with -DLIVE_MMU_ALIGN
|
||||
* for PROGRAM_MMU_ALIGN, with -DLIVE_SLANT for PROGRAM_SLANT, and with
|
||||
* -DLIVE_SLANT -DLIVE_HSCALE for PROGRAM_HSCALE. */
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned short u16;
|
||||
#define PVR(off) (*(volatile u32 *)(0xA05F8000 + (off)))
|
||||
@@ -574,6 +575,16 @@ static void ta_scene(void)
|
||||
* one's bank has it green. */
|
||||
ta_quad_two(TSP_PLAIN, (6u << 27) | (0x1000 >> 3), TSP_PLAIN, (6u << 27) | (0x30u << 21) | (0x60000 >> 3),
|
||||
F(0.5f), F(200.0f), F(214.0f), F(240.0f), F(236.0f));
|
||||
#ifdef LIVE_SLANT
|
||||
/* With -DLIVE_SLANT, over the middle of it all: a triangle shaded from
|
||||
* red through green to blue, whose edges slant across the pixels and
|
||||
* cover parts of them - what SSAA's samples differ over, and what its
|
||||
* resolve averages (tools/vulkan/vk_hdr.sh's --exact) */
|
||||
ta_send(TA_POLYGON | 0x2, ISP_GEQUAL, TSP_PLAIN, 0, 0, 0, 0, 0); /* Gouraud */
|
||||
ta_send(TA_VERTEX, F(40.3f), F(115.7f), F(0.92f), 0, 0, 0xFFE01010, 0);
|
||||
ta_send(TA_VERTEX, F(150.1f), F(205.9f), F(0.92f), 0, 0, 0xFF10E010, 0);
|
||||
ta_send(TA_VERTEX | TA_LAST, F(290.6f), F(130.2f), F(0.92f), 0, 0, 0xFF1010E0, 0);
|
||||
#endif
|
||||
ta_send(0, 0, 0, 0, 0, 0, 0, 0); /* end of the opaque list */
|
||||
|
||||
ta_volume_part(0, x0, y0, x1, y1, F(0.75f));
|
||||
@@ -1511,6 +1522,16 @@ void cmain(void)
|
||||
PVR(0xCC) = 0x00150104; /* SPG_VBLANK_INT: in 260, out 21 */
|
||||
PVR(0x68) = 639 << 16; /* FB_X_CLIP: 0..639 */
|
||||
PVR(0x6C) = 479 << 16; /* FB_Y_CLIP: 0..479 */
|
||||
#ifdef LIVE_HSCALE
|
||||
/* With -DLIVE_HSCALE, the screen's renders through the X scaler too,
|
||||
* each pixel written the average of a pair drawn, into a framebuffer of
|
||||
* 32 bits, which the write-out does not pack */
|
||||
PVR(0xF4) |= 0x10000; /* SCALER_CTL: hscale */
|
||||
PVR(0x48) = 6; /* FB_W_CTRL: ARGB8888 */
|
||||
PVR(0x4C) = 640 * 4 / 8; /* FB_W_LINESTRIDE */
|
||||
PVR(0x44) = (PVR(0x44) & 0x00800000) | 0xD; /* FB_R_CTRL: enable, 0888 */
|
||||
PVR(0x5C) = (1u << 20) | (479u << 10) | 639u; /* FB_R_SIZE: 640x480 */
|
||||
#endif
|
||||
PVR(0x7C) = 0x0027DF77; /* FPU_PARAM_CFG: 6-word region entries */
|
||||
PVR(0x20) = 0x100000; /* PARAM_BASE */
|
||||
PVR(0x128) = 0x100000; /* TA_ISP_BASE */
|
||||
|
||||
@@ -800,12 +800,9 @@ static void run_case(const char *name, const struct hdr_dt_settings *dt, const s
|
||||
double worst = 0.0;
|
||||
unsigned at = 0;
|
||||
hdr_dt_configure(dt);
|
||||
if (cube)
|
||||
{
|
||||
/* (the tables made for these settings first, the cube from them) */
|
||||
hdr_dt_fill(b, o->paper_white_nits, o->max_nits, o->panel_peak_nits, o->panel_xy);
|
||||
hdr_dt_aces2_cube_finish(o->paper_white_nits);
|
||||
}
|
||||
/* (ACES 2.0 (full)'s tables made now, which frames leave to a worker,
|
||||
* and from them the cube) */
|
||||
hdr_dt_finish(o->paper_white_nits, o->max_nits, o->panel_peak_nits, o->panel_xy, cube != 0);
|
||||
hdr_dt_fill(b, o->paper_white_nits, o->max_nits, o->panel_peak_nits, o->panel_xy);
|
||||
make_tables();
|
||||
if (cube && (tables[3].v == VK_NULL_HANDLE || b->gm[2] == 0.0f))
|
||||
|
||||
@@ -529,6 +529,51 @@ static int same_pictures(const picture_t *a, const picture_t *b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The scRGB picture (@h) of an SSAA frame against its 24-bit one (@s),
|
||||
* in the 24-bit picture's steps (the reference knee is the identity below
|
||||
* paper white, and 2.4 the transfer): each channel decoded is within half
|
||||
* a step of the byte the resolve rounded it to (and a half float's
|
||||
* rounding) - what was encoded is the samples' exact average, which no
|
||||
* dither moved - and some are off the steps, which a byte cannot be. */
|
||||
static int exact_pictures(const picture_t *s, const picture_t *h)
|
||||
{
|
||||
const double paper = 200.0, tol = 0.5 + 0.12;
|
||||
unsigned long off = 0, n = 0;
|
||||
double worst = 0.0;
|
||||
uint32_t i;
|
||||
int c;
|
||||
if (s->w != h->w || s->h != h->h || h->format != VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
{
|
||||
fprintf(stderr, "vk_hdr: --exact wants a scRGB picture the size of the 24-bit one\n");
|
||||
return 2;
|
||||
}
|
||||
for (i = 0; i < s->w * s->h; i++)
|
||||
for (c = 0; c < 3; c++)
|
||||
{
|
||||
const double got = half_to_double(((const uint16_t*)h->px)[i * 4 + c]) * 80.0 / paper;
|
||||
const double e = 255.0 * pow(got > 0.0 ? got : 0.0, 1.0 / 2.4);
|
||||
const double d = fabs(e - (double)s->px[i * 4 + c]);
|
||||
n++;
|
||||
if (d > worst)
|
||||
worst = d;
|
||||
if (fabs(e - floor(e + 0.5)) > 0.15)
|
||||
off++;
|
||||
}
|
||||
printf("vk_hdr: %lu channels, %lu off the 24-bit steps, at most %.3f of a step from the 24-bit picture\n",
|
||||
n, off, worst);
|
||||
if (worst > tol)
|
||||
{
|
||||
fprintf(stderr, "vk_hdr: a channel is %.3f of a step from the 24-bit picture: dithered, or not its resolve\n", worst);
|
||||
return 1;
|
||||
}
|
||||
if (off < 100)
|
||||
{
|
||||
fprintf(stderr, "vk_hdr: %lu channels off the 24-bit steps: what was encoded is the bytes, not the samples\n", off);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compare(const char *sdr_path, const char *hdr_path)
|
||||
{
|
||||
return with_pictures(sdr_path, hdr_path, compare_pictures);
|
||||
@@ -578,6 +623,8 @@ int main(int argc, char **argv)
|
||||
|
||||
if (argc == 4 && !strcmp(argv[1], "--compare"))
|
||||
return compare(argv[2], argv[3]);
|
||||
if (argc == 4 && !strcmp(argv[1], "--exact"))
|
||||
return with_pictures(argv[2], argv[3], exact_pictures);
|
||||
if (argc == 4 && !strcmp(argv[1], "--same"))
|
||||
return same(argv[2], argv[3]);
|
||||
if (argc < 5)
|
||||
|
||||
+33
-1
@@ -13,6 +13,12 @@
|
||||
# vk_hdr --compare encodes the 24-bit picture on the CPU and holds the
|
||||
# HDR one to it;
|
||||
# - with the chip's write-out on, the picture written out, encoded;
|
||||
# - with it off, what was resolved - SSAA's samples on every renderer,
|
||||
# the X scaler's pair of pixels on the compute renderer - is encoded
|
||||
# from their exact average, not the byte the picture rounded it to,
|
||||
# and is not dithered (vk_hdr --exact; on the disc with a slanted
|
||||
# shaded triangle, and that with the X scaler, which the old code
|
||||
# fails);
|
||||
# - a filmic curve is not (the comparison sees a wrong encode);
|
||||
# - every Display Transform draws, and ACES 2.0 (Full) long enough for
|
||||
# its cube to be made and used.
|
||||
@@ -31,6 +37,11 @@ trap 'rm -rf "$WORK"' EXIT
|
||||
${CC:-cc} -O1 -g -Wall -I./core/libretro-common/include -I./core/deps/khronos \
|
||||
-o "$WORK/vk_hdr" tools/vulkan/vk_hdr.c -ldl -lm
|
||||
python3 tools/threads/live_disc.py "$WORK/test.gdi"
|
||||
# (each in a directory of its own: the track files are named alike)
|
||||
mkdir -p "$WORK/slant" "$WORK/hscale"
|
||||
python3 tools/threads/live_disc.py "$WORK/slant/slant.gdi" --slant
|
||||
python3 tools/threads/live_disc.py "$WORK/hscale/hscale.gdi" --hscale
|
||||
DISC=test.gdi
|
||||
# (from frame 70 the disc's picture has its textured background, mid-tones
|
||||
# and saturated colours in it; for its first 64 frames it renders through
|
||||
# the tile accelerator three frames in four, and writes the fourth to the
|
||||
@@ -40,7 +51,7 @@ FRAMES=70
|
||||
run() {
|
||||
# @1 the frontend, @2 the picture, @3... options
|
||||
fe=$1; out=$2; shift 2
|
||||
VKH_DIR="$WORK" VKH_FRONTEND=$fe "$WORK/vk_hdr" "$CORE" "$WORK/test.gdi" "$WORK/$out" $FRAMES "$@" \
|
||||
VKH_DIR="$WORK" VKH_FRONTEND=$fe "$WORK/vk_hdr" "$CORE" "$WORK/$DISC" "$WORK/$out" $FRAMES "$@" \
|
||||
2>"$WORK/log.txt" || { cat "$WORK/log.txt"; echo "vk_hdr.sh: $out failed"; exit 1; }
|
||||
}
|
||||
|
||||
@@ -95,6 +106,27 @@ if "$WORK/vk_hdr" --compare "$WORK/wo-strip.raw" "$WORK/strip-hdr10.raw" > /dev/
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# What was resolved, encoded from its exact average: SSAA's samples, on
|
||||
# each renderer, the slanted triangle's edges between them...
|
||||
DISC=slant/slant.gdi
|
||||
for r in "per-strip (fast, least accurate)|rasterizer|x-strip" \
|
||||
"per-triangle (normal)|rasterizer|x-triangle" \
|
||||
"per-pixel (accurate)|rasterizer|x-pixel" \
|
||||
"per-pixel (accurate)|compute|x-compute"; do
|
||||
sort=${r%%|*}; rest=${r#*|}; method=${rest%%|*}; name=${rest#*|}
|
||||
set -- "reicast_alpha_sorting=$sort" "reicast_rendering_method=$method" reicast_ssaa=4x
|
||||
run sdr "$name.raw" "$@"
|
||||
run scrgb "$name-scrgb.raw" reicast_color_format=64bit_scrgb "$@"
|
||||
"$WORK/vk_hdr" --exact "$WORK/$name.raw" "$WORK/$name-scrgb.raw"
|
||||
done
|
||||
# ...and the compute renderer's X scaler's pairs of pixels, at one sample
|
||||
DISC=hscale/hscale.gdi
|
||||
set -- reicast_pvr2_scaler=enabled "reicast_alpha_sorting=per-pixel (accurate)" reicast_rendering_method=compute
|
||||
run sdr x-hscale.raw "$@"
|
||||
run scrgb x-hscale-scrgb.raw reicast_color_format=64bit_scrgb "$@"
|
||||
"$WORK/vk_hdr" --exact "$WORK/x-hscale.raw" "$WORK/x-hscale-scrgb.raw"
|
||||
DISC=test.gdi
|
||||
|
||||
# (the comparison has to see a wrong encode, or it proves nothing)
|
||||
run hdr10 aces.raw reicast_color_format=30bit_hdr reicast_hdr_display_transform=aces
|
||||
if "$WORK/vk_hdr" --compare "$WORK/sdr.raw" "$WORK/aces.raw" > /dev/null 2>&1; then
|
||||
|
||||
@@ -56,4 +56,7 @@ run sdr triangle-ssaa reicast_ssaa=4x
|
||||
run sdr write-out reicast_pvr2_scaler=enabled
|
||||
run hdr10 hdr10 reicast_color_format=30bit_hdr
|
||||
run scrgb scrgb reicast_color_format=64bit_scrgb reicast_hdr_display_transform=aces2
|
||||
# (SSAA's channel sums for the encode: the per-pixel and compute renderers')
|
||||
run scrgb pixel-ssaa-scrgb reicast_color_format=64bit_scrgb "reicast_alpha_sorting=per-pixel (accurate)" reicast_ssaa=4x
|
||||
run scrgb compute-ssaa-scrgb reicast_color_format=64bit_scrgb "reicast_alpha_sorting=per-pixel (accurate)" reicast_rendering_method=compute reicast_ssaa=4x
|
||||
echo "vk_sanitize.sh: passed ($SANITIZE)"
|
||||
Reference in new issue
Block a user