|
|
|
|
@ -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);
|
|
|
|
|
|