285 lines
12 KiB
C
285 lines
12 KiB
C
#include "rendertarget.h"
|
|
|
|
#include <Kinc/Graphics5/RenderTarget.h>
|
|
#include <Kinc/Graphics5/Texture.h>
|
|
#include <kinc/backend/SystemMicrosoft.h>
|
|
|
|
#ifdef KORE_WINDOWS
|
|
#include <dxgi1_4.h>
|
|
#endif
|
|
|
|
#ifdef KORE_DIRECT3D_HAS_NO_SWAPCHAIN
|
|
extern ID3D12Resource *swapChainRenderTargets[QUEUE_SLOT_COUNT];
|
|
#endif
|
|
|
|
static void WaitForFence(ID3D12Fence *fence, UINT64 completionValue, HANDLE waitEvent) {
|
|
if (fence->GetCompletedValue() < completionValue) {
|
|
fence->SetEventOnCompletion(completionValue, waitEvent);
|
|
WaitForSingleObject(waitEvent, INFINITE);
|
|
}
|
|
}
|
|
|
|
static void createRenderTargetView(ID3D12Resource *renderTarget, ID3D12DescriptorHeap *renderTargetDescriptorHeap, DXGI_FORMAT format) {
|
|
// const D3D12_RESOURCE_DESC resourceDesc = renderTarget->lpVtbl->GetDesc(renderTarget);
|
|
|
|
D3D12_RENDER_TARGET_VIEW_DESC viewDesc;
|
|
viewDesc.Format = format;
|
|
viewDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
|
viewDesc.Texture2D.MipSlice = 0;
|
|
viewDesc.Texture2D.PlaneSlice = 0;
|
|
|
|
device->CreateRenderTargetView(renderTarget, &viewDesc, renderTargetDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
|
}
|
|
|
|
static DXGI_FORMAT convertFormat(kinc_g5_render_target_format_t format) {
|
|
switch (format) {
|
|
case KINC_G5_RENDER_TARGET_FORMAT_128BIT_FLOAT:
|
|
return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
|
case KINC_G5_RENDER_TARGET_FORMAT_64BIT_FLOAT:
|
|
return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
|
case KINC_G5_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT:
|
|
return DXGI_FORMAT_R32_FLOAT;
|
|
case KINC_G5_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT:
|
|
return DXGI_FORMAT_R16_FLOAT;
|
|
case KINC_G5_RENDER_TARGET_FORMAT_8BIT_RED:
|
|
return DXGI_FORMAT_R8_UNORM;
|
|
case KINC_G5_RENDER_TARGET_FORMAT_32BIT:
|
|
default:
|
|
#ifdef KORE_WINDOWS
|
|
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
#else
|
|
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
extern "C" void kinc_memory_emergency();
|
|
|
|
static void render_target_init(kinc_g5_render_target_t *render_target, int width, int height, kinc_g5_render_target_format_t format, int depthBufferBits,
|
|
int stencilBufferBits, int samples_per_pixel, int framebuffer_index) {
|
|
render_target->texWidth = render_target->width = width;
|
|
render_target->texHeight = render_target->height = height;
|
|
render_target->impl.stage = 0;
|
|
render_target->impl.stage_depth = -1;
|
|
render_target->impl.renderTargetReadback = NULL;
|
|
render_target->impl.framebuffer_index = framebuffer_index;
|
|
|
|
DXGI_FORMAT dxgiFormat = convertFormat(format);
|
|
|
|
D3D12_CLEAR_VALUE clearValue;
|
|
clearValue.Format = dxgiFormat;
|
|
clearValue.Color[0] = 0.0f;
|
|
clearValue.Color[1] = 0.0f;
|
|
clearValue.Color[2] = 0.0f;
|
|
clearValue.Color[3] = 1.0f;
|
|
|
|
D3D12_HEAP_PROPERTIES heapProperties;
|
|
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
heapProperties.CreationNodeMask = 1;
|
|
heapProperties.VisibleNodeMask = 1;
|
|
|
|
D3D12_RESOURCE_DESC texResourceDesc;
|
|
texResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
texResourceDesc.Alignment = 0;
|
|
texResourceDesc.Width = render_target->texWidth;
|
|
texResourceDesc.Height = render_target->texHeight;
|
|
texResourceDesc.DepthOrArraySize = 1;
|
|
texResourceDesc.MipLevels = 1;
|
|
texResourceDesc.Format = dxgiFormat;
|
|
texResourceDesc.SampleDesc.Count = 1;
|
|
texResourceDesc.SampleDesc.Quality = 0;
|
|
texResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
texResourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
|
|
|
HRESULT result = device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &texResourceDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue,
|
|
IID_GRAPHICS_PPV_ARGS(&render_target->impl.renderTarget));
|
|
if (result != S_OK) {
|
|
for (int i = 0; i < 10; ++i) {
|
|
kinc_memory_emergency();
|
|
result = device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &texResourceDesc, D3D12_RESOURCE_STATE_RENDER_TARGET, &clearValue,
|
|
IID_GRAPHICS_PPV_ARGS(&render_target->impl.renderTarget));
|
|
if (result == S_OK) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
D3D12_RENDER_TARGET_VIEW_DESC view;
|
|
// const D3D12_RESOURCE_DESC resourceDesc = render_target->impl.renderTarget->lpVtbl->GetDesc(render_target->impl.renderTarget);
|
|
view.Format = dxgiFormat;
|
|
view.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
|
view.Texture2D.MipSlice = 0;
|
|
view.Texture2D.PlaneSlice = 0;
|
|
|
|
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
|
|
heapDesc.NumDescriptors = 1;
|
|
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
|
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
|
device->CreateDescriptorHeap(&heapDesc, IID_GRAPHICS_PPV_ARGS(&render_target->impl.renderTargetDescriptorHeap));
|
|
|
|
device->CreateRenderTargetView(render_target->impl.renderTarget, &view,
|
|
render_target->impl.renderTargetDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
|
|
|
D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {};
|
|
descriptorHeapDesc.NumDescriptors = 1;
|
|
|
|
descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
|
descriptorHeapDesc.NodeMask = 0;
|
|
descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
|
|
|
device->CreateDescriptorHeap(&descriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(&render_target->impl.srvDescriptorHeap));
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc = {0};
|
|
shaderResourceViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
shaderResourceViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
shaderResourceViewDesc.Format = dxgiFormat;
|
|
shaderResourceViewDesc.Texture2D.MipLevels = 1;
|
|
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
|
|
shaderResourceViewDesc.Texture2D.ResourceMinLODClamp = 0.0f;
|
|
|
|
device->CreateShaderResourceView(render_target->impl.renderTarget, &shaderResourceViewDesc,
|
|
render_target->impl.srvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
|
|
|
if (depthBufferBits > 0) {
|
|
D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
|
|
dsvHeapDesc.NumDescriptors = 1;
|
|
dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
|
|
dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
|
device->CreateDescriptorHeap(&dsvHeapDesc, IID_GRAPHICS_PPV_ARGS(&render_target->impl.depthStencilDescriptorHeap));
|
|
|
|
D3D12_RESOURCE_DESC depthTexture;
|
|
depthTexture.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
|
depthTexture.Alignment = 0;
|
|
depthTexture.Width = width;
|
|
depthTexture.Height = height;
|
|
depthTexture.DepthOrArraySize = 1;
|
|
depthTexture.MipLevels = 1;
|
|
depthTexture.Format = DXGI_FORMAT_D32_FLOAT;
|
|
depthTexture.SampleDesc.Count = 1;
|
|
depthTexture.SampleDesc.Quality = 0;
|
|
depthTexture.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
|
depthTexture.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
|
|
|
D3D12_CLEAR_VALUE clearValue;
|
|
clearValue.Format = DXGI_FORMAT_D32_FLOAT;
|
|
clearValue.DepthStencil.Depth = 1.0f;
|
|
clearValue.DepthStencil.Stencil = 0;
|
|
|
|
D3D12_HEAP_PROPERTIES heapProperties;
|
|
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
|
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
|
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
|
heapProperties.CreationNodeMask = 1;
|
|
heapProperties.VisibleNodeMask = 1;
|
|
|
|
HRESULT result = device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &depthTexture, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue,
|
|
IID_GRAPHICS_PPV_ARGS(&render_target->impl.depthStencilTexture));
|
|
if (result != S_OK) {
|
|
for (int i = 0; i < 10; ++i) {
|
|
kinc_memory_emergency();
|
|
result = device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &depthTexture, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue,
|
|
IID_GRAPHICS_PPV_ARGS(&render_target->impl.depthStencilTexture));
|
|
if (result == S_OK) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
device->CreateDepthStencilView(render_target->impl.depthStencilTexture, NULL,
|
|
render_target->impl.depthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
|
|
|
// Reading depth texture as a shader resource
|
|
D3D12_DESCRIPTOR_HEAP_DESC srvDepthHeapDesc = {};
|
|
srvDepthHeapDesc.NumDescriptors = 1;
|
|
srvDepthHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
|
srvDepthHeapDesc.NodeMask = 0;
|
|
srvDepthHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
|
device->CreateDescriptorHeap(&srvDepthHeapDesc, IID_GRAPHICS_PPV_ARGS(&render_target->impl.srvDepthDescriptorHeap));
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDepthViewDesc = {0};
|
|
srvDepthViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
|
srvDepthViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
|
srvDepthViewDesc.Format = DXGI_FORMAT_R32_FLOAT;
|
|
srvDepthViewDesc.Texture2D.MipLevels = 1;
|
|
srvDepthViewDesc.Texture2D.MostDetailedMip = 0;
|
|
srvDepthViewDesc.Texture2D.ResourceMinLODClamp = 0.0f;
|
|
device->CreateShaderResourceView(render_target->impl.depthStencilTexture, &srvDepthViewDesc,
|
|
render_target->impl.srvDepthDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
|
}
|
|
else {
|
|
render_target->impl.depthStencilDescriptorHeap = NULL;
|
|
render_target->impl.depthStencilTexture = NULL;
|
|
render_target->impl.srvDepthDescriptorHeap = NULL;
|
|
}
|
|
|
|
render_target->impl.scissor.top = 0;
|
|
render_target->impl.scissor.left = 0;
|
|
render_target->impl.scissor.right = width;
|
|
render_target->impl.scissor.bottom = height;
|
|
|
|
render_target->impl.viewport.TopLeftX = 0.0f;
|
|
render_target->impl.viewport.TopLeftY = 0.0f;
|
|
render_target->impl.viewport.Width = (float)width;
|
|
render_target->impl.viewport.Height = (float)height;
|
|
render_target->impl.viewport.MinDepth = 0.0f;
|
|
render_target->impl.viewport.MaxDepth = 1.0f;
|
|
|
|
if (framebuffer_index >= 0) {
|
|
#ifdef KORE_DIRECT3D_HAS_NO_SWAPCHAIN
|
|
render_target->impl.renderTarget = swapChainRenderTargets[framebuffer_index];
|
|
#else
|
|
IDXGISwapChain *swapChain = kinc_dx_current_window()->swapChain;
|
|
swapChain->GetBuffer(framebuffer_index, IID_PPV_ARGS(&render_target->impl.renderTarget));
|
|
wchar_t buffer[128];
|
|
wsprintf(buffer, L"Backbuffer (index %i)", framebuffer_index);
|
|
render_target->impl.renderTarget->SetName(buffer);
|
|
#endif
|
|
createRenderTargetView(render_target->impl.renderTarget, render_target->impl.renderTargetDescriptorHeap, dxgiFormat);
|
|
}
|
|
}
|
|
|
|
void kinc_g5_render_target_init_with_multisampling(kinc_g5_render_target_t *target, int width, int height, kinc_g5_render_target_format_t format,
|
|
int depthBufferBits, int stencilBufferBits, int samples_per_pixel) {
|
|
render_target_init(target, width, height, format, depthBufferBits, stencilBufferBits, samples_per_pixel, -1);
|
|
}
|
|
|
|
static int framebuffer_count = 0;
|
|
|
|
void kinc_g5_render_target_init_framebuffer_with_multisampling(kinc_g5_render_target_t *target, int width, int height, kinc_g5_render_target_format_t format,
|
|
int depthBufferBits, int stencilBufferBits, int samples_per_pixel) {
|
|
render_target_init(target, width, height, format, depthBufferBits, stencilBufferBits, samples_per_pixel, framebuffer_count);
|
|
framebuffer_count += 1;
|
|
}
|
|
|
|
void kinc_g5_render_target_init_cube_with_multisampling(kinc_g5_render_target_t *render_target, int cubeMapSize, kinc_g5_render_target_format_t format,
|
|
int depthBufferBits, int stencilBufferBits, int samples_per_pixel) {
|
|
render_target->impl.stage = 0;
|
|
render_target->impl.stage_depth = -1;
|
|
}
|
|
|
|
void kinc_g5_render_target_destroy(kinc_g5_render_target_t *render_target) {
|
|
if (render_target->impl.framebuffer_index >= 0) {
|
|
framebuffer_count -= 1;
|
|
}
|
|
|
|
render_target->impl.renderTarget->Release();
|
|
render_target->impl.renderTargetDescriptorHeap->Release();
|
|
render_target->impl.srvDescriptorHeap->Release();
|
|
if (render_target->impl.depthStencilTexture != NULL) {
|
|
render_target->impl.depthStencilTexture->Release();
|
|
render_target->impl.depthStencilDescriptorHeap->Release();
|
|
render_target->impl.srvDepthDescriptorHeap->Release();
|
|
}
|
|
if (render_target->impl.renderTargetReadback != NULL) {
|
|
render_target->impl.renderTargetReadback->Release();
|
|
}
|
|
}
|
|
|
|
void kinc_g5_render_target_set_depth_stencil_from(kinc_g5_render_target_t *render_target, kinc_g5_render_target_t *source) {
|
|
render_target->impl.depthStencilDescriptorHeap = source->impl.depthStencilDescriptorHeap;
|
|
render_target->impl.srvDepthDescriptorHeap = source->impl.srvDepthDescriptorHeap;
|
|
render_target->impl.depthStencilTexture = source->impl.depthStencilTexture;
|
|
}
|