demos/teapot: Add diffuse lighting.

This commit is contained in:
Henri Verbeet
2025-06-26 20:52:13 +02:00
parent 00f53b72a1
commit b6725a3a00
Notes: Henri Verbeet 2025-07-14 18:53:47 +02:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1611
3 changed files with 161 additions and 18 deletions

View File

@@ -177,6 +177,7 @@ static demo_key demo_key_from_nsevent(id event)
enum vkey
{
kVK_ANSI_A = 0x00,
kVK_ANSI_W = 0x0d,
kVK_ANSI_Equal = 0x18,
kVK_ANSI_Minus = 0x1b,
kVK_Escape = 0x35,
@@ -198,6 +199,7 @@ static demo_key demo_key_from_nsevent(id event)
lookup[] =
{
{kVK_ANSI_A, 'a'},
{kVK_ANSI_W, 'w'},
{kVK_ANSI_Equal, '='},
{kVK_ANSI_Minus, '-'},
{kVK_Escape, DEMO_KEY_ESCAPE},

View File

@@ -39,6 +39,7 @@ struct teapot_cb_data
{
struct demo_matrix mvp_matrix;
float level;
unsigned int wireframe;
};
struct demo_text_run
@@ -90,7 +91,7 @@ struct teapot
unsigned int text_scale;
float theta, phi;
bool display_help;
bool display_help, wireframe;
struct timeval last_text;
struct timeval frame_times[16];
size_t frame_count;
@@ -107,12 +108,12 @@ struct teapot
ID3D12CommandAllocator *command_allocator;
ID3D12GraphicsCommandList *command_list;
} *swapchain_images;
ID3D12DescriptorHeap *rtv_heap;
ID3D12DescriptorHeap *rtv_heap, *dsv_heap;
unsigned int rtv_descriptor_size;
ID3D12RootSignature *root_signature;
ID3D12PipelineState *pipeline_state;
ID3D12Resource *cb, *vb, *ib;
ID3D12Resource *ds, *cb, *vb, *ib;
D3D12_VERTEX_BUFFER_VIEW vbv;
D3D12_INDEX_BUFFER_VIEW ibv;
@@ -423,8 +424,8 @@ static void demo_text_cleanup(struct demo_text *text)
static void teapot_populate_command_list(struct teapot *teapot,
ID3D12GraphicsCommandList *command_list, unsigned int rt_idx)
{
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle, dsv_handle;
size_t rotate_idx_count, flip_idx_count;
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle;
D3D12_RESOURCE_BARRIER barrier;
HRESULT hr;
@@ -449,10 +450,13 @@ static void teapot_populate_command_list(struct teapot *teapot,
rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(teapot->rtv_heap);
rtv_handle.ptr += rt_idx * teapot->rtv_descriptor_size;
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &rtv_handle, FALSE, NULL);
dsv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(teapot->dsv_heap);
ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &rtv_handle, FALSE, &dsv_handle);
ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv_handle,
(float[]){1.00f * 0.1f, 0.69f * 0.1f, 0.00f, 1.0f}, 0, NULL);
ID3D12GraphicsCommandList_ClearDepthStencilView(command_list,
dsv_handle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, NULL);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST);
ID3D12GraphicsCommandList_IASetIndexBuffer(command_list, &teapot->ibv);
ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 1, &teapot->vbv);
@@ -542,9 +546,10 @@ static void teapot_update_text(struct teapot *teapot, double fps)
demo_text_draw(text, &amber, 0, -2 * h, "%.2f fps", fps);
if (teapot->display_help)
{
demo_text_draw(text, &amber, 0, 2 * h, "ESC: Exit");
demo_text_draw(text, &amber, 0, 1 * h, " F1: Toggle help");
demo_text_draw(text, &amber, 0, 0 * h, "-/+: Tessellation level (%u)", teapot->tessellation_level);
demo_text_draw(text, &amber, 0, 3 * h, "ESC: Exit");
demo_text_draw(text, &amber, 0, 2 * h, " F1: Toggle help");
demo_text_draw(text, &amber, 0, 1 * h, "-/+: Tessellation level (%u)", teapot->tessellation_level);
demo_text_draw(text, &amber, 0, 0 * h, " W: Toggle wireframe (%s)", teapot->wireframe ? "on" : "off");
}
a = text->draw_arguments;
@@ -579,6 +584,7 @@ static void teapot_destroy_pipeline(struct teapot *teapot)
{
unsigned int i;
ID3D12DescriptorHeap_Release(teapot->dsv_heap);
ID3D12DescriptorHeap_Release(teapot->rtv_heap);
for (i = 0; i < demo_swapchain_get_back_buffer_count(teapot->swapchain); ++i)
{
@@ -642,6 +648,13 @@ static void teapot_load_pipeline(struct teapot *teapot)
&IID_ID3D12CommandAllocator, (void **)&teapot->swapchain_images[i].command_allocator);
assert(SUCCEEDED(hr));
}
heap_desc.NumDescriptors = 1;
heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
hr = ID3D12Device_CreateDescriptorHeap(teapot->device, &heap_desc,
&IID_ID3D12DescriptorHeap, (void **)&teapot->dsv_heap);
assert(SUCCEEDED(hr));
}
static void teapot_fence_destroy(struct teapot_fence *teapot_fence)
@@ -659,6 +672,7 @@ static void teapot_destroy_assets(struct teapot *teapot)
ID3D12Resource_Release(teapot->vb);
ID3D12Resource_Unmap(teapot->cb, 0, NULL);
ID3D12Resource_Release(teapot->cb);
ID3D12Resource_Release(teapot->ds);
for (i = 0; i < demo_swapchain_get_back_buffer_count(teapot->swapchain); ++i)
{
ID3D12GraphicsCommandList_Release(teapot->swapchain_images[i].command_list);
@@ -715,7 +729,11 @@ static void teapot_load_assets(struct teapot *teapot)
D3D12_ROOT_SIGNATURE_DESC root_signature_desc;
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
D3D12_ROOT_PARAMETER root_parameters[1];
ID3DBlob *vs, *hs, *ds, *ps;
D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle;
D3D12_RESOURCE_DESC resource_desc;
ID3DBlob *vs, *hs, *ds, *gs, *ps;
D3D12_HEAP_PROPERTIES heap_desc;
D3D12_CLEAR_VALUE clear_value;
unsigned int i;
HRESULT hr;
@@ -734,8 +752,7 @@ static void teapot_load_assets(struct teapot *teapot)
root_signature_desc.pParameters = root_parameters;
root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
| D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS
| D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS
| D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
| D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
hr = demo_create_root_signature(teapot->device, &root_signature_desc, &teapot->root_signature);
assert(SUCCEEDED(hr));
@@ -748,6 +765,9 @@ static void teapot_load_assets(struct teapot *teapot)
hr = D3DCompile(teapot_hlsl, teapot_hlsl_size, "teapot.hlsl",
NULL, NULL, "ds_main", "ds_5_0", 0, 0, &ds, NULL);
assert(SUCCEEDED(hr));
hr = D3DCompile(teapot_hlsl, teapot_hlsl_size, "teapot.hlsl",
NULL, NULL, "gs_main", "gs_5_0", 0, 0, &gs, NULL);
assert(SUCCEEDED(hr));
hr = D3DCompile(teapot_hlsl, teapot_hlsl_size, "teapot.hlsl",
NULL, NULL, "ps_main", "ps_5_0", 0, 0, &ps, NULL);
assert(SUCCEEDED(hr));
@@ -762,24 +782,31 @@ static void teapot_load_assets(struct teapot *teapot)
pso_desc.HS.BytecodeLength = ID3D10Blob_GetBufferSize(hs);
pso_desc.DS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ds);
pso_desc.DS.BytecodeLength = ID3D10Blob_GetBufferSize(ds);
pso_desc.GS.pShaderBytecode = ID3D10Blob_GetBufferPointer(gs);
pso_desc.GS.BytecodeLength = ID3D10Blob_GetBufferSize(gs);
pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps);
pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps);
demo_rasterizer_desc_init_default(&pso_desc.RasterizerState);
pso_desc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
pso_desc.RasterizerState.FrontCounterClockwise = TRUE;
demo_blend_desc_init_default(&pso_desc.BlendState);
pso_desc.DepthStencilState.DepthEnable = TRUE;
pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
pso_desc.DepthStencilState.StencilEnable = FALSE;
pso_desc.SampleMask = UINT_MAX;
pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
pso_desc.NumRenderTargets = 1;
pso_desc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
pso_desc.SampleDesc.Count = 1;
hr = ID3D12Device_CreateGraphicsPipelineState(teapot->device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&teapot->pipeline_state);
assert(SUCCEEDED(hr));
ID3D10Blob_Release(ps);
ID3D10Blob_Release(gs);
ID3D10Blob_Release(ds);
ID3D10Blob_Release(hs);
ID3D10Blob_Release(vs);
@@ -794,12 +821,42 @@ static void teapot_load_assets(struct teapot *teapot)
assert(SUCCEEDED(hr));
}
heap_desc.Type = D3D12_HEAP_TYPE_DEFAULT;
heap_desc.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heap_desc.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heap_desc.CreationNodeMask = 1;
heap_desc.VisibleNodeMask = 1;
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resource_desc.Alignment = 0;
resource_desc.Width = teapot->width;
resource_desc.Height = teapot->height;
resource_desc.DepthOrArraySize = 1;
resource_desc.MipLevels = 1;
resource_desc.Format = DXGI_FORMAT_D32_FLOAT;
resource_desc.SampleDesc.Count = 1;
resource_desc.SampleDesc.Quality = 0;
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
clear_value.Format = DXGI_FORMAT_D32_FLOAT;
clear_value.DepthStencil.Depth = 1.0f;
clear_value.DepthStencil.Stencil = 0;
hr = ID3D12Device_CreateCommittedResource(teapot->device, &heap_desc, D3D12_HEAP_FLAG_NONE, &resource_desc,
D3D12_RESOURCE_STATE_DEPTH_WRITE, &clear_value, &IID_ID3D12Resource, (void **)&teapot->ds);
assert(SUCCEEDED(hr));
dsv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(teapot->dsv_heap);
ID3D12Device_CreateDepthStencilView(teapot->device, teapot->ds, NULL, dsv_handle);
teapot->cb = create_buffer(teapot->device, sizeof(*teapot->cb_data));
hr = ID3D12Resource_Map(teapot->cb, 0, &(D3D12_RANGE){0, 0}, (void **)&teapot->cb_data);
assert(SUCCEEDED(hr));
teapot_update_mvp(teapot);
teapot->cb_data->level = teapot->tessellation_level;
teapot->cb_data->wireframe = teapot->wireframe;
demo_text_init(&teapot->text, teapot->device, teapot->width, teapot->height, teapot->text_scale);
teapot_load_mesh(teapot);
@@ -824,6 +881,9 @@ static void teapot_key_press(struct demo_window *window, demo_key key, void *use
if (teapot->tessellation_level < D3D12_TESSELLATOR_MAX_TESSELLATION_FACTOR)
teapot->cb_data->level = ++teapot->tessellation_level;
break;
case 'w':
teapot->cb_data->wireframe = teapot->wireframe = !teapot->wireframe;
break;
case DEMO_KEY_ESCAPE:
demo_window_destroy(window);
break;
@@ -889,7 +949,7 @@ static int teapot_main(void)
teapot.width = width;
teapot.height = height;
teapot.tessellation_level = 4;
teapot.tessellation_level = 10;
teapot.text_scale = (1.25 * dpi_y / 96.0) + 0.5;
teapot.theta = M_PI / 2.0f;

View File

@@ -16,10 +16,13 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define M_PI 3.14159265
cbuffer teapot_cb : register(b0)
{
float4x4 mvp_matrix;
float level;
uint wireframe;
};
struct control_point
@@ -33,9 +36,19 @@ struct patch_constant_data
float inside[2] : SV_InsideTessFactor;
};
struct gs_in
{
float4 position : SV_POSITION;
float3 pos : POSITION;
float3 normal : NORMAL;
};
struct ps_in
{
float4 position : SV_POSITION;
float3 pos : POSITION;
float3 normal : NORMAL;
float2 barycentric : BARYCENTRIC;
};
float4 vs_main(float4 position : POSITION, uint id : SV_InstanceID) : SV_POSITION
@@ -92,30 +105,98 @@ float3 eval_cubic(float3 p0, float3 p1, float3 p2, float3 p3, float t)
eval_quadratic(p1, p2, p3, t), t);
}
struct ps_in eval_patch(float2 t, float4 p[16])
struct gs_in eval_patch(float2 t, float4 p[16])
{
float3 position, q[4];
struct ps_in o;
float3 position, normal, q[4], u, v;
struct gs_in o;
q[0] = eval_cubic( p[0].xyz, p[1].xyz, p[2].xyz, p[3].xyz, t.x);
q[1] = eval_cubic( p[4].xyz, p[5].xyz, p[6].xyz, p[7].xyz, t.x);
q[2] = eval_cubic( p[8].xyz, p[9].xyz, p[10].xyz, p[11].xyz, t.x);
q[3] = eval_cubic(p[12].xyz, p[13].xyz, p[14].xyz, p[15].xyz, t.x);
u = eval_quadratic(q[0], q[1], q[2], t.y) - eval_quadratic(q[1], q[2], q[3], t.y);
q[0] = eval_cubic(p[0].xyz, p[4].xyz, p[8].xyz, p[12].xyz, t.y);
q[1] = eval_cubic(p[1].xyz, p[5].xyz, p[9].xyz, p[13].xyz, t.y);
q[2] = eval_cubic(p[2].xyz, p[6].xyz, p[10].xyz, p[14].xyz, t.y);
q[3] = eval_cubic(p[3].xyz, p[7].xyz, p[11].xyz, p[15].xyz, t.y);
v = eval_quadratic(q[0], q[1], q[2], t.x) - eval_quadratic(q[1], q[2], q[3], t.x);
position = eval_cubic(q[0], q[1], q[2], q[3], t.x);
o.position = mul(mvp_matrix, float4(position, 1.0));
o.pos = position;
/* The patches for the bottom of the teapot and the top of its lid are
* degenerate. Technically this isn't the right way to deal with that, but
* it's easy and gets the right result for these patches. */
if (length(v) == 0.0)
normal = cross(p[4].xyz - p[0].xyz, p[7].xyz - p[3].xyz);
else
normal = cross(u, v);
o.normal = normalize(normal);
return o;
}
[domain("quad")]
struct ps_in ds_main(struct patch_constant_data input,
struct gs_in ds_main(struct patch_constant_data input,
float2 tess_coord : SV_DomainLocation, const OutputPatch<control_point, 16> patch)
{
return eval_patch(tess_coord, patch);
}
[maxvertexcount(3)]
void gs_main(triangle struct gs_in i[3], inout TriangleStream<struct ps_in> stream)
{
struct ps_in v[3];
float3 n;
v[0].position = i[0].position;
v[0].pos = i[0].pos;
v[0].normal = i[0].normal;
v[0].barycentric = float2(1.0, 0.0);
v[1].position = i[1].position;
v[1].pos = i[1].pos;
v[1].normal = i[1].normal;
v[1].barycentric = float2(0.0, 1.0);
v[2].position = i[2].position;
v[2].pos = i[2].pos;
v[2].normal = i[2].normal;
v[2].barycentric = float2(0.0, 0.0);
stream.Append(v[0]);
stream.Append(v[1]);
stream.Append(v[2]);
}
/* Lambertian diffuse. */
float3 brdf_lambert(float3 diffuse)
{
return diffuse / M_PI;
}
float4 ps_main(struct ps_in i) : SV_TARGET
{
return float4(1.0, 0.69, 0.0, 1.0);
float3 light_dir = normalize(float3(5.0, 5.0, 10.0));
float3 light_colour = float3(1.0, 0.95, 0.88);
float3 light_irradiance = 5.0 * light_colour;
float3 barycentric, diffuse_colour, radiance;
float3 base_colour = float3(0.8, 0.8, 0.8);
float3 ambient = 0.3 * light_colour;
float cos_theta_i, wire;
float metallic = 0.3;
diffuse_colour = base_colour * (1.0 - metallic);
cos_theta_i = saturate(dot(normalize(i.normal), light_dir));
/* Cook-Torrance. */
radiance = brdf_lambert(diffuse_colour) * light_irradiance * cos_theta_i;
radiance += ambient * base_colour;
barycentric = float3(i.barycentric, 1.0 - (i.barycentric.x + i.barycentric.y));
barycentric /= fwidth(barycentric);
wire = wireframe ? min(min(barycentric.x, barycentric.y), barycentric.z) : 1.0;
return float4(lerp(float3(1.00, 0.69, 0.0), saturate(radiance), saturate(wire)), 1.0);
}