DX12: Initial setup that can render some broken geometry.
This commit is contained in:
@@ -10,6 +10,21 @@
|
||||
#include "D3Dcompiler.h"
|
||||
#include <DirectXMath.h>
|
||||
|
||||
const int VERTEX_CHUNK_SIZE = 512 * 1024;
|
||||
|
||||
const int XYZ_SIZE = 4 * VERTEX_CHUNK_SIZE;
|
||||
const int COLOR_SIZE = 1 * VERTEX_CHUNK_SIZE;
|
||||
const int ST0_SIZE = 2 * VERTEX_CHUNK_SIZE;
|
||||
const int ST1_SIZE = 2 * VERTEX_CHUNK_SIZE;
|
||||
|
||||
const int XYZ_OFFSET = 0;
|
||||
const int COLOR_OFFSET = XYZ_OFFSET + XYZ_SIZE;
|
||||
const int ST0_OFFSET = COLOR_OFFSET + COLOR_SIZE;
|
||||
const int ST1_OFFSET = ST0_OFFSET + ST0_SIZE;
|
||||
|
||||
static const int VERTEX_BUFFER_SIZE = XYZ_SIZE + COLOR_SIZE + ST0_SIZE + ST1_SIZE;
|
||||
static const int INDEX_BUFFER_SIZE = 2 * 1024 * 1024;
|
||||
|
||||
// Helper function for acquiring the first available hardware adapter that supports Direct3D 12.
|
||||
// If no such adapter can be found, *ppAdapter will be set to nullptr.
|
||||
static void get_hardware_adapter(IDXGIFactory4* p_factory, IDXGIAdapter1** pp_adapter) {
|
||||
@@ -68,11 +83,11 @@ static void wait_for_queue_idle(ID3D12CommandQueue* command_queue) {
|
||||
}
|
||||
}
|
||||
|
||||
static void record_and_run_commands(ID3D12CommandAllocator* command_allocator, ID3D12CommandQueue* command_queue,
|
||||
std::function<void(ID3D12GraphicsCommandList*)> recorder) {
|
||||
static void record_and_run_commands(ID3D12CommandQueue* command_queue, std::function<void(ID3D12GraphicsCommandList*)> recorder) {
|
||||
dx.helper_command_allocator->Reset();
|
||||
|
||||
ID3D12GraphicsCommandList* command_list;
|
||||
DX_CHECK(dx.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, command_allocator,
|
||||
DX_CHECK(dx.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, dx.helper_command_allocator,
|
||||
nullptr, IID_PPV_ARGS(&command_list)));
|
||||
|
||||
recorder(command_list);
|
||||
@@ -168,14 +183,20 @@ void dx_initialize() {
|
||||
}
|
||||
|
||||
DX_CHECK(dx.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&dx.command_allocator)));
|
||||
DX_CHECK(dx.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&dx.helper_command_allocator)));
|
||||
|
||||
//
|
||||
// Create the root signature.
|
||||
//
|
||||
{
|
||||
CD3DX12_DESCRIPTOR_RANGE ranges[1];
|
||||
ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0);
|
||||
CD3DX12_DESCRIPTOR_RANGE ranges[2];
|
||||
ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
|
||||
ranges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 1);
|
||||
|
||||
CD3DX12_ROOT_PARAMETER root_parameters[1];
|
||||
CD3DX12_ROOT_PARAMETER root_parameters[3];
|
||||
root_parameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);
|
||||
root_parameters[1].InitAsDescriptorTable(1, &ranges[1], D3D12_SHADER_VISIBILITY_PIXEL);
|
||||
root_parameters[2].InitAsConstants(32, 0);
|
||||
|
||||
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
||||
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
@@ -219,8 +240,8 @@ void dx_initialize() {
|
||||
// Define the vertex input layout.
|
||||
D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 2, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
|
||||
};
|
||||
|
||||
// Describe and create the graphics pipeline state object (PSO).
|
||||
@@ -230,6 +251,7 @@ void dx_initialize() {
|
||||
psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get());
|
||||
psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get());
|
||||
psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
|
||||
|
||||
psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
|
||||
psoDesc.DepthStencilState.DepthEnable = FALSE;
|
||||
psoDesc.DepthStencilState.StencilEnable = FALSE;
|
||||
@@ -247,51 +269,6 @@ void dx_initialize() {
|
||||
// to record yet. The main loop expects it to be closed, so close it now.
|
||||
DX_CHECK(dx.command_list->Close());
|
||||
|
||||
// Create the vertex buffer.
|
||||
{
|
||||
struct Vertex
|
||||
{
|
||||
XMFLOAT3 position;
|
||||
XMFLOAT2 color;
|
||||
};
|
||||
|
||||
float aspect_ratio = float(glConfig.vidWidth) / float(glConfig.vidHeight);
|
||||
|
||||
// Define the geometry for a triangle.
|
||||
Vertex triangleVertices[] =
|
||||
{
|
||||
{ { 0.0f, 0.5f * aspect_ratio, 0.0f }, { 0.5f, 0.0f } },
|
||||
{ { 0.5f, -0.5f * aspect_ratio, 0.0f }, { 1.0f, 1.0f } },
|
||||
{ { -0.5f, -0.5f * aspect_ratio, 0.0f }, { 0.0f, 1.0f } }
|
||||
};
|
||||
|
||||
const UINT vertexBufferSize = sizeof(triangleVertices);
|
||||
|
||||
// Note: using upload heaps to transfer static data like vert buffers is not
|
||||
// recommended. Every time the GPU needs it, the upload heap will be marshalled
|
||||
// over. Please read up on Default Heap usage. An upload heap is used here for
|
||||
// code simplicity and because there are very few verts to actually transfer.
|
||||
DX_CHECK(dx.device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize),
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&dx.vertex_buffer)));
|
||||
|
||||
// Copy the triangle data to the vertex buffer.
|
||||
UINT8* pVertexDataBegin;
|
||||
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
|
||||
DX_CHECK(dx.vertex_buffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)));
|
||||
memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
|
||||
dx.vertex_buffer->Unmap(0, nullptr);
|
||||
|
||||
// Initialize the vertex buffer view.
|
||||
dx.vertex_buffer_view.BufferLocation = dx.vertex_buffer->GetGPUVirtualAddress();
|
||||
dx.vertex_buffer_view.StrideInBytes = sizeof(Vertex);
|
||||
dx.vertex_buffer_view.SizeInBytes = vertexBufferSize;
|
||||
}
|
||||
|
||||
// Create synchronization objects.
|
||||
{
|
||||
DX_CHECK(dx.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&dx.fence)));
|
||||
@@ -310,6 +287,30 @@ void dx_initialize() {
|
||||
wait_for_previous_frame();
|
||||
}
|
||||
|
||||
//
|
||||
// Geometry buffers.
|
||||
//
|
||||
{
|
||||
// store geometry in upload heap since Q3 regenerates it every frame
|
||||
DX_CHECK(dx.device->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(VERTEX_BUFFER_SIZE + INDEX_BUFFER_SIZE),
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&dx.geometry_buffer)));
|
||||
|
||||
void* p_data;
|
||||
CD3DX12_RANGE read_range(0, 0);
|
||||
DX_CHECK(dx.geometry_buffer->Map(0, &read_range, &p_data));
|
||||
|
||||
dx.vertex_buffer_ptr = static_cast<byte*>(p_data);
|
||||
assert(((size_t)dx.vertex_buffer_ptr & 0xffff) == 0);
|
||||
|
||||
dx.index_buffer_ptr = static_cast<byte*>(p_data) + VERTEX_BUFFER_SIZE;
|
||||
assert(((size_t)dx.index_buffer_ptr & 0xffff) == 0);
|
||||
}
|
||||
|
||||
dx.active = true;
|
||||
}
|
||||
|
||||
@@ -319,6 +320,9 @@ void dx_shutdown() {
|
||||
dx.command_allocator->Release();
|
||||
dx.command_allocator = nullptr;
|
||||
|
||||
dx.helper_command_allocator->Release();
|
||||
dx.helper_command_allocator = nullptr;
|
||||
|
||||
for (int i = 0; i < D3D_FRAME_COUNT; i++) {
|
||||
dx.render_targets[i]->Release();
|
||||
}
|
||||
@@ -347,8 +351,8 @@ void dx_shutdown() {
|
||||
::CloseHandle(dx.fence_event);
|
||||
dx.fence_event = NULL;
|
||||
|
||||
dx.vertex_buffer->Release();
|
||||
dx.vertex_buffer = nullptr;
|
||||
dx.geometry_buffer->Release();
|
||||
dx.geometry_buffer = nullptr;
|
||||
|
||||
dx.device->Release();
|
||||
dx.device = nullptr;
|
||||
@@ -361,6 +365,11 @@ void dx_release_resources() {
|
||||
}
|
||||
}
|
||||
Com_Memset(&dx_world, 0, sizeof(dx_world));
|
||||
|
||||
// Reset geometry buffer's current offsets.
|
||||
dx.xyz_elements = 0;
|
||||
dx.color_st_elements = 0;
|
||||
dx.index_buffer_offset = 0;
|
||||
}
|
||||
|
||||
Dx_Image dx_create_image(int width, int height, DXGI_FORMAT format, int mip_levels, bool repeat_texture, int image_index) {
|
||||
@@ -401,6 +410,8 @@ Dx_Image dx_create_image(int width, int height, DXGI_FORMAT format, int mip_leve
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle;
|
||||
handle.ptr = dx.srv_heap->GetCPUDescriptorHandleForHeapStart().ptr + image_index * dx.srv_descriptor_size;
|
||||
dx.device->CreateShaderResourceView(image.texture, &srv_desc, handle);
|
||||
|
||||
dx_world.current_image_indices[glState.currenttmu] = image_index;
|
||||
}
|
||||
|
||||
return image;
|
||||
@@ -423,8 +434,7 @@ void dx_upload_image_data(ID3D12Resource* texture, int width, int height, bool m
|
||||
texture_data.RowPitch = width * bytes_per_pixel;
|
||||
texture_data.SlicePitch = texture_data.RowPitch * height;
|
||||
|
||||
record_and_run_commands(dx.command_allocator, dx.command_queue,
|
||||
[&texture, &upload_texture, &texture_data](ID3D12GraphicsCommandList* command_list)
|
||||
record_and_run_commands(dx.command_queue, [&texture, &upload_texture, &texture_data](ID3D12GraphicsCommandList* command_list)
|
||||
{
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(texture,
|
||||
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST));
|
||||
@@ -436,6 +446,259 @@ void dx_upload_image_data(ID3D12Resource* texture, int width, int height, bool m
|
||||
});
|
||||
}
|
||||
|
||||
ID3D12PipelineState* dx_find_pipeline(const Vk_Pipeline_Def& def) {
|
||||
return dx.pipeline_state;
|
||||
}
|
||||
|
||||
static void get_mvp_transform(float* mvp) {
|
||||
if (backEnd.projection2D) {
|
||||
float mvp0 = 2.0f / glConfig.vidWidth;
|
||||
float mvp5 = 2.0f / glConfig.vidHeight;
|
||||
|
||||
mvp[0] = mvp0; mvp[1] = 0.0f; mvp[2] = 0.0f; mvp[3] = 0.0f;
|
||||
mvp[4] = 0.0f; mvp[5] = -mvp5; mvp[6] = 0.0f; mvp[7] = 0.0f;
|
||||
mvp[8] = 0.0f; mvp[9] = 0.0f; mvp[10] = 1.0f; mvp[11] = 0.0f;
|
||||
mvp[12] = -1.0f; mvp[13] = 1.0f; mvp[14] = 0.0f; mvp[15] = 1.0f;
|
||||
|
||||
} else {
|
||||
const float* p = backEnd.viewParms.projectionMatrix;
|
||||
|
||||
// update q3's proj matrix (opengl) to vulkan conventions: z - [0, 1] instead of [-1, 1] and invert y direction
|
||||
float zNear = r_znear->value;
|
||||
float zFar = backEnd.viewParms.zFar;
|
||||
float P10 = -zFar / (zFar - zNear);
|
||||
float P14 = -zFar*zNear / (zFar - zNear);
|
||||
float P5 = -p[5];
|
||||
|
||||
float proj[16] = {
|
||||
p[0], p[1], p[2], p[3],
|
||||
p[4], P5, p[6], p[7],
|
||||
p[8], p[9], P10, p[11],
|
||||
p[12], p[13], P14, p[15]
|
||||
};
|
||||
|
||||
myGlMultMatrix(vk_world.modelview_transform, proj, mvp);
|
||||
}
|
||||
}
|
||||
|
||||
void dx_bind_geometry() {
|
||||
if (!dx.active)
|
||||
return;
|
||||
|
||||
// xyz stream
|
||||
{
|
||||
if ((dx.xyz_elements + tess.numVertexes) * sizeof(vec4_t) > XYZ_SIZE)
|
||||
ri.Error(ERR_DROP, "dx_bind_geometry: vertex buffer overflow (xyz)\n");
|
||||
|
||||
byte* dst = dx.vertex_buffer_ptr + XYZ_OFFSET + dx.xyz_elements * sizeof(vec4_t);
|
||||
Com_Memcpy(dst, tess.xyz, tess.numVertexes * sizeof(vec4_t));
|
||||
|
||||
uint32_t xyz_offset = XYZ_OFFSET + dx.xyz_elements * sizeof(vec4_t);
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW xyz_view;
|
||||
xyz_view.BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + xyz_offset;
|
||||
xyz_view.SizeInBytes = static_cast<UINT>(tess.numVertexes * sizeof(vec4_t));
|
||||
xyz_view.StrideInBytes = static_cast<UINT>(sizeof(vec4_t));
|
||||
dx.command_list->IASetVertexBuffers(0, 1, &xyz_view);
|
||||
|
||||
dx.xyz_elements += tess.numVertexes;
|
||||
}
|
||||
|
||||
// indexes stream
|
||||
{
|
||||
std::size_t indexes_size = tess.numIndexes * sizeof(uint32_t);
|
||||
|
||||
if (dx.index_buffer_offset + indexes_size > INDEX_BUFFER_SIZE)
|
||||
ri.Error(ERR_DROP, "dx_bind_geometry: index buffer overflow\n");
|
||||
|
||||
byte* dst = dx.index_buffer_ptr + dx.index_buffer_offset;
|
||||
Com_Memcpy(dst, tess.indexes, indexes_size);
|
||||
|
||||
D3D12_INDEX_BUFFER_VIEW index_view;
|
||||
index_view.BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + VERTEX_BUFFER_SIZE + dx.index_buffer_offset;
|
||||
index_view.SizeInBytes = static_cast<UINT>(indexes_size);
|
||||
index_view.Format = DXGI_FORMAT_R32_UINT;
|
||||
dx.command_list->IASetIndexBuffer(&index_view);
|
||||
|
||||
dx.index_buffer_offset += static_cast<int>(indexes_size);
|
||||
}
|
||||
|
||||
//
|
||||
// Specify push constants.
|
||||
//
|
||||
float root_constants[16 + 12 + 4]; // mvp transform + eye transform + clipping plane in eye space
|
||||
|
||||
get_mvp_transform(root_constants);
|
||||
int root_constant_count = 16;
|
||||
|
||||
if (backEnd.viewParms.isPortal) {
|
||||
// Eye space transform.
|
||||
// NOTE: backEnd.or.modelMatrix incorporates s_flipMatrix, so it should be taken into account
|
||||
// when computing clipping plane too.
|
||||
float* eye_xform = root_constants + 16;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
eye_xform[i] = backEnd.or.modelMatrix[(i%4)*4 + i/4 ];
|
||||
}
|
||||
|
||||
// Clipping plane in eye coordinates.
|
||||
float world_plane[4];
|
||||
world_plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||||
world_plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||||
world_plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||||
world_plane[3] = backEnd.viewParms.portalPlane.dist;
|
||||
|
||||
float eye_plane[4];
|
||||
eye_plane[0] = DotProduct (backEnd.viewParms.or.axis[0], world_plane);
|
||||
eye_plane[1] = DotProduct (backEnd.viewParms.or.axis[1], world_plane);
|
||||
eye_plane[2] = DotProduct (backEnd.viewParms.or.axis[2], world_plane);
|
||||
eye_plane[3] = DotProduct (world_plane, backEnd.viewParms.or.origin) - world_plane[3];
|
||||
|
||||
// Apply s_flipMatrix to be in the same coordinate system as eye_xfrom.
|
||||
root_constants[28] = -eye_plane[1];
|
||||
root_constants[29] = eye_plane[2];
|
||||
root_constants[30] = -eye_plane[0];
|
||||
root_constants[31] = eye_plane[3];
|
||||
|
||||
root_constant_count += 16;
|
||||
}
|
||||
dx.command_list->SetGraphicsRoot32BitConstants(2, root_constant_count, root_constants, 0);
|
||||
}
|
||||
|
||||
static D3D12_RECT get_viewport_rect() {
|
||||
D3D12_RECT r;
|
||||
if (backEnd.projection2D) {
|
||||
r.left = 0.0f;
|
||||
r.top = 0.0f;
|
||||
r.right = glConfig.vidWidth;
|
||||
r.bottom = glConfig.vidHeight;
|
||||
} else {
|
||||
r.left = backEnd.viewParms.viewportX;
|
||||
r.top = glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight);
|
||||
r.right = r.left + backEnd.viewParms.viewportWidth;
|
||||
r.bottom = r.top + backEnd.viewParms.viewportHeight;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static D3D12_VIEWPORT get_viewport(Vk_Depth_Range depth_range) {
|
||||
D3D12_RECT r = get_viewport_rect();
|
||||
|
||||
D3D12_VIEWPORT viewport;
|
||||
viewport.TopLeftX = (float)r.left;
|
||||
viewport.TopLeftY = (float)r.top;
|
||||
viewport.Width = (float)(r.right - r.left);
|
||||
viewport.Height = (float)(r.bottom - r.top);
|
||||
|
||||
if (depth_range == Vk_Depth_Range::force_zero) {
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 0.0f;
|
||||
} else if (depth_range == Vk_Depth_Range::force_one) {
|
||||
viewport.MinDepth = 1.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
} else if (depth_range == Vk_Depth_Range::weapon) {
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 0.3f;
|
||||
} else {
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
}
|
||||
return viewport;
|
||||
}
|
||||
|
||||
static D3D12_RECT get_scissor_rect() {
|
||||
D3D12_RECT r = get_viewport_rect();
|
||||
|
||||
if (r.left < 0)
|
||||
r.left = 0;
|
||||
if (r.top < 0)
|
||||
r.top = 0;
|
||||
|
||||
if (r.right > glConfig.vidWidth)
|
||||
r.right = glConfig.vidWidth;
|
||||
if (r.bottom > glConfig.vidHeight)
|
||||
r.bottom = glConfig.vidHeight;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void dx_shade_geometry(ID3D12PipelineState* pipeline_state, bool multitexture, Vk_Depth_Range depth_range, bool indexed) {
|
||||
// color
|
||||
{
|
||||
if ((dx.color_st_elements + tess.numVertexes) * sizeof(color4ub_t) > COLOR_SIZE)
|
||||
ri.Error(ERR_DROP, "vulkan: vertex buffer overflow (color)\n");
|
||||
|
||||
byte* dst = dx.vertex_buffer_ptr + COLOR_OFFSET + dx.color_st_elements * sizeof(color4ub_t);
|
||||
Com_Memcpy(dst, tess.svars.colors, tess.numVertexes * sizeof(color4ub_t));
|
||||
}
|
||||
// st0
|
||||
{
|
||||
if ((dx.color_st_elements + tess.numVertexes) * sizeof(vec2_t) > ST0_SIZE)
|
||||
ri.Error(ERR_DROP, "vulkan: vertex buffer overflow (st0)\n");
|
||||
|
||||
byte* dst = dx.vertex_buffer_ptr + ST0_OFFSET + dx.color_st_elements * sizeof(vec2_t);
|
||||
Com_Memcpy(dst, tess.svars.texcoords[0], tess.numVertexes * sizeof(vec2_t));
|
||||
}
|
||||
// st1
|
||||
if (multitexture) {
|
||||
if ((dx.color_st_elements + tess.numVertexes) * sizeof(vec2_t) > ST1_SIZE)
|
||||
ri.Error(ERR_DROP, "vulkan: vertex buffer overflow (st1)\n");
|
||||
|
||||
byte* dst = dx.vertex_buffer_ptr + ST1_OFFSET + dx.color_st_elements * sizeof(vec2_t);
|
||||
Com_Memcpy(dst, tess.svars.texcoords[1], tess.numVertexes * sizeof(vec2_t));
|
||||
}
|
||||
|
||||
// configure vertex data stream
|
||||
D3D12_VERTEX_BUFFER_VIEW color_st_views[3];
|
||||
color_st_views[0].BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + COLOR_OFFSET + dx.color_st_elements * sizeof(color4ub_t);
|
||||
color_st_views[0].SizeInBytes = static_cast<UINT>(tess.numVertexes * sizeof(color4ub_t));
|
||||
color_st_views[0].StrideInBytes = static_cast<UINT>(sizeof(color4ub_t));
|
||||
|
||||
color_st_views[1].BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + ST0_OFFSET + dx.color_st_elements * sizeof(vec2_t);
|
||||
color_st_views[1].SizeInBytes = static_cast<UINT>(tess.numVertexes * sizeof(vec2_t));
|
||||
color_st_views[1].StrideInBytes = static_cast<UINT>(sizeof(vec2_t));
|
||||
|
||||
color_st_views[2].BufferLocation = dx.geometry_buffer->GetGPUVirtualAddress() + ST1_OFFSET + dx.color_st_elements * sizeof(vec2_t);
|
||||
color_st_views[2].SizeInBytes = static_cast<UINT>(tess.numVertexes * sizeof(vec2_t));
|
||||
color_st_views[2].StrideInBytes = static_cast<UINT>(sizeof(vec2_t));
|
||||
|
||||
dx.command_list->IASetVertexBuffers(1, multitexture ? 3 : 2, color_st_views);
|
||||
|
||||
dx.color_st_elements += tess.numVertexes;
|
||||
|
||||
// bind descriptor sets
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE handle = dx.srv_heap->GetGPUDescriptorHandleForHeapStart();
|
||||
handle.ptr += dx.srv_descriptor_size * dx_world.current_image_indices[0];
|
||||
dx.command_list->SetGraphicsRootDescriptorTable(0, handle);
|
||||
|
||||
if (multitexture) {
|
||||
handle = dx.srv_heap->GetGPUDescriptorHandleForHeapStart();
|
||||
handle.ptr += dx.srv_descriptor_size * dx_world.current_image_indices[1];
|
||||
dx.command_list->SetGraphicsRootDescriptorTable(1, handle);
|
||||
}
|
||||
|
||||
// bind pipeline
|
||||
dx.command_list->SetPipelineState(pipeline_state);
|
||||
|
||||
// configure pipeline's dynamic state
|
||||
D3D12_RECT scissor_rect = get_scissor_rect();
|
||||
dx.command_list->RSSetScissorRects(1, &scissor_rect);
|
||||
|
||||
D3D12_VIEWPORT viewport = get_viewport(depth_range);
|
||||
dx.command_list->RSSetViewports(1, &viewport);
|
||||
|
||||
/*if (tess.shader->polygonOffset) {
|
||||
vkCmdSetDepthBias(vk.command_buffer, r_offsetUnits->value, 0.0f, r_offsetFactor->value);
|
||||
}*/
|
||||
|
||||
// issue draw call
|
||||
if (indexed)
|
||||
dx.command_list->DrawIndexedInstanced(tess.numIndexes, 1, 0, 0, 0);
|
||||
else
|
||||
dx.command_list->DrawInstanced(tess.numVertexes, 1, 0, 0);
|
||||
|
||||
vk_world.dirty_depth_attachment = true;
|
||||
}
|
||||
|
||||
void dx_begin_frame() {
|
||||
// Command list allocators can only be reset when the associated
|
||||
// command lists have finished execution on the GPU; apps should use
|
||||
@@ -475,17 +738,18 @@ void dx_begin_frame() {
|
||||
const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
|
||||
dx.command_list->ClearRenderTargetView(rtv_handle, clearColor, 0, nullptr);
|
||||
dx.command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
dx.command_list->IASetVertexBuffers(0, 1, &dx.vertex_buffer_view);
|
||||
dx.command_list->DrawInstanced(3, 1, 0, 0);
|
||||
|
||||
// Indicate that the back buffer will now be used to present.
|
||||
dx.xyz_elements = 0;
|
||||
dx.color_st_elements = 0;
|
||||
dx.index_buffer_offset = 0;
|
||||
}
|
||||
|
||||
void dx_end_frame() {
|
||||
dx.command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(dx.render_targets[dx.frame_index],
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
|
||||
|
||||
DX_CHECK(dx.command_list->Close());
|
||||
}
|
||||
|
||||
void dx_end_frame() {
|
||||
// Execute the command list.
|
||||
ID3D12CommandList* ppCommandLists[] = { dx.command_list };
|
||||
dx.command_queue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
|
||||
|
||||
Reference in New Issue
Block a user