forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
2654
Kha/Kinc/Backends/Graphics5/Direct3D12/Sources/d3dx12.h
Normal file
2654
Kha/Kinc/Backends/Graphics5/Direct3D12/Sources/d3dx12.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,626 @@
|
||||
#include "commandlist.h"
|
||||
#include "indexbuffer.h"
|
||||
#include "pipeline.h"
|
||||
#include "vertexbuffer.h"
|
||||
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/math/core.h>
|
||||
#include <kinc/window.h>
|
||||
#ifdef KINC_WINDOWS
|
||||
#include <dxgi1_4.h>
|
||||
#undef CreateWindow
|
||||
#endif
|
||||
#include <kinc/system.h>
|
||||
#ifdef KINC_WINDOWS
|
||||
#include <kinc/backend/Windows.h>
|
||||
#endif
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
|
||||
/*IDXGIFactory4* dxgiFactory;
|
||||
ID3D12Device* device;
|
||||
ID3D12GraphicsCommandList* commandList;
|
||||
ID3D12CommandQueue* commandQueue;
|
||||
ID3D12CommandAllocator* commandAllocators[frameCount];
|
||||
unsigned currentFrame = 0;
|
||||
ID3D12Fence* fence;
|
||||
UINT64 window->current_fence_value[frameCount];
|
||||
HANDLE fenceEvent;
|
||||
ID3D12Resource* renderTargets[frameCount];
|
||||
ID3D12DescriptorHeap* rtvHeap;
|
||||
unsigned rtvDescriptorSize;
|
||||
ID3D12CommandAllocator* bundleAllocator;
|
||||
ID3D12RootSignature* rootSignature;
|
||||
D3D12_VIEWPORT screenViewport;
|
||||
D3D12_RECT scissorRect;
|
||||
ID3D12DescriptorHeap* cbvHeap;*/
|
||||
// ID3D12DeviceContext* context;
|
||||
// ID3D12RenderTargetView* renderTargetView;
|
||||
// ID3D12DepthStencilView* depthStencilView;
|
||||
|
||||
// ID3D12GraphicsCommandList* commandList;
|
||||
|
||||
extern "C" {
|
||||
ID3D12CommandQueue *commandQueue;
|
||||
#ifdef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
ID3D12Resource *swapChainRenderTargets[QUEUE_SLOT_COUNT];
|
||||
#else
|
||||
// IDXGISwapChain *swapChain;
|
||||
#endif
|
||||
}
|
||||
|
||||
// int window->width;
|
||||
// int window->height;
|
||||
// int window->new_width;
|
||||
// int window->new_height;
|
||||
|
||||
#ifndef KINC_WINDOWS
|
||||
#define DXGI_SWAP_CHAIN_DESC DXGI_SWAP_CHAIN_DESC1
|
||||
#define IDXGISwapChain IDXGISwapChain1
|
||||
#endif
|
||||
|
||||
struct RenderEnvironment {
|
||||
ID3D12Device *device;
|
||||
ID3D12CommandQueue *queue;
|
||||
#ifdef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
ID3D12Resource *renderTargets[QUEUE_SLOT_COUNT];
|
||||
#else
|
||||
IDXGISwapChain *swapChain;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef KINC_WINDOWS
|
||||
#ifdef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
extern "C" void createSwapChain(struct RenderEnvironment *env, int bufferCount);
|
||||
#else
|
||||
extern "C" void createSwapChain(struct RenderEnvironment *env, const DXGI_SWAP_CHAIN_DESC1 *desc);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern bool bilinearFiltering;
|
||||
|
||||
// ID3D12Resource* renderTarget;
|
||||
// ID3D12DescriptorHeap* renderTargetDescriptorHeap;
|
||||
|
||||
// static UINT64 window->current_fence_value;
|
||||
// static UINT64 window->current_fence_value[QUEUE_SLOT_COUNT];
|
||||
// static HANDLE window->frame_fence_events[QUEUE_SLOT_COUNT];
|
||||
// static ID3D12Fence *window->frame_fences[QUEUE_SLOT_COUNT];
|
||||
static ID3D12Fence *uploadFence;
|
||||
static ID3D12GraphicsCommandList *initCommandList;
|
||||
static ID3D12CommandAllocator *initCommandAllocator;
|
||||
|
||||
extern "C" struct RenderEnvironment createDeviceAndSwapChainHelper(D3D_FEATURE_LEVEL minimumFeatureLevel, const struct DXGI_SWAP_CHAIN_DESC *swapChainDesc) {
|
||||
struct RenderEnvironment result = {0};
|
||||
#ifdef KINC_WINDOWS
|
||||
kinc_microsoft_affirm(D3D12CreateDevice(NULL, minimumFeatureLevel, IID_PPV_ARGS(&result.device)));
|
||||
|
||||
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
|
||||
kinc_microsoft_affirm(result.device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&result.queue)));
|
||||
|
||||
IDXGIFactory4 *dxgiFactory;
|
||||
kinc_microsoft_affirm(CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)));
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapChainDescCopy = *swapChainDesc;
|
||||
kinc_microsoft_affirm(dxgiFactory->CreateSwapChain((IUnknown *)result.queue, &swapChainDescCopy, &result.swapChain));
|
||||
#else
|
||||
#ifdef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
createSwapChain(&result, QUEUE_SLOT_COUNT);
|
||||
#else
|
||||
createSwapChain(&result, swapChainDesc);
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static void waitForFence(ID3D12Fence *fence, UINT64 completionValue, HANDLE waitEvent) {
|
||||
if (fence->GetCompletedValue() < completionValue) {
|
||||
kinc_microsoft_affirm(fence->SetEventOnCompletion(completionValue, waitEvent));
|
||||
WaitForSingleObject(waitEvent, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void setupSwapChain(struct dx_window *window) {
|
||||
/*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(&renderTargetDescriptorHeap));*/
|
||||
|
||||
D3D12_RESOURCE_DESC depthTexture = {};
|
||||
depthTexture.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
depthTexture.Alignment = 0;
|
||||
depthTexture.Width = window->width;
|
||||
depthTexture.Height = window->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_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
|
||||
|
||||
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;
|
||||
|
||||
window->current_fence_value = 0;
|
||||
|
||||
for (int i = 0; i < QUEUE_SLOT_COUNT; ++i) {
|
||||
window->frame_fence_events[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
window->fence_values[i] = 0;
|
||||
device->CreateFence(window->current_fence_value, D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(&window->frame_fences[i]));
|
||||
}
|
||||
|
||||
//**swapChain->GetBuffer(window->current_backbuffer, IID_GRAPHICS_PPV_ARGS(&renderTarget));
|
||||
//**createRenderTargetView();
|
||||
}
|
||||
|
||||
#ifdef KINC_CONSOLE
|
||||
extern "C" void createDeviceAndSwapChain(struct dx_window *window);
|
||||
#else
|
||||
static void createDeviceAndSwapChain(struct dx_window *window) {
|
||||
#ifdef _DEBUG
|
||||
ID3D12Debug *debugController = NULL;
|
||||
D3D12GetDebugInterface(IID_PPV_ARGS(&debugController));
|
||||
debugController->EnableDebugLayer();
|
||||
#endif
|
||||
|
||||
struct DXGI_SWAP_CHAIN_DESC swapChainDesc;
|
||||
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
|
||||
|
||||
swapChainDesc.BufferCount = QUEUE_SLOT_COUNT;
|
||||
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.BufferDesc.Width = window->width;
|
||||
swapChainDesc.BufferDesc.Height = window->height;
|
||||
swapChainDesc.OutputWindow = kinc_windows_window_handle(window->window_index);
|
||||
swapChainDesc.SampleDesc.Count = 1;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
swapChainDesc.Windowed = true;
|
||||
|
||||
struct RenderEnvironment renderEnv = createDeviceAndSwapChainHelper(D3D_FEATURE_LEVEL_11_0, &swapChainDesc);
|
||||
|
||||
device = renderEnv.device;
|
||||
commandQueue = renderEnv.queue;
|
||||
|
||||
// swapChain = renderEnv.swapChain;
|
||||
|
||||
setupSwapChain(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void createRootSignature() {
|
||||
ID3DBlob *rootBlob;
|
||||
ID3DBlob *errorBlob;
|
||||
|
||||
D3D12_ROOT_PARAMETER parameters[4] = {};
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE range;
|
||||
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
range.NumDescriptors = (UINT)KINC_INTERNAL_G5_TEXTURE_COUNT;
|
||||
range.BaseShaderRegister = 0;
|
||||
range.RegisterSpace = 0;
|
||||
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
parameters[0].DescriptorTable.NumDescriptorRanges = 1;
|
||||
parameters[0].DescriptorTable.pDescriptorRanges = ⦥
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE range2;
|
||||
range2.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
|
||||
range2.NumDescriptors = (UINT)KINC_INTERNAL_G5_TEXTURE_COUNT;
|
||||
range2.BaseShaderRegister = 0;
|
||||
range2.RegisterSpace = 0;
|
||||
range2.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
parameters[1].DescriptorTable.NumDescriptorRanges = 1;
|
||||
parameters[1].DescriptorTable.pDescriptorRanges = &range2;
|
||||
|
||||
parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
|
||||
parameters[2].Descriptor.ShaderRegister = 0;
|
||||
parameters[2].Descriptor.RegisterSpace = 0;
|
||||
|
||||
parameters[3].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
parameters[3].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||
parameters[3].Descriptor.ShaderRegister = 0;
|
||||
parameters[3].Descriptor.RegisterSpace = 0;
|
||||
|
||||
D3D12_STATIC_SAMPLER_DESC samplers[KINC_INTERNAL_G5_TEXTURE_COUNT * 2];
|
||||
for (int i = 0; i < KINC_INTERNAL_G5_TEXTURE_COUNT; ++i) {
|
||||
samplers[i].ShaderRegister = i;
|
||||
samplers[i].Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
samplers[i].AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].MipLODBias = 0;
|
||||
samplers[i].MaxAnisotropy = 16;
|
||||
samplers[i].ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
samplers[i].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
|
||||
samplers[i].MinLOD = 0.0f;
|
||||
samplers[i].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
samplers[i].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
samplers[i].RegisterSpace = 0;
|
||||
}
|
||||
for (int i = KINC_INTERNAL_G5_TEXTURE_COUNT; i < KINC_INTERNAL_G5_TEXTURE_COUNT * 2; ++i) {
|
||||
samplers[i].ShaderRegister = i;
|
||||
samplers[i].Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
samplers[i].AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].MipLODBias = 0;
|
||||
samplers[i].MaxAnisotropy = 16;
|
||||
samplers[i].ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
samplers[i].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
|
||||
samplers[i].MinLOD = 0.0f;
|
||||
samplers[i].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
samplers[i].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
samplers[i].RegisterSpace = 0;
|
||||
}
|
||||
|
||||
D3D12_ROOT_SIGNATURE_DESC descRootSignature;
|
||||
descRootSignature.NumParameters = 4;
|
||||
descRootSignature.pParameters = parameters;
|
||||
descRootSignature.NumStaticSamplers = 0;
|
||||
descRootSignature.pStaticSamplers = NULL;
|
||||
descRootSignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
||||
|
||||
kinc_microsoft_affirm(D3D12SerializeRootSignature(&descRootSignature, D3D_ROOT_SIGNATURE_VERSION_1, &rootBlob, &errorBlob));
|
||||
device->CreateRootSignature(0, rootBlob->GetBufferPointer(), rootBlob->GetBufferSize(), IID_GRAPHICS_PPV_ARGS(&globalRootSignature));
|
||||
}
|
||||
|
||||
static void createComputeRootSignature() {
|
||||
ID3DBlob *rootBlob;
|
||||
ID3DBlob *errorBlob;
|
||||
|
||||
D3D12_ROOT_PARAMETER parameters[4] = {};
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE range;
|
||||
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
range.NumDescriptors = (UINT)KINC_INTERNAL_G5_TEXTURE_COUNT;
|
||||
range.BaseShaderRegister = 0;
|
||||
range.RegisterSpace = 0;
|
||||
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
parameters[0].DescriptorTable.NumDescriptorRanges = 1;
|
||||
parameters[0].DescriptorTable.pDescriptorRanges = ⦥
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE uav_range;
|
||||
uav_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
uav_range.NumDescriptors = (UINT)KINC_INTERNAL_G5_TEXTURE_COUNT;
|
||||
uav_range.BaseShaderRegister = 0;
|
||||
uav_range.RegisterSpace = 0;
|
||||
uav_range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
parameters[1].DescriptorTable.NumDescriptorRanges = 1;
|
||||
parameters[1].DescriptorTable.pDescriptorRanges = &uav_range;
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE range2;
|
||||
range2.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
|
||||
range2.NumDescriptors = (UINT)KINC_INTERNAL_G5_TEXTURE_COUNT;
|
||||
range2.BaseShaderRegister = 0;
|
||||
range2.RegisterSpace = 0;
|
||||
range2.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
parameters[2].DescriptorTable.NumDescriptorRanges = 1;
|
||||
parameters[2].DescriptorTable.pDescriptorRanges = &range2;
|
||||
|
||||
parameters[3].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
parameters[3].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
parameters[3].Descriptor.ShaderRegister = 0;
|
||||
parameters[3].Descriptor.RegisterSpace = 0;
|
||||
|
||||
D3D12_STATIC_SAMPLER_DESC samplers[KINC_INTERNAL_G5_TEXTURE_COUNT * 2];
|
||||
for (int i = 0; i < KINC_INTERNAL_G5_TEXTURE_COUNT; ++i) {
|
||||
samplers[i].ShaderRegister = i;
|
||||
samplers[i].Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
samplers[i].AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].MipLODBias = 0;
|
||||
samplers[i].MaxAnisotropy = 16;
|
||||
samplers[i].ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
samplers[i].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
|
||||
samplers[i].MinLOD = 0.0f;
|
||||
samplers[i].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
samplers[i].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
samplers[i].RegisterSpace = 0;
|
||||
}
|
||||
for (int i = KINC_INTERNAL_G5_TEXTURE_COUNT; i < KINC_INTERNAL_G5_TEXTURE_COUNT * 2; ++i) {
|
||||
samplers[i].ShaderRegister = i;
|
||||
samplers[i].Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
samplers[i].AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
samplers[i].MipLODBias = 0;
|
||||
samplers[i].MaxAnisotropy = 16;
|
||||
samplers[i].ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
samplers[i].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
|
||||
samplers[i].MinLOD = 0.0f;
|
||||
samplers[i].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
samplers[i].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
samplers[i].RegisterSpace = 0;
|
||||
}
|
||||
|
||||
D3D12_ROOT_SIGNATURE_DESC descRootSignature;
|
||||
descRootSignature.NumParameters = 4;
|
||||
descRootSignature.pParameters = parameters;
|
||||
descRootSignature.NumStaticSamplers = 0;
|
||||
descRootSignature.pStaticSamplers = NULL;
|
||||
descRootSignature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
||||
|
||||
kinc_microsoft_affirm(D3D12SerializeRootSignature(&descRootSignature, D3D_ROOT_SIGNATURE_VERSION_1, &rootBlob, &errorBlob));
|
||||
device->CreateRootSignature(0, rootBlob->GetBufferPointer(), rootBlob->GetBufferSize(), IID_GRAPHICS_PPV_ARGS(&globalComputeRootSignature));
|
||||
|
||||
// createSamplersAndHeaps();
|
||||
}
|
||||
|
||||
static void initialize(struct dx_window *window) {
|
||||
createDeviceAndSwapChain(window);
|
||||
createRootSignature();
|
||||
createComputeRootSignature();
|
||||
|
||||
device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(&uploadFence));
|
||||
|
||||
device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_GRAPHICS_PPV_ARGS(&initCommandAllocator));
|
||||
device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, initCommandAllocator, NULL, IID_GRAPHICS_PPV_ARGS(&initCommandList));
|
||||
|
||||
initCommandList->Close();
|
||||
|
||||
ID3D12CommandList *commandLists[] = {(ID3D12CommandList *)initCommandList};
|
||||
commandQueue->ExecuteCommandLists(1, commandLists);
|
||||
commandQueue->Signal(uploadFence, 1);
|
||||
|
||||
HANDLE waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
waitForFence(uploadFence, 1, waitEvent);
|
||||
|
||||
initCommandAllocator->Reset();
|
||||
initCommandList->Release(); // check me
|
||||
initCommandAllocator->Release(); // check me
|
||||
|
||||
CloseHandle(waitEvent);
|
||||
}
|
||||
|
||||
static void shutdown() {
|
||||
for (int i = 0; i < QUEUE_SLOT_COUNT; ++i) {
|
||||
// waitForFence(window->frame_fences[i], window->current_fence_value[i], window->frame_fence_events[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < QUEUE_SLOT_COUNT; ++i) {
|
||||
// CloseHandle(window->frame_fence_events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef KINC_WINDOWS
|
||||
static void initWindow(struct dx_window *window, int windowIndex) {
|
||||
HWND hwnd = kinc_windows_window_handle(windowIndex);
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swapChainDesc;
|
||||
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
|
||||
|
||||
swapChainDesc.BufferCount = QUEUE_SLOT_COUNT;
|
||||
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.BufferDesc.Width = kinc_window_width(windowIndex);
|
||||
swapChainDesc.BufferDesc.Height = kinc_window_height(windowIndex);
|
||||
swapChainDesc.OutputWindow = hwnd;
|
||||
swapChainDesc.SampleDesc.Count = 1;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
swapChainDesc.Windowed = true;
|
||||
|
||||
IDXGIFactory4 *dxgiFactory = NULL;
|
||||
kinc_microsoft_affirm(CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)));
|
||||
|
||||
kinc_microsoft_affirm(dxgiFactory->CreateSwapChain((IUnknown *)commandQueue, &swapChainDesc, &window->swapChain));
|
||||
|
||||
setupSwapChain(window);
|
||||
}
|
||||
#endif
|
||||
|
||||
void kinc_g5_internal_destroy_window(int window) {}
|
||||
|
||||
void kinc_g5_internal_destroy() {
|
||||
#ifdef KINC_WINDOWS
|
||||
if (device) {
|
||||
device->Release();
|
||||
device = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_internal_init() {
|
||||
#ifdef KINC_WINDOWS
|
||||
#ifdef _DEBUG
|
||||
ID3D12Debug *debugController = NULL;
|
||||
if (D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)) == S_OK) {
|
||||
debugController->EnableDebugLayer();
|
||||
}
|
||||
#endif
|
||||
kinc_microsoft_affirm(D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device)));
|
||||
|
||||
createRootSignature();
|
||||
createComputeRootSignature();
|
||||
|
||||
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
|
||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
|
||||
kinc_microsoft_affirm(device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)));
|
||||
|
||||
device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&uploadFence));
|
||||
|
||||
device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&initCommandAllocator));
|
||||
device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, initCommandAllocator, NULL, IID_PPV_ARGS(&initCommandList));
|
||||
|
||||
initCommandList->Close();
|
||||
|
||||
ID3D12CommandList *commandLists[] = {(ID3D12CommandList *)initCommandList};
|
||||
commandQueue->ExecuteCommandLists(1, commandLists);
|
||||
commandQueue->Signal(uploadFence, 1);
|
||||
|
||||
HANDLE waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
waitForFence(uploadFence, 1, waitEvent);
|
||||
|
||||
initCommandAllocator->Reset();
|
||||
initCommandList->Release(); // check me
|
||||
initCommandAllocator->Release(); // check me
|
||||
|
||||
CloseHandle(waitEvent);
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_internal_init_window(int windowIndex, int depthBufferBits, int stencilBufferBits, bool verticalSync) {
|
||||
struct dx_window *window = &dx_ctx.windows[windowIndex];
|
||||
window->window_index = windowIndex;
|
||||
window->vsync = verticalSync;
|
||||
window->width = window->new_width = kinc_window_width(windowIndex);
|
||||
window->height = window->new_height = kinc_window_height(windowIndex);
|
||||
#ifdef KINC_WINDOWS
|
||||
initWindow(window, windowIndex);
|
||||
#else
|
||||
HWND hwnd = NULL;
|
||||
window->vsync = verticalSync;
|
||||
window->new_width = window->width = kinc_width();
|
||||
window->new_height = window->height = kinc_height();
|
||||
initialize(window);
|
||||
#endif
|
||||
}
|
||||
|
||||
int kinc_g5_max_bound_textures(void) {
|
||||
return D3D12_COMMONSHADER_SAMPLER_SLOT_COUNT;
|
||||
}
|
||||
|
||||
#ifndef KINC_WINDOWS
|
||||
extern "C" void kinc_internal_wait_for_frame();
|
||||
#endif
|
||||
|
||||
static bool began = false;
|
||||
|
||||
void kinc_g5_begin(kinc_g5_render_target_t *renderTarget, int windowId) {
|
||||
if (began)
|
||||
return;
|
||||
began = true;
|
||||
|
||||
#ifndef KINC_WINDOWS
|
||||
kinc_internal_wait_for_frame();
|
||||
#endif
|
||||
|
||||
struct dx_window *window = &dx_ctx.windows[windowId];
|
||||
dx_ctx.current_window = windowId;
|
||||
|
||||
window->current_backbuffer = (window->current_backbuffer + 1) % QUEUE_SLOT_COUNT;
|
||||
|
||||
if (window->new_width != window->width || window->new_height != window->height) {
|
||||
#ifndef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
kinc_microsoft_affirm(window->swapChain->ResizeBuffers(QUEUE_SLOT_COUNT, window->new_width, window->new_height, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
|
||||
#endif
|
||||
setupSwapChain(window);
|
||||
window->width = window->new_width;
|
||||
window->height = window->new_height;
|
||||
window->current_backbuffer = 0;
|
||||
}
|
||||
|
||||
const UINT64 fenceValue = window->current_fence_value;
|
||||
commandQueue->Signal(window->frame_fences[window->current_backbuffer], fenceValue);
|
||||
window->fence_values[window->current_backbuffer] = fenceValue;
|
||||
++window->current_fence_value;
|
||||
|
||||
#ifdef KINC_WINDOWSAPP
|
||||
context->OMSetRenderTargets(1, &renderTargetView, depthStencilView);
|
||||
#endif
|
||||
|
||||
waitForFence(window->frame_fences[window->current_backbuffer], window->fence_values[window->current_backbuffer],
|
||||
window->frame_fence_events[window->current_backbuffer]);
|
||||
|
||||
// static const float clearColor[] = {0.042f, 0.042f, 0.042f, 1};
|
||||
|
||||
// commandList->ClearRenderTargetView(GetCPUDescriptorHandle(renderTargetDescriptorHeap), clearColor, 0, nullptr);
|
||||
|
||||
// commandList->ClearDepthStencilView(GetCPUDescriptorHandle(depthStencilDescriptorHeap), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
|
||||
|
||||
static int frameNumber = 0;
|
||||
frameNumber++;
|
||||
}
|
||||
|
||||
void kinc_g5_end(int window) {
|
||||
began = false;
|
||||
}
|
||||
|
||||
bool kinc_g5_vsynced() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_window_vsynced(int window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void kinc_g4_on_g5_internal_resize(int, int, int);
|
||||
|
||||
extern "C" void kinc_internal_resize(int windowId, int width, int height) {
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
struct dx_window *window = &dx_ctx.windows[windowId];
|
||||
window->new_width = width;
|
||||
window->new_height = height;
|
||||
kinc_g4_on_g5_internal_resize(windowId, width, height);
|
||||
}
|
||||
|
||||
extern "C" void kinc_internal_change_framebuffer(int window, kinc_framebuffer_options_t *frame) {}
|
||||
|
||||
#ifndef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
bool kinc_g5_swap_buffers() {
|
||||
for (int i = 0; i < MAXIMUM_WINDOWS; i++) {
|
||||
struct dx_window *window = &dx_ctx.windows[i];
|
||||
if (window->swapChain) {
|
||||
kinc_microsoft_affirm(window->swapChain->Present(window->vsync, 0));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void kinc_g5_flush() {}
|
||||
|
||||
bool kinc_g5_render_targets_inverted_y() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_raytracing() {
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS5 options;
|
||||
if (device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options, sizeof(options)) == S_OK) {
|
||||
return options.RaytracingTier >= D3D12_RAYTRACING_TIER_1_0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_instanced_rendering() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_compute_shaders() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_blend_constants() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_non_pow2_textures() {
|
||||
return true;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#include "ShaderHash.h"
|
||||
|
||||
// djb2
|
||||
uint32_t kinc_internal_hash_name(unsigned char *str) {
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
while ((c = *str++)) {
|
||||
hash = hash * 33 ^ c;
|
||||
}
|
||||
return hash;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t hash;
|
||||
uint32_t index;
|
||||
} kinc_internal_hash_index_t;
|
||||
|
||||
uint32_t kinc_internal_hash_name(unsigned char *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,625 @@
|
||||
#include <kinc/graphics5/commandlist.h>
|
||||
#include <kinc/graphics5/compute.h>
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
void createHeaps(kinc_g5_command_list_t *list);
|
||||
|
||||
static int formatSize(DXGI_FORMAT format) {
|
||||
switch (format) {
|
||||
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
||||
return 16;
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
return 8;
|
||||
case DXGI_FORMAT_R16_FLOAT:
|
||||
return 2;
|
||||
case DXGI_FORMAT_R8_UNORM:
|
||||
return 1;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_init(struct kinc_g5_command_list *list) {
|
||||
#ifndef NDEBUG
|
||||
list->impl.open = false;
|
||||
#endif
|
||||
|
||||
device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_GRAPHICS_PPV_ARGS(&list->impl._commandAllocator));
|
||||
device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, list->impl._commandAllocator, NULL, IID_GRAPHICS_PPV_ARGS(&list->impl._commandList));
|
||||
|
||||
list->impl.fence_value = 0;
|
||||
list->impl.fence_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(&list->impl.fence));
|
||||
|
||||
list->impl._indexCount = 0;
|
||||
|
||||
list->impl.current_full_scissor.left = -1;
|
||||
|
||||
for (int i = 0; i < KINC_INTERNAL_G5_TEXTURE_COUNT; ++i) {
|
||||
list->impl.currentRenderTargets[i] = NULL;
|
||||
list->impl.currentTextures[i] = NULL;
|
||||
list->impl.current_samplers[i] = NULL;
|
||||
}
|
||||
list->impl.heapIndex = 0;
|
||||
createHeaps(list);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_destroy(struct kinc_g5_command_list *list) {}
|
||||
|
||||
void kinc_g5_internal_reset_textures(struct kinc_g5_command_list *list);
|
||||
|
||||
void kinc_g5_command_list_begin(struct kinc_g5_command_list *list) {
|
||||
assert(!list->impl.open);
|
||||
|
||||
compute_pipeline_set = false;
|
||||
|
||||
if (list->impl.fence_value > 0) {
|
||||
waitForFence(list->impl.fence, list->impl.fence_value, list->impl.fence_event);
|
||||
list->impl._commandAllocator->Reset();
|
||||
list->impl._commandList->Reset(list->impl._commandAllocator, NULL);
|
||||
}
|
||||
|
||||
kinc_g5_internal_reset_textures(list);
|
||||
|
||||
#ifndef NDEBUG
|
||||
list->impl.open = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_end(struct kinc_g5_command_list *list) {
|
||||
assert(list->impl.open);
|
||||
|
||||
list->impl._commandList->Close();
|
||||
|
||||
#ifndef NDEBUG
|
||||
list->impl.open = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_clear(struct kinc_g5_command_list *list, kinc_g5_render_target_t *renderTarget, unsigned flags, unsigned color, float depth,
|
||||
int stencil) {
|
||||
assert(list->impl.open);
|
||||
|
||||
if (flags & KINC_G5_CLEAR_COLOR) {
|
||||
float clearColor[] = {((color & 0x00ff0000) >> 16) / 255.0f, ((color & 0x0000ff00) >> 8) / 255.0f, (color & 0x000000ff) / 255.0f,
|
||||
((color & 0xff000000) >> 24) / 255.0f};
|
||||
list->impl._commandList->ClearRenderTargetView(renderTarget->impl.renderTargetDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), clearColor, 0,
|
||||
NULL);
|
||||
}
|
||||
if ((flags & KINC_G5_CLEAR_DEPTH) || (flags & KINC_G5_CLEAR_STENCIL)) {
|
||||
D3D12_CLEAR_FLAGS d3dflags = (flags & KINC_G5_CLEAR_DEPTH) && (flags & KINC_G5_CLEAR_STENCIL) ? D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL
|
||||
: (flags & KINC_G5_CLEAR_DEPTH) ? D3D12_CLEAR_FLAG_DEPTH
|
||||
: D3D12_CLEAR_FLAG_STENCIL;
|
||||
|
||||
if (renderTarget->impl.depthStencilDescriptorHeap != NULL) {
|
||||
list->impl._commandList->ClearDepthStencilView(renderTarget->impl.depthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), d3dflags, depth,
|
||||
stencil, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_render_target_to_framebuffer_barrier(struct kinc_g5_command_list *list, kinc_g5_render_target_t *renderTarget) {
|
||||
assert(list->impl.open);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Transition.pResource = renderTarget->impl.renderTarget;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
list->impl._commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_framebuffer_to_render_target_barrier(struct kinc_g5_command_list *list, kinc_g5_render_target_t *renderTarget) {
|
||||
assert(list->impl.open);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Transition.pResource = renderTarget->impl.renderTarget;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
list->impl._commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_texture_to_render_target_barrier(struct kinc_g5_command_list *list, kinc_g5_render_target_t *renderTarget) {
|
||||
assert(list->impl.open);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Transition.pResource = renderTarget->impl.renderTarget;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
list->impl._commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_render_target_to_texture_barrier(struct kinc_g5_command_list *list, kinc_g5_render_target_t *renderTarget) {
|
||||
assert(list->impl.open);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Transition.pResource = renderTarget->impl.renderTarget;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
list->impl._commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_vertex_constant_buffer(struct kinc_g5_command_list *list, kinc_g5_constant_buffer_t *buffer, int offset, size_t size) {
|
||||
assert(list->impl.open);
|
||||
|
||||
#ifdef KINC_DXC
|
||||
if (list->impl._currentPipeline->impl.vertexConstantsSize > 0) {
|
||||
if (list->impl._currentPipeline->impl.textures > 0) {
|
||||
list->impl._commandList->SetGraphicsRootConstantBufferView(2, buffer->impl.constant_buffer->GetGPUVirtualAddress() + offset);
|
||||
}
|
||||
else {
|
||||
list->impl._commandList->SetGraphicsRootConstantBufferView(0, buffer->impl.constant_buffer->GetGPUVirtualAddress() + offset);
|
||||
}
|
||||
}
|
||||
#else
|
||||
list->impl._commandList->SetGraphicsRootConstantBufferView(2, buffer->impl.constant_buffer->GetGPUVirtualAddress() + offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_fragment_constant_buffer(struct kinc_g5_command_list *list, kinc_g5_constant_buffer_t *buffer, int offset, size_t size) {
|
||||
assert(list->impl.open);
|
||||
|
||||
#ifdef KINC_DXC
|
||||
if (list->impl._currentPipeline->impl.fragmentConstantsSize > 0) {
|
||||
list->impl._commandList->SetGraphicsRootConstantBufferView(3, buffer->impl.constant_buffer->GetGPUVirtualAddress() + offset);
|
||||
}
|
||||
#else
|
||||
list->impl._commandList->SetGraphicsRootConstantBufferView(3, buffer->impl.constant_buffer->GetGPUVirtualAddress() + offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_compute_constant_buffer(struct kinc_g5_command_list *list, kinc_g5_constant_buffer_t *buffer, int offset, size_t size) {
|
||||
assert(list->impl.open);
|
||||
|
||||
#ifdef KINC_DXC
|
||||
if (list->impl._currentPipeline->impl.fragmentConstantsSize > 0) {
|
||||
list->impl._commandList->SetGraphicsRootConstantBufferView(3, buffer->impl.constant_buffer->GetGPUVirtualAddress() + offset);
|
||||
}
|
||||
#else
|
||||
list->impl._commandList->SetComputeRootConstantBufferView(3, buffer->impl.constant_buffer->GetGPUVirtualAddress() + offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices(struct kinc_g5_command_list *list) {
|
||||
kinc_g5_command_list_draw_indexed_vertices_from_to(list, 0, list->impl._indexCount);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_from_to(struct kinc_g5_command_list *list, int start, int count) {
|
||||
assert(list->impl.open);
|
||||
|
||||
list->impl._commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
/*u8* data;
|
||||
D3D12_RANGE range;
|
||||
range.Begin = currentConstantBuffer * sizeof(vertexConstants);
|
||||
range.End = range.Begin + sizeof(vertexConstants);
|
||||
vertexConstantBuffer->Map(0, &range, (void**)&data);
|
||||
memcpy(data + currentConstantBuffer * sizeof(vertexConstants), vertexConstants, sizeof(vertexConstants));
|
||||
vertexConstantBuffer->Unmap(0, &range);
|
||||
|
||||
range.Begin = currentConstantBuffer * sizeof(fragmentConstants);
|
||||
range.End = range.Begin + sizeof(fragmentConstants);
|
||||
fragmentConstantBuffer->Map(0, &range, (void**)&data);
|
||||
memcpy(data + currentConstantBuffer * sizeof(fragmentConstants), fragmentConstants, sizeof(fragmentConstants));
|
||||
fragmentConstantBuffer->Unmap(0, &range);
|
||||
|
||||
_commandList->SetGraphicsRootConstantBufferView(1, vertexConstantBuffer->GetGPUVirtualAddress() + currentConstantBuffer * sizeof(vertexConstants));
|
||||
_commandList->SetGraphicsRootConstantBufferView(2, fragmentConstantBuffer->GetGPUVirtualAddress() + currentConstantBuffer * sizeof(fragmentConstants));
|
||||
|
||||
++currentConstantBuffer;
|
||||
if (currentConstantBuffer >= constantBufferMultiply) {
|
||||
currentConstantBuffer = 0;
|
||||
}*/
|
||||
|
||||
list->impl._commandList->DrawIndexedInstanced(count, 1, start, 0, 0);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_from_to_from(struct kinc_g5_command_list *list, int start, int count, int vertex_offset) {
|
||||
assert(list->impl.open);
|
||||
|
||||
list->impl._commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
list->impl._commandList->DrawIndexedInstanced(count, 1, start, vertex_offset, 0);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_instanced(kinc_g5_command_list_t *list, int instanceCount) {
|
||||
kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(list, instanceCount, 0, list->impl._indexCount);
|
||||
}
|
||||
void kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(kinc_g5_command_list_t *list, int instanceCount, int start, int count) {
|
||||
assert(list->impl.open);
|
||||
|
||||
list->impl._commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
list->impl._commandList->DrawIndexedInstanced(count, instanceCount, start, 0, 0);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_execute(kinc_g5_command_list_t *list) {
|
||||
assert(!list->impl.open);
|
||||
|
||||
ID3D12CommandList *commandLists[] = {(ID3D12CommandList *)list->impl._commandList};
|
||||
commandQueue->ExecuteCommandLists(1, commandLists);
|
||||
|
||||
commandQueue->Signal(list->impl.fence, ++list->impl.fence_value);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_wait_for_execution_to_finish(kinc_g5_command_list_t *list) {
|
||||
waitForFence(list->impl.fence, list->impl.fence_value, list->impl.fence_event);
|
||||
}
|
||||
|
||||
bool kinc_g5_non_pow2_textures_supported(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_viewport(struct kinc_g5_command_list *list, int x, int y, int width, int height) {
|
||||
assert(list->impl.open);
|
||||
|
||||
D3D12_VIEWPORT viewport;
|
||||
viewport.TopLeftX = (float)x;
|
||||
viewport.TopLeftY = (float)y;
|
||||
viewport.Width = (float)width;
|
||||
viewport.Height = (float)height;
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
list->impl._commandList->RSSetViewports(1, &viewport);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_scissor(struct kinc_g5_command_list *list, int x, int y, int width, int height) {
|
||||
assert(list->impl.open);
|
||||
|
||||
D3D12_RECT scissor;
|
||||
scissor.left = x;
|
||||
scissor.top = y;
|
||||
scissor.right = x + width;
|
||||
scissor.bottom = y + height;
|
||||
list->impl._commandList->RSSetScissorRects(1, &scissor);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_disable_scissor(struct kinc_g5_command_list *list) {
|
||||
assert(list->impl.open);
|
||||
|
||||
if (list->impl.current_full_scissor.left >= 0) {
|
||||
list->impl._commandList->RSSetScissorRects(1, (D3D12_RECT *)&list->impl.current_full_scissor);
|
||||
}
|
||||
else {
|
||||
D3D12_RECT scissor;
|
||||
scissor.left = 0;
|
||||
scissor.top = 0;
|
||||
scissor.right = kinc_window_width(0);
|
||||
scissor.bottom = kinc_window_height(0);
|
||||
list->impl._commandList->RSSetScissorRects(1, &scissor);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_pipeline(struct kinc_g5_command_list *list, kinc_g5_pipeline_t *pipeline) {
|
||||
assert(list->impl.open);
|
||||
|
||||
list->impl._currentPipeline = pipeline;
|
||||
list->impl._commandList->SetPipelineState(pipeline->impl.pso);
|
||||
compute_pipeline_set = false;
|
||||
|
||||
for (int i = 0; i < KINC_INTERNAL_G5_TEXTURE_COUNT; ++i) {
|
||||
list->impl.currentRenderTargets[i] = NULL;
|
||||
list->impl.currentTextures[i] = NULL;
|
||||
}
|
||||
kinc_g5_internal_setConstants(list, list->impl._currentPipeline);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_blend_constant(kinc_g5_command_list_t *list, float r, float g, float b, float a) {
|
||||
const FLOAT BlendFactor[4] = {r, g, b, a};
|
||||
list->impl._commandList->OMSetBlendFactor(BlendFactor);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_vertex_buffers(struct kinc_g5_command_list *list, kinc_g5_vertex_buffer_t **buffers, int *offsets, int count) {
|
||||
assert(list->impl.open);
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW *views = (D3D12_VERTEX_BUFFER_VIEW *)alloca(sizeof(D3D12_VERTEX_BUFFER_VIEW) * count);
|
||||
ZeroMemory(views, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
views[i].BufferLocation = buffers[i]->impl.uploadBuffer->GetGPUVirtualAddress() + offsets[i] * kinc_g5_vertex_buffer_stride(buffers[i]);
|
||||
views[i].SizeInBytes = (kinc_g5_vertex_buffer_count(buffers[i]) - offsets[i]) * kinc_g5_vertex_buffer_stride(buffers[i]);
|
||||
views[i].StrideInBytes = kinc_g5_vertex_buffer_stride(buffers[i]); // * kinc_g5_vertex_buffer_count(buffers[i]);
|
||||
}
|
||||
list->impl._commandList->IASetVertexBuffers(0, count, views);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_index_buffer(struct kinc_g5_command_list *list, kinc_g5_index_buffer_t *buffer) {
|
||||
assert(list->impl.open);
|
||||
|
||||
list->impl._indexCount = kinc_g5_index_buffer_count(buffer);
|
||||
list->impl._commandList->IASetIndexBuffer((D3D12_INDEX_BUFFER_VIEW *)&buffer->impl.index_buffer_view);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_render_targets(struct kinc_g5_command_list *list, kinc_g5_render_target_t **targets, int count) {
|
||||
assert(list->impl.open);
|
||||
|
||||
kinc_g5_render_target_t *render_target = targets[0];
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE target_descriptors[16];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
target_descriptors[i] = targets[i]->impl.renderTargetDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
}
|
||||
|
||||
assert(render_target != NULL);
|
||||
|
||||
if (render_target->impl.depthStencilDescriptorHeap != NULL) {
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE heapStart = render_target->impl.depthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
list->impl._commandList->OMSetRenderTargets(count, &target_descriptors[0], false, &heapStart);
|
||||
}
|
||||
else {
|
||||
list->impl._commandList->OMSetRenderTargets(count, &target_descriptors[0], false, NULL);
|
||||
}
|
||||
|
||||
list->impl._commandList->RSSetViewports(1, (D3D12_VIEWPORT *)&render_target->impl.viewport);
|
||||
list->impl._commandList->RSSetScissorRects(1, (D3D12_RECT *)&render_target->impl.scissor);
|
||||
|
||||
list->impl.current_full_scissor = render_target->impl.scissor;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_upload_vertex_buffer(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer *buffer) {}
|
||||
|
||||
void kinc_g5_command_list_upload_index_buffer(kinc_g5_command_list_t *list, kinc_g5_index_buffer_t *buffer) {
|
||||
assert(list->impl.open);
|
||||
kinc_g5_internal_index_buffer_upload(buffer, list->impl._commandList);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_upload_texture(kinc_g5_command_list_t *list, kinc_g5_texture_t *texture) {
|
||||
assert(list->impl.open);
|
||||
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER transition = {};
|
||||
transition.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
transition.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
transition.Transition.pResource = texture->impl.image;
|
||||
transition.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
transition.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
transition.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
list->impl._commandList->ResourceBarrier(1, &transition);
|
||||
}
|
||||
|
||||
D3D12_RESOURCE_DESC Desc = texture->impl.image->GetDesc();
|
||||
ID3D12Device *device = NULL;
|
||||
texture->impl.image->GetDevice(IID_GRAPHICS_PPV_ARGS(&device));
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
|
||||
device->GetCopyableFootprints(&Desc, 0, 1, 0, &footprint, NULL, NULL, NULL);
|
||||
device->Release();
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION source = {0};
|
||||
source.pResource = texture->impl.uploadImage;
|
||||
source.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
source.PlacedFootprint = footprint;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION destination = {0};
|
||||
destination.pResource = texture->impl.image;
|
||||
destination.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
destination.SubresourceIndex = 0;
|
||||
|
||||
list->impl._commandList->CopyTextureRegion(&destination, 0, 0, 0, &source, NULL);
|
||||
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER transition = {};
|
||||
transition.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
transition.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
transition.Transition.pResource = texture->impl.image;
|
||||
transition.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
transition.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
|
||||
transition.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
list->impl._commandList->ResourceBarrier(1, &transition);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
|
||||
static int d3d12_textureAlignment() {
|
||||
return D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
|
||||
}
|
||||
#else
|
||||
extern "C" int d3d12_textureAlignment();
|
||||
#endif
|
||||
|
||||
void kinc_g5_command_list_get_render_target_pixels(kinc_g5_command_list_t *list, kinc_g5_render_target_t *render_target, uint8_t *data) {
|
||||
assert(list->impl.open);
|
||||
|
||||
DXGI_FORMAT dxgiFormat = render_target->impl.renderTarget->GetDesc().Format;
|
||||
int formatByteSize = formatSize(dxgiFormat);
|
||||
int rowPitch = render_target->texWidth * formatByteSize;
|
||||
int align = rowPitch % d3d12_textureAlignment();
|
||||
if (align != 0)
|
||||
rowPitch = rowPitch + (d3d12_textureAlignment() - align);
|
||||
|
||||
// Create readback buffer
|
||||
if (render_target->impl.renderTargetReadback == NULL) {
|
||||
D3D12_HEAP_PROPERTIES heapProperties;
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProperties.CreationNodeMask = 1;
|
||||
heapProperties.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC resourceDesc;
|
||||
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resourceDesc.Alignment = 0;
|
||||
resourceDesc.Width = rowPitch * render_target->texHeight;
|
||||
resourceDesc.Height = 1;
|
||||
resourceDesc.DepthOrArraySize = 1;
|
||||
resourceDesc.MipLevels = 1;
|
||||
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
resourceDesc.SampleDesc.Count = 1;
|
||||
resourceDesc.SampleDesc.Quality = 0;
|
||||
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&render_target->impl.renderTargetReadback));
|
||||
}
|
||||
|
||||
// Copy render target to readback buffer
|
||||
D3D12_RESOURCE_STATES sourceState = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Transition.pResource = render_target->impl.renderTarget;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.StateBefore = sourceState;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
list->impl._commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION source;
|
||||
source.pResource = render_target->impl.renderTarget;
|
||||
source.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
source.SubresourceIndex = 0;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dest;
|
||||
dest.pResource = render_target->impl.renderTargetReadback;
|
||||
dest.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
dest.PlacedFootprint.Offset = 0;
|
||||
dest.PlacedFootprint.Footprint.Format = dxgiFormat;
|
||||
dest.PlacedFootprint.Footprint.Width = render_target->texWidth;
|
||||
dest.PlacedFootprint.Footprint.Height = render_target->texHeight;
|
||||
dest.PlacedFootprint.Footprint.Depth = 1;
|
||||
dest.PlacedFootprint.Footprint.RowPitch = rowPitch;
|
||||
|
||||
list->impl._commandList->CopyTextureRegion(&dest, 0, 0, 0, &source, NULL);
|
||||
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Transition.pResource = render_target->impl.renderTarget;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
barrier.Transition.StateAfter = sourceState;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
list->impl._commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
kinc_g5_command_list_end(list);
|
||||
kinc_g5_command_list_execute(list);
|
||||
kinc_g5_command_list_wait_for_execution_to_finish(list);
|
||||
kinc_g5_command_list_begin(list);
|
||||
|
||||
// Read buffer
|
||||
void *p;
|
||||
render_target->impl.renderTargetReadback->Map(0, NULL, &p);
|
||||
memcpy(data, p, render_target->texWidth * render_target->texHeight * formatByteSize);
|
||||
render_target->impl.renderTargetReadback->Unmap(0, NULL);
|
||||
}
|
||||
|
||||
void kinc_g5_internal_set_compute_constants(kinc_g5_command_list_t *commandList);
|
||||
|
||||
void kinc_g5_command_list_set_compute_shader(kinc_g5_command_list_t *list, kinc_g5_compute_shader *shader) {
|
||||
list->impl._commandList->SetPipelineState(shader->impl.pso);
|
||||
compute_pipeline_set = true;
|
||||
|
||||
for (int i = 0; i < KINC_INTERNAL_G5_TEXTURE_COUNT; ++i) {
|
||||
list->impl.currentRenderTargets[i] = NULL;
|
||||
list->impl.currentTextures[i] = NULL;
|
||||
}
|
||||
kinc_g5_internal_set_compute_constants(list);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_compute(kinc_g5_command_list_t *list, int x, int y, int z) {
|
||||
assert(list->impl.open);
|
||||
list->impl._commandList->Dispatch(x, y, z);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_render_target_face(kinc_g5_command_list_t *list, kinc_g5_render_target_t *texture, int face) {}
|
||||
|
||||
void kinc_g5_command_list_set_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture) {
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
kinc_g5_internal_texture_set(list, texture, unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]);
|
||||
}
|
||||
else if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
kinc_g5_internal_texture_set(list, texture, unit.stages[KINC_G5_SHADER_TYPE_VERTEX]);
|
||||
}
|
||||
else if (unit.stages[KINC_G5_SHADER_TYPE_COMPUTE] >= 0) {
|
||||
kinc_g5_internal_texture_set(list, texture, unit.stages[KINC_G5_SHADER_TYPE_COMPUTE]);
|
||||
}
|
||||
kinc_g5_internal_set_textures(list);
|
||||
}
|
||||
|
||||
void kinc_g5_internal_sampler_set(kinc_g5_command_list_t *list, kinc_g5_sampler_t *sampler, int unit);
|
||||
|
||||
void kinc_g5_command_list_set_sampler(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_sampler_t *sampler) {
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
kinc_g5_internal_sampler_set(list, sampler, unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]);
|
||||
}
|
||||
else if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
kinc_g5_internal_sampler_set(list, sampler, unit.stages[KINC_G5_SHADER_TYPE_VERTEX]);
|
||||
}
|
||||
kinc_g5_internal_set_textures(list);
|
||||
}
|
||||
|
||||
bool kinc_g5_command_list_init_occlusion_query(kinc_g5_command_list_t *list, unsigned *occlusionQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_image_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture) {
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
kinc_g5_internal_texture_set(list, texture, unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]);
|
||||
}
|
||||
else if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
kinc_g5_internal_texture_set(list, texture, unit.stages[KINC_G5_SHADER_TYPE_VERTEX]);
|
||||
}
|
||||
else if (unit.stages[KINC_G5_SHADER_TYPE_COMPUTE] >= 0) {
|
||||
kinc_g5_internal_texture_set(list, texture, unit.stages[KINC_G5_SHADER_TYPE_COMPUTE]);
|
||||
}
|
||||
kinc_g5_internal_set_textures(list);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_delete_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery) {}
|
||||
|
||||
void kinc_g5_command_list_render_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery, int triangles) {}
|
||||
|
||||
bool kinc_g5_command_list_are_query_results_available(kinc_g5_command_list_t *list, unsigned occlusionQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_get_query_result(kinc_g5_command_list_t *list, unsigned occlusionQuery, unsigned *pixelCount) {}
|
||||
|
||||
void kinc_g5_command_list_set_texture_from_render_target(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_render_target_t *target) {
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
target->impl.stage = unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT];
|
||||
list->impl.currentRenderTargets[target->impl.stage] = target;
|
||||
}
|
||||
else if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
target->impl.stage = unit.stages[KINC_G5_SHADER_TYPE_VERTEX];
|
||||
list->impl.currentRenderTargets[target->impl.stage] = target;
|
||||
}
|
||||
list->impl.currentTextures[target->impl.stage] = NULL;
|
||||
|
||||
kinc_g5_internal_set_textures(list);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_texture_from_render_target_depth(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_render_target_t *target) {
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
target->impl.stage_depth = unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT];
|
||||
list->impl.currentRenderTargets[target->impl.stage_depth] = target;
|
||||
}
|
||||
else if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
target->impl.stage_depth = unit.stages[KINC_G5_SHADER_TYPE_VERTEX];
|
||||
list->impl.currentRenderTargets[target->impl.stage_depth] = target;
|
||||
}
|
||||
list->impl.currentTextures[target->impl.stage_depth] = NULL;
|
||||
|
||||
kinc_g5_internal_set_textures(list);
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "d3d12mini.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct kinc_g5_pipeline;
|
||||
struct kinc_g5_render_target;
|
||||
struct kinc_g5_texture;
|
||||
struct kinc_g5_sampler;
|
||||
|
||||
#define KINC_INTERNAL_G5_TEXTURE_COUNT 16
|
||||
|
||||
typedef struct {
|
||||
struct ID3D12CommandAllocator *_commandAllocator;
|
||||
struct ID3D12GraphicsCommandList *_commandList;
|
||||
struct kinc_g5_pipeline *_currentPipeline;
|
||||
int _indexCount;
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool open;
|
||||
#endif
|
||||
|
||||
struct D3D12Rect current_full_scissor;
|
||||
|
||||
// keep track of when a command-list is done
|
||||
uint64_t fence_value;
|
||||
struct ID3D12Fence *fence;
|
||||
HANDLE fence_event;
|
||||
|
||||
struct kinc_g5_render_target *currentRenderTargets[KINC_INTERNAL_G5_TEXTURE_COUNT];
|
||||
struct kinc_g5_texture *currentTextures[KINC_INTERNAL_G5_TEXTURE_COUNT];
|
||||
struct kinc_g5_sampler *current_samplers[KINC_INTERNAL_G5_TEXTURE_COUNT];
|
||||
|
||||
int heapIndex;
|
||||
struct ID3D12DescriptorHeap *srvHeap;
|
||||
struct ID3D12DescriptorHeap *samplerHeap;
|
||||
} CommandList5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,167 @@
|
||||
#include <kinc/graphics5/compute.h>
|
||||
|
||||
#include <kinc/graphics4/texture.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
|
||||
void kinc_g5_compute_shader_init(kinc_g5_compute_shader *shader, void *_data, int length) {
|
||||
unsigned index = 0;
|
||||
uint8_t *data = (uint8_t *)_data;
|
||||
|
||||
memset(&shader->impl.attributes, 0, sizeof(shader->impl.attributes));
|
||||
int attributesCount = data[index++];
|
||||
for (int i = 0; i < attributesCount; ++i) {
|
||||
unsigned char name[256];
|
||||
for (unsigned i2 = 0; i2 < 255; ++i2) {
|
||||
name[i2] = data[index++];
|
||||
if (name[i2] == 0)
|
||||
break;
|
||||
}
|
||||
shader->impl.attributes[i].hash = kinc_internal_hash_name(name);
|
||||
shader->impl.attributes[i].index = data[index++];
|
||||
}
|
||||
|
||||
memset(&shader->impl.textures, 0, sizeof(shader->impl.textures));
|
||||
uint8_t texCount = data[index++];
|
||||
for (unsigned i = 0; i < texCount; ++i) {
|
||||
unsigned char name[256];
|
||||
for (unsigned i2 = 0; i2 < 255; ++i2) {
|
||||
name[i2] = data[index++];
|
||||
if (name[i2] == 0)
|
||||
break;
|
||||
}
|
||||
shader->impl.textures[i].hash = kinc_internal_hash_name(name);
|
||||
shader->impl.textures[i].index = data[index++];
|
||||
}
|
||||
|
||||
memset(&shader->impl.constants, 0, sizeof(shader->impl.constants));
|
||||
uint8_t constantCount = data[index++];
|
||||
shader->impl.constantsSize = 0;
|
||||
for (unsigned i = 0; i < constantCount; ++i) {
|
||||
unsigned char name[256];
|
||||
for (unsigned i2 = 0; i2 < 255; ++i2) {
|
||||
name[i2] = data[index++];
|
||||
if (name[i2] == 0)
|
||||
break;
|
||||
}
|
||||
kinc_compute_internal_shader_constant_t constant;
|
||||
constant.hash = kinc_internal_hash_name(name);
|
||||
memcpy(&constant.offset, &data[index], sizeof(constant.offset));
|
||||
index += 4;
|
||||
memcpy(&constant.size, &data[index], sizeof(constant.size));
|
||||
index += 4;
|
||||
constant.columns = data[index];
|
||||
index += 1;
|
||||
constant.rows = data[index];
|
||||
index += 1;
|
||||
|
||||
shader->impl.constants[i] = constant;
|
||||
shader->impl.constantsSize = constant.offset + constant.size;
|
||||
}
|
||||
|
||||
shader->impl.length = (int)(length - index);
|
||||
shader->impl.data = (uint8_t *)malloc(shader->impl.length);
|
||||
assert(shader->impl.data != NULL);
|
||||
memcpy(shader->impl.data, &data[index], shader->impl.length);
|
||||
|
||||
D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {0};
|
||||
desc.CS.BytecodeLength = shader->impl.length;
|
||||
desc.CS.pShaderBytecode = shader->impl.data;
|
||||
desc.pRootSignature = globalComputeRootSignature;
|
||||
HRESULT hr = device->CreateComputePipelineState(&desc, IID_GRAPHICS_PPV_ARGS(&shader->impl.pso));
|
||||
|
||||
if (hr != S_OK) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not initialize compute shader.");
|
||||
return;
|
||||
}
|
||||
|
||||
// kinc_microsoft_affirm(device->CreateBuffer(&CD3D11_BUFFER_DESC(getMultipleOf16(shader->impl.constantsSize), D3D11_BIND_CONSTANT_BUFFER), nullptr,
|
||||
// &shader->impl.constantBuffer));
|
||||
}
|
||||
|
||||
void kinc_g5_compute_shader_destroy(kinc_g5_compute_shader *shader) {
|
||||
if (shader->impl.pso != NULL) {
|
||||
shader->impl.pso->Release();
|
||||
shader->impl.pso = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static kinc_compute_internal_shader_constant_t *findComputeConstant(kinc_compute_internal_shader_constant_t *constants, uint32_t hash) {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
if (constants[i].hash == hash) {
|
||||
return &constants[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static kinc_internal_hash_index_t *findComputeTextureUnit(kinc_internal_hash_index_t *units, uint32_t hash) {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
if (units[i].hash == hash) {
|
||||
return &units[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kinc_g5_constant_location_t kinc_g5_compute_shader_get_constant_location(kinc_g5_compute_shader *shader, const char *name) {
|
||||
kinc_g5_constant_location_t location = {0};
|
||||
|
||||
uint32_t hash = kinc_internal_hash_name((unsigned char *)name);
|
||||
|
||||
kinc_compute_internal_shader_constant_t *constant = findComputeConstant(shader->impl.constants, hash);
|
||||
if (constant == NULL) {
|
||||
location.impl.computeOffset = 0;
|
||||
location.impl.computeSize = 0;
|
||||
}
|
||||
else {
|
||||
location.impl.computeOffset = constant->offset;
|
||||
location.impl.computeSize = constant->size;
|
||||
}
|
||||
|
||||
if (location.impl.computeSize == 0) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Uniform %s not found.", name);
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
kinc_g5_texture_unit_t kinc_g5_compute_shader_get_texture_unit(kinc_g5_compute_shader *shader, const char *name) {
|
||||
char unitName[64];
|
||||
int unitOffset = 0;
|
||||
size_t len = strlen(name);
|
||||
if (len > 63)
|
||||
len = 63;
|
||||
strncpy(unitName, name, len + 1);
|
||||
if (unitName[len - 1] == ']') { // Check for array - mySampler[2]
|
||||
unitOffset = (int)(unitName[len - 2] - '0'); // Array index is unit offset
|
||||
unitName[len - 3] = 0; // Strip array from name
|
||||
}
|
||||
|
||||
uint32_t hash = kinc_internal_hash_name((unsigned char *)unitName);
|
||||
|
||||
kinc_g5_texture_unit_t unit;
|
||||
for (int i = 0; i < KINC_G5_SHADER_TYPE_COUNT; ++i) {
|
||||
unit.stages[i] = -1;
|
||||
}
|
||||
kinc_internal_hash_index_t *computeUnit = findComputeTextureUnit(shader->impl.textures, hash);
|
||||
if (computeUnit == NULL) {
|
||||
#ifndef NDEBUG
|
||||
static int notFoundCount = 0;
|
||||
if (notFoundCount < 10) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Sampler %s not found.", unitName);
|
||||
++notFoundCount;
|
||||
}
|
||||
else if (notFoundCount == 10) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Giving up on sampler not found messages.", unitName);
|
||||
++notFoundCount;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
unit.stages[KINC_G5_SHADER_TYPE_COMPUTE] = computeUnit->index + unitOffset;
|
||||
}
|
||||
return unit;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/backend/graphics5/ShaderHash.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t hash;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
uint8_t columns;
|
||||
uint8_t rows;
|
||||
} kinc_compute_internal_shader_constant_t;
|
||||
|
||||
typedef struct kinc_g5_compute_shader_impl {
|
||||
kinc_compute_internal_shader_constant_t constants[64];
|
||||
int constantsSize;
|
||||
kinc_internal_hash_index_t attributes[64];
|
||||
kinc_internal_hash_index_t textures[64];
|
||||
uint8_t *data;
|
||||
int length;
|
||||
struct ID3D12Buffer *constantBuffer;
|
||||
struct ID3D12PipelineState *pso;
|
||||
} kinc_g5_compute_shader_impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,70 @@
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
|
||||
bool kinc_g5_transposeMat3 = false;
|
||||
bool kinc_g5_transposeMat4 = false;
|
||||
|
||||
void kinc_g5_constant_buffer_init(kinc_g5_constant_buffer_t *buffer, int size) {
|
||||
buffer->impl.mySize = size;
|
||||
buffer->data = NULL;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProperties;
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProperties.CreationNodeMask = 1;
|
||||
heapProperties.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC resourceDesc;
|
||||
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resourceDesc.Alignment = 0;
|
||||
resourceDesc.Width = size;
|
||||
resourceDesc.Height = 1;
|
||||
resourceDesc.DepthOrArraySize = 1;
|
||||
resourceDesc.MipLevels = 1;
|
||||
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
resourceDesc.SampleDesc.Count = 1;
|
||||
resourceDesc.SampleDesc.Quality = 0;
|
||||
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
kinc_microsoft_affirm(device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&buffer->impl.constant_buffer)));
|
||||
|
||||
void *p;
|
||||
buffer->impl.constant_buffer->Map(0, NULL, &p);
|
||||
ZeroMemory(p, size);
|
||||
buffer->impl.constant_buffer->Unmap(0, NULL);
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_destroy(kinc_g5_constant_buffer_t *buffer) {
|
||||
buffer->impl.constant_buffer->Release();
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_lock_all(kinc_g5_constant_buffer_t *buffer) {
|
||||
kinc_g5_constant_buffer_lock(buffer, 0, kinc_g5_constant_buffer_size(buffer));
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_lock(kinc_g5_constant_buffer_t *buffer, int start, int count) {
|
||||
buffer->impl.lastStart = start;
|
||||
buffer->impl.lastCount = count;
|
||||
D3D12_RANGE range;
|
||||
range.Begin = start;
|
||||
range.End = range.Begin + count;
|
||||
uint8_t *p;
|
||||
buffer->impl.constant_buffer->Map(0, &range, (void **)&p);
|
||||
buffer->data = &p[start];
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_unlock(kinc_g5_constant_buffer_t *buffer) {
|
||||
D3D12_RANGE range;
|
||||
range.Begin = buffer->impl.lastStart;
|
||||
range.End = range.Begin + buffer->impl.lastCount;
|
||||
buffer->impl.constant_buffer->Unmap(0, &range);
|
||||
buffer->data = NULL;
|
||||
}
|
||||
|
||||
int kinc_g5_constant_buffer_size(kinc_g5_constant_buffer_t *buffer) {
|
||||
return buffer->impl.mySize;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID3D12Resource;
|
||||
|
||||
typedef struct {
|
||||
struct ID3D12Resource *constant_buffer;
|
||||
int lastStart;
|
||||
int lastCount;
|
||||
int mySize;
|
||||
} ConstantBuffer5Impl;
|
||||
|
||||
KINC_FUNC extern bool kinc_g5_transposeMat3;
|
||||
KINC_FUNC extern bool kinc_g5_transposeMat4;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID3D12CommandAllocator;
|
||||
struct ID3D12GraphicsCommandList;
|
||||
struct ID3D12Fence;
|
||||
struct ID3D12Resource;
|
||||
struct ID3D12DescriptorHeap;
|
||||
struct IDXGISwapChain;
|
||||
|
||||
typedef void *HANDLE;
|
||||
typedef unsigned __int64 UINT64;
|
||||
|
||||
struct D3D12Viewport {
|
||||
float TopLeftX;
|
||||
float TopLeftY;
|
||||
float Width;
|
||||
float Height;
|
||||
float MinDepth;
|
||||
float MaxDepth;
|
||||
};
|
||||
|
||||
struct D3D12Rect {
|
||||
long left;
|
||||
long top;
|
||||
long right;
|
||||
long bottom;
|
||||
};
|
||||
|
||||
#define QUEUE_SLOT_COUNT 2
|
||||
|
||||
struct dx_window {
|
||||
#ifndef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
struct IDXGISwapChain *swapChain;
|
||||
#endif
|
||||
UINT64 current_fence_value;
|
||||
UINT64 fence_values[QUEUE_SLOT_COUNT];
|
||||
HANDLE frame_fence_events[QUEUE_SLOT_COUNT];
|
||||
struct ID3D12Fence *frame_fences[QUEUE_SLOT_COUNT];
|
||||
int width;
|
||||
int height;
|
||||
int new_width;
|
||||
int new_height;
|
||||
int current_backbuffer;
|
||||
bool vsync;
|
||||
int window_index;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,106 @@
|
||||
#include <kinc/global.h>
|
||||
|
||||
// Windows 7
|
||||
#define WINVER 0x0601
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINNT 0x0601
|
||||
|
||||
#define NOATOM
|
||||
#define NOCLIPBOARD
|
||||
#define NOCOLOR
|
||||
#define NOCOMM
|
||||
#define NOCTLMGR
|
||||
#define NODEFERWINDOWPOS
|
||||
#define NODRAWTEXT
|
||||
#define NOGDI
|
||||
#define NOGDICAPMASKS
|
||||
#define NOHELP
|
||||
#define NOICONS
|
||||
#define NOKANJI
|
||||
#define NOKEYSTATES
|
||||
#define NOMB
|
||||
#define NOMCX
|
||||
#define NOMEMMGR
|
||||
#define NOMENUS
|
||||
#define NOMETAFILE
|
||||
#define NOMINMAX
|
||||
// #define NOMSG
|
||||
#define NONLS
|
||||
#define NOOPENFILE
|
||||
#define NOPROFILER
|
||||
#define NORASTEROPS
|
||||
#define NOSCROLL
|
||||
#define NOSERVICE
|
||||
#define NOSHOWWINDOW
|
||||
#define NOSOUND
|
||||
#define NOSYSCOMMANDS
|
||||
#define NOSYSMETRICS
|
||||
#define NOTEXTMETRIC
|
||||
// #define NOUSER
|
||||
#define NOVIRTUALKEYCODES
|
||||
#define NOWH
|
||||
#define NOWINMESSAGES
|
||||
#define NOWINOFFSETS
|
||||
#define NOWINSTYLES
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#ifdef KINC_WINDOWS
|
||||
#include <d3d12.h>
|
||||
#else
|
||||
#include <kinc/backend/d3d12_special_edition.h>
|
||||
#endif
|
||||
#ifdef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
struct DXGI_SWAP_CHAIN_DESC1;
|
||||
#else
|
||||
#include <dxgi.h>
|
||||
#endif
|
||||
|
||||
#include "d3d12mini.h"
|
||||
|
||||
#ifndef IID_GRAPHICS_PPV_ARGS
|
||||
#define IID_GRAPHICS_PPV_ARGS(x) IID_PPV_ARGS(x)
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
ID3D12Device *device = NULL;
|
||||
}
|
||||
static ID3D12RootSignature *globalRootSignature = NULL;
|
||||
static ID3D12RootSignature *globalComputeRootSignature = NULL;
|
||||
// extern ID3D12GraphicsCommandList* commandList;
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAXIMUM_WINDOWS 16
|
||||
|
||||
struct dx_ctx {
|
||||
int current_window;
|
||||
struct dx_window windows[MAXIMUM_WINDOWS];
|
||||
};
|
||||
|
||||
static struct dx_ctx dx_ctx = {0};
|
||||
|
||||
inline struct dx_window *kinc_dx_current_window() {
|
||||
return &dx_ctx.windows[dx_ctx.current_window];
|
||||
}
|
||||
|
||||
static bool compute_pipeline_set = false;
|
||||
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "Direct3D12.c.h"
|
||||
#include "ShaderHash.c.h"
|
||||
#include "commandlist.c.h"
|
||||
#include "compute.c.h"
|
||||
#include "constantbuffer.c.h"
|
||||
#include "indexbuffer.c.h"
|
||||
#include "pipeline.c.h"
|
||||
#include "raytrace.c.h"
|
||||
#include "rendertarget.c.h"
|
||||
#include "sampler.c.h"
|
||||
#include "shader.c.h"
|
||||
#include "texture.c.h"
|
||||
#include "vertexbuffer.c.h"
|
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/backend/graphics5/indexbuffer.h>
|
||||
#include <kinc/backend/graphics5/rendertarget.h>
|
||||
#include <kinc/backend/graphics5/texture.h>
|
||||
#include <kinc/backend/graphics5/vertexbuffer.h>
|
@ -0,0 +1,130 @@
|
||||
#include "indexbuffer.h"
|
||||
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
|
||||
void kinc_g5_index_buffer_init(kinc_g5_index_buffer_t *buffer, int count, kinc_g5_index_buffer_format_t format, bool gpuMemory) {
|
||||
buffer->impl.count = count;
|
||||
buffer->impl.gpu_memory = gpuMemory;
|
||||
buffer->impl.format = format;
|
||||
|
||||
// static_assert(sizeof(D3D12IindexBufferView) == sizeof(D3D12_INDEX_BUFFER_VIEW), "Something is wrong with D3D12IindexBufferView");
|
||||
int uploadBufferSize = format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? sizeof(uint16_t) * count : sizeof(uint32_t) * count;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProperties;
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProperties.CreationNodeMask = 1;
|
||||
heapProperties.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC resourceDesc;
|
||||
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resourceDesc.Alignment = 0;
|
||||
resourceDesc.Width = uploadBufferSize;
|
||||
resourceDesc.Height = 1;
|
||||
resourceDesc.DepthOrArraySize = 1;
|
||||
resourceDesc.MipLevels = 1;
|
||||
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
resourceDesc.SampleDesc.Count = 1;
|
||||
resourceDesc.SampleDesc.Quality = 0;
|
||||
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
kinc_microsoft_affirm(device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&buffer->impl.upload_buffer)));
|
||||
|
||||
if (gpuMemory) {
|
||||
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;
|
||||
|
||||
kinc_microsoft_affirm(device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&buffer->impl.index_buffer)));
|
||||
|
||||
buffer->impl.index_buffer_view.BufferLocation = buffer->impl.index_buffer->GetGPUVirtualAddress();
|
||||
}
|
||||
else {
|
||||
buffer->impl.index_buffer_view.BufferLocation = buffer->impl.upload_buffer->GetGPUVirtualAddress();
|
||||
}
|
||||
buffer->impl.index_buffer_view.SizeInBytes = uploadBufferSize;
|
||||
buffer->impl.index_buffer_view.Format = format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
||||
|
||||
buffer->impl.last_start = 0;
|
||||
buffer->impl.last_count = kinc_g5_index_buffer_count(buffer);
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_destroy(kinc_g5_index_buffer_t *buffer) {
|
||||
if (buffer->impl.index_buffer != NULL) {
|
||||
buffer->impl.index_buffer->Release();
|
||||
buffer->impl.index_buffer = NULL;
|
||||
}
|
||||
|
||||
buffer->impl.upload_buffer->Release();
|
||||
buffer->impl.upload_buffer = NULL;
|
||||
}
|
||||
|
||||
static int kinc_g5_internal_index_buffer_stride(kinc_g5_index_buffer_t *buffer) {
|
||||
return buffer->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_32BIT ? 4 : 2;
|
||||
}
|
||||
|
||||
void *kinc_g5_index_buffer_lock_all(kinc_g5_index_buffer_t *buffer) {
|
||||
return kinc_g5_index_buffer_lock(buffer, 0, kinc_g5_index_buffer_count(buffer));
|
||||
}
|
||||
|
||||
void *kinc_g5_index_buffer_lock(kinc_g5_index_buffer_t *buffer, int start, int count) {
|
||||
buffer->impl.last_start = start;
|
||||
buffer->impl.last_count = count;
|
||||
|
||||
D3D12_RANGE range;
|
||||
range.Begin = start * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
range.End = (start + count) * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
|
||||
void *p;
|
||||
buffer->impl.upload_buffer->Map(0, &range, &p);
|
||||
byte *bytes = (byte *)p;
|
||||
bytes += start * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_unlock_all(kinc_g5_index_buffer_t *buffer) {
|
||||
D3D12_RANGE range;
|
||||
range.Begin = buffer->impl.last_start * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
range.End = (buffer->impl.last_start + buffer->impl.last_count) * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
|
||||
buffer->impl.upload_buffer->Unmap(0, &range);
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_unlock(kinc_g5_index_buffer_t *buffer, int count) {
|
||||
D3D12_RANGE range;
|
||||
range.Begin = buffer->impl.last_start * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
range.End = (buffer->impl.last_start + count) * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
|
||||
buffer->impl.upload_buffer->Unmap(0, &range);
|
||||
}
|
||||
|
||||
void kinc_g5_internal_index_buffer_upload(kinc_g5_index_buffer_t *buffer, ID3D12GraphicsCommandList *commandList) {
|
||||
if (!buffer->impl.gpu_memory)
|
||||
return;
|
||||
|
||||
commandList->CopyBufferRegion(buffer->impl.index_buffer, 0, buffer->impl.upload_buffer, 0,
|
||||
buffer->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? sizeof(uint16_t) * buffer->impl.count
|
||||
: sizeof(uint32_t) * buffer->impl.count);
|
||||
|
||||
D3D12_RESOURCE_BARRIER barriers[1] = {};
|
||||
barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barriers[0].Transition.pResource = buffer->impl.index_buffer;
|
||||
barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
|
||||
barriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
|
||||
commandList->ResourceBarrier(1, barriers);
|
||||
}
|
||||
|
||||
int kinc_g5_index_buffer_count(kinc_g5_index_buffer_t *buffer) {
|
||||
return buffer->impl.count;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID3D12Resource;
|
||||
|
||||
struct D3D12IindexBufferView {
|
||||
__int64 BufferLocation;
|
||||
unsigned int SizeInBytes;
|
||||
int Format;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct ID3D12Resource *index_buffer;
|
||||
struct D3D12IindexBufferView index_buffer_view;
|
||||
struct ID3D12Resource *upload_buffer;
|
||||
int count;
|
||||
bool gpu_memory;
|
||||
int format;
|
||||
int last_start;
|
||||
int last_count;
|
||||
} IndexBuffer5Impl;
|
||||
|
||||
struct kinc_g5_index_buffer;
|
||||
|
||||
void kinc_g5_internal_index_buffer_upload(struct kinc_g5_index_buffer *buffer, struct ID3D12GraphicsCommandList *commandList);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,563 @@
|
||||
#include "pipeline.h"
|
||||
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/graphics5/shader.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
|
||||
void kinc_g5_internal_setConstants(kinc_g5_command_list_t *commandList, kinc_g5_pipeline_t *pipeline) {
|
||||
/*if (currentProgram->vertexShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->vertexConstantBuffer, 0, nullptr, vertexConstants, 0, 0);
|
||||
context->VSSetConstantBuffers(0, 1, ¤tProgram->vertexConstantBuffer);
|
||||
}
|
||||
if (currentProgram->fragmentShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->fragmentConstantBuffer, 0, nullptr, fragmentConstants, 0, 0);
|
||||
context->PSSetConstantBuffers(0, 1, ¤tProgram->fragmentConstantBuffer);
|
||||
}
|
||||
if (currentProgram->geometryShader != nullptr && currentProgram->geometryShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->geometryConstantBuffer, 0, nullptr, geometryConstants, 0, 0);
|
||||
context->GSSetConstantBuffers(0, 1, ¤tProgram->geometryConstantBuffer);
|
||||
}
|
||||
if (currentProgram->tessControlShader != nullptr && currentProgram->tessControlShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->tessControlConstantBuffer, 0, nullptr, tessControlConstants, 0, 0);
|
||||
context->HSSetConstantBuffers(0, 1, ¤tProgram->tessControlConstantBuffer);
|
||||
}
|
||||
if (currentProgram->tessEvalShader != nullptr && currentProgram->tessEvalShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->tessEvalConstantBuffer, 0, nullptr, tessEvalConstants, 0, 0);
|
||||
context->DSSetConstantBuffers(0, 1, ¤tProgram->tessEvalConstantBuffer);
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef KINC_DXC
|
||||
// commandList->SetGraphicsRootSignature(pipeline->impl.rootSignature);
|
||||
commandList->impl._commandList->SetGraphicsRootSignature(globalRootSignature);
|
||||
#else
|
||||
commandList->impl._commandList->SetGraphicsRootSignature(globalRootSignature);
|
||||
#endif
|
||||
|
||||
if (pipeline->impl.textures > 0) {
|
||||
kinc_g5_internal_set_textures(commandList);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_internal_set_compute_constants(kinc_g5_command_list_t *commandList) {
|
||||
/*if (currentProgram->vertexShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->vertexConstantBuffer, 0, nullptr, vertexConstants, 0, 0);
|
||||
context->VSSetConstantBuffers(0, 1, ¤tProgram->vertexConstantBuffer);
|
||||
}
|
||||
if (currentProgram->fragmentShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->fragmentConstantBuffer, 0, nullptr, fragmentConstants, 0, 0);
|
||||
context->PSSetConstantBuffers(0, 1, ¤tProgram->fragmentConstantBuffer);
|
||||
}
|
||||
if (currentProgram->geometryShader != nullptr && currentProgram->geometryShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->geometryConstantBuffer, 0, nullptr, geometryConstants, 0, 0);
|
||||
context->GSSetConstantBuffers(0, 1, ¤tProgram->geometryConstantBuffer);
|
||||
}
|
||||
if (currentProgram->tessControlShader != nullptr && currentProgram->tessControlShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->tessControlConstantBuffer, 0, nullptr, tessControlConstants, 0, 0);
|
||||
context->HSSetConstantBuffers(0, 1, ¤tProgram->tessControlConstantBuffer);
|
||||
}
|
||||
if (currentProgram->tessEvalShader != nullptr && currentProgram->tessEvalShader->constantsSize > 0) {
|
||||
context->UpdateSubresource(currentProgram->tessEvalConstantBuffer, 0, nullptr, tessEvalConstants, 0, 0);
|
||||
context->DSSetConstantBuffers(0, 1, ¤tProgram->tessEvalConstantBuffer);
|
||||
}
|
||||
*/
|
||||
|
||||
commandList->impl._commandList->SetComputeRootSignature(globalComputeRootSignature);
|
||||
|
||||
//if (pipeline->impl.textures > 0) {
|
||||
kinc_g5_internal_set_textures(commandList);
|
||||
//}
|
||||
}
|
||||
|
||||
void kinc_g5_pipeline_init(kinc_g5_pipeline_t *pipe) {
|
||||
kinc_g5_internal_pipeline_init(pipe);
|
||||
}
|
||||
|
||||
void kinc_g5_pipeline_destroy(kinc_g5_pipeline_t *pipe) {
|
||||
if (pipe->impl.pso != NULL) {
|
||||
pipe->impl.pso->Release();
|
||||
pipe->impl.pso = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// void PipelineState5Impl::set(Graphics5::PipelineState* pipeline) {
|
||||
//_current = this;
|
||||
// context->VSSetShader((ID3D11VertexShader*)vertexShader->shader, nullptr, 0);
|
||||
// context->PSSetShader((ID3D11PixelShader*)fragmentShader->shader, nullptr, 0);
|
||||
|
||||
// if (geometryShader != nullptr) context->GSSetShader((ID3D11GeometryShader*)geometryShader->shader, nullptr, 0);
|
||||
// if (tessControlShader != nullptr) context->HSSetShader((ID3D11HullShader*)tessControlShader->shader, nullptr, 0);
|
||||
// if (tessEvalShader != nullptr) context->DSSetShader((ID3D11DomainShader*)tessEvalShader->shader, nullptr, 0);
|
||||
|
||||
// context->IASetInputLayout(inputLayout);
|
||||
//}
|
||||
|
||||
#define MAX_SHADER_THING 32
|
||||
|
||||
static ShaderConstant findConstant(kinc_g5_shader_t *shader, const char *name) {
|
||||
if (shader != NULL) {
|
||||
for (int i = 0; i < MAX_SHADER_THING; ++i) {
|
||||
if (strcmp(shader->impl.constants[i].name, name) == 0) {
|
||||
return shader->impl.constants[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderConstant constant;
|
||||
constant.name[0] = 0;
|
||||
constant.offset = -1;
|
||||
constant.size = 0;
|
||||
return constant;
|
||||
}
|
||||
|
||||
static ShaderTexture findTexture(kinc_g5_shader_t *shader, const char *name) {
|
||||
for (int i = 0; i < MAX_SHADER_THING; ++i) {
|
||||
if (strcmp(shader->impl.textures[i].name, name) == 0) {
|
||||
return shader->impl.textures[i];
|
||||
}
|
||||
}
|
||||
|
||||
ShaderTexture texture;
|
||||
texture.name[0] = 0;
|
||||
texture.texture = -1;
|
||||
return texture;
|
||||
}
|
||||
|
||||
static ShaderAttribute findAttribute(kinc_g5_shader_t *shader, const char *name) {
|
||||
for (int i = 0; i < MAX_SHADER_THING; ++i) {
|
||||
if (strcmp(shader->impl.attributes[i].name, name) == 0) {
|
||||
return shader->impl.attributes[i];
|
||||
}
|
||||
}
|
||||
|
||||
ShaderAttribute attribute;
|
||||
attribute.name[0] = 0;
|
||||
attribute.attribute = -1;
|
||||
return attribute;
|
||||
}
|
||||
|
||||
kinc_g5_constant_location_t kinc_g5_pipeline_get_constant_location(struct kinc_g5_pipeline *pipe, const char *name) {
|
||||
kinc_g5_constant_location_t location;
|
||||
|
||||
{
|
||||
ShaderConstant constant = findConstant(pipe->vertexShader, name);
|
||||
location.impl.vertexOffset = constant.offset;
|
||||
location.impl.vertexSize = constant.size;
|
||||
}
|
||||
|
||||
{
|
||||
ShaderConstant constant = findConstant(pipe->fragmentShader, name);
|
||||
location.impl.fragmentOffset = constant.offset;
|
||||
location.impl.fragmentSize = constant.size;
|
||||
}
|
||||
|
||||
location.impl.computeOffset = 0;
|
||||
location.impl.computeSize = 0;
|
||||
|
||||
{
|
||||
ShaderConstant constant = findConstant(pipe->geometryShader, name);
|
||||
location.impl.geometryOffset = constant.offset;
|
||||
location.impl.geometrySize = constant.size;
|
||||
}
|
||||
|
||||
{
|
||||
ShaderConstant constant = findConstant(pipe->tessellationControlShader, name);
|
||||
location.impl.tessControlOffset = constant.offset;
|
||||
location.impl.tessControlSize = constant.size;
|
||||
}
|
||||
|
||||
{
|
||||
ShaderConstant constant = findConstant(pipe->tessellationEvaluationShader, name);
|
||||
location.impl.tessEvalOffset = constant.offset;
|
||||
location.impl.tessEvalSize = constant.size;
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
kinc_g5_texture_unit_t kinc_g5_pipeline_get_texture_unit(kinc_g5_pipeline_t *pipe, const char *name) {
|
||||
kinc_g5_texture_unit_t unit;
|
||||
for (int i = 0; i < KINC_G5_SHADER_TYPE_COUNT; ++i) {
|
||||
unit.stages[i] = -1;
|
||||
}
|
||||
|
||||
ShaderTexture vertexTexture = findTexture(pipe->vertexShader, name);
|
||||
if (vertexTexture.texture != -1) {
|
||||
unit.stages[KINC_G5_SHADER_TYPE_VERTEX] = vertexTexture.texture;
|
||||
}
|
||||
else {
|
||||
ShaderTexture fragmentTexture = findTexture(pipe->fragmentShader, name);
|
||||
unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] = fragmentTexture.texture;
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
static D3D12_BLEND convert_blend_factor(kinc_g5_blending_factor_t factor) {
|
||||
switch (factor) {
|
||||
case KINC_G5_BLEND_ONE:
|
||||
return D3D12_BLEND_ONE;
|
||||
case KINC_G5_BLEND_ZERO:
|
||||
return D3D12_BLEND_ZERO;
|
||||
case KINC_G5_BLEND_SOURCE_ALPHA:
|
||||
return D3D12_BLEND_SRC_ALPHA;
|
||||
case KINC_G5_BLEND_DEST_ALPHA:
|
||||
return D3D12_BLEND_DEST_ALPHA;
|
||||
case KINC_G5_BLEND_INV_SOURCE_ALPHA:
|
||||
return D3D12_BLEND_INV_SRC_ALPHA;
|
||||
case KINC_G5_BLEND_INV_DEST_ALPHA:
|
||||
return D3D12_BLEND_INV_DEST_ALPHA;
|
||||
case KINC_G5_BLEND_SOURCE_COLOR:
|
||||
return D3D12_BLEND_SRC_COLOR;
|
||||
case KINC_G5_BLEND_DEST_COLOR:
|
||||
return D3D12_BLEND_DEST_COLOR;
|
||||
case KINC_G5_BLEND_INV_SOURCE_COLOR:
|
||||
return D3D12_BLEND_INV_SRC_COLOR;
|
||||
case KINC_G5_BLEND_INV_DEST_COLOR:
|
||||
return D3D12_BLEND_INV_DEST_COLOR;
|
||||
case KINC_G5_BLEND_CONSTANT:
|
||||
return D3D12_BLEND_BLEND_FACTOR;
|
||||
case KINC_G5_BLEND_INV_CONSTANT:
|
||||
return D3D12_BLEND_INV_BLEND_FACTOR;
|
||||
default:
|
||||
assert(false);
|
||||
return D3D12_BLEND_ONE;
|
||||
}
|
||||
}
|
||||
|
||||
static D3D12_BLEND_OP convert_blend_operation(kinc_g5_blending_operation_t op) {
|
||||
switch (op) {
|
||||
case KINC_G5_BLENDOP_ADD:
|
||||
return D3D12_BLEND_OP_ADD;
|
||||
case KINC_G5_BLENDOP_SUBTRACT:
|
||||
return D3D12_BLEND_OP_SUBTRACT;
|
||||
case KINC_G5_BLENDOP_REVERSE_SUBTRACT:
|
||||
return D3D12_BLEND_OP_REV_SUBTRACT;
|
||||
case KINC_G5_BLENDOP_MIN:
|
||||
return D3D12_BLEND_OP_MIN;
|
||||
case KINC_G5_BLENDOP_MAX:
|
||||
return D3D12_BLEND_OP_MAX;
|
||||
default:
|
||||
assert(false);
|
||||
return D3D12_BLEND_OP_ADD;
|
||||
}
|
||||
}
|
||||
|
||||
static D3D12_CULL_MODE convert_cull_mode(kinc_g5_cull_mode_t cullMode) {
|
||||
switch (cullMode) {
|
||||
case KINC_G5_CULL_MODE_CLOCKWISE:
|
||||
return D3D12_CULL_MODE_FRONT;
|
||||
case KINC_G5_CULL_MODE_COUNTERCLOCKWISE:
|
||||
return D3D12_CULL_MODE_BACK;
|
||||
case KINC_G5_CULL_MODE_NEVER:
|
||||
default:
|
||||
return D3D12_CULL_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static D3D12_COMPARISON_FUNC convert_compare_mode(kinc_g5_compare_mode_t compare) {
|
||||
switch (compare) {
|
||||
default:
|
||||
case KINC_G5_COMPARE_MODE_ALWAYS:
|
||||
return D3D12_COMPARISON_FUNC_ALWAYS;
|
||||
case KINC_G5_COMPARE_MODE_NEVER:
|
||||
return D3D12_COMPARISON_FUNC_NEVER;
|
||||
case KINC_G5_COMPARE_MODE_EQUAL:
|
||||
return D3D12_COMPARISON_FUNC_EQUAL;
|
||||
case KINC_G5_COMPARE_MODE_NOT_EQUAL:
|
||||
return D3D12_COMPARISON_FUNC_NOT_EQUAL;
|
||||
case KINC_G5_COMPARE_MODE_LESS:
|
||||
return D3D12_COMPARISON_FUNC_LESS;
|
||||
case KINC_G5_COMPARE_MODE_LESS_EQUAL:
|
||||
return D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
case KINC_G5_COMPARE_MODE_GREATER:
|
||||
return D3D12_COMPARISON_FUNC_GREATER;
|
||||
case KINC_G5_COMPARE_MODE_GREATER_EQUAL:
|
||||
return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
|
||||
}
|
||||
}
|
||||
|
||||
static DXGI_FORMAT convert_format(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 KINC_WINDOWS
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
#else
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void set_blend_state(D3D12_BLEND_DESC *blend_desc, kinc_g5_pipeline_t *pipe, int target) {
|
||||
blend_desc->RenderTarget[target].BlendEnable = pipe->blend_source != KINC_G5_BLEND_ONE || pipe->blend_destination != KINC_G5_BLEND_ZERO ||
|
||||
pipe->alpha_blend_source != KINC_G5_BLEND_ONE || pipe->alpha_blend_destination != KINC_G5_BLEND_ZERO;
|
||||
blend_desc->RenderTarget[target].SrcBlend = convert_blend_factor(pipe->blend_source);
|
||||
blend_desc->RenderTarget[target].DestBlend = convert_blend_factor(pipe->blend_destination);
|
||||
blend_desc->RenderTarget[target].BlendOp = convert_blend_operation(pipe->blend_operation);
|
||||
blend_desc->RenderTarget[target].SrcBlendAlpha = convert_blend_factor(pipe->alpha_blend_source);
|
||||
blend_desc->RenderTarget[target].DestBlendAlpha = convert_blend_factor(pipe->alpha_blend_destination);
|
||||
blend_desc->RenderTarget[target].BlendOpAlpha = convert_blend_operation(pipe->alpha_blend_operation);
|
||||
blend_desc->RenderTarget[target].RenderTargetWriteMask =
|
||||
(((pipe->colorWriteMaskRed[target] ? D3D12_COLOR_WRITE_ENABLE_RED : 0) | (pipe->colorWriteMaskGreen[target] ? D3D12_COLOR_WRITE_ENABLE_GREEN : 0)) |
|
||||
(pipe->colorWriteMaskBlue[target] ? D3D12_COLOR_WRITE_ENABLE_BLUE : 0)) |
|
||||
(pipe->colorWriteMaskAlpha[target] ? D3D12_COLOR_WRITE_ENABLE_ALPHA : 0);
|
||||
}
|
||||
|
||||
void kinc_g5_pipeline_compile(kinc_g5_pipeline_t *pipe) {
|
||||
// TODO FLOAT4x4
|
||||
int vertexAttributeCount = 0;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (pipe->inputLayout[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
vertexAttributeCount += pipe->inputLayout[i]->size;
|
||||
}
|
||||
D3D12_INPUT_ELEMENT_DESC *vertexDesc = (D3D12_INPUT_ELEMENT_DESC *)alloca(sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexAttributeCount);
|
||||
ZeroMemory(vertexDesc, sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexAttributeCount);
|
||||
int curAttr = 0;
|
||||
for (int stream = 0; pipe->inputLayout[stream] != NULL; ++stream) {
|
||||
for (int i = 0; i < pipe->inputLayout[stream]->size; ++i) {
|
||||
vertexDesc[curAttr].SemanticName = "TEXCOORD";
|
||||
#ifdef KINC_KONG
|
||||
vertexDesc[curAttr].SemanticIndex = i;
|
||||
#else
|
||||
vertexDesc[curAttr].SemanticIndex = findAttribute(pipe->vertexShader, pipe->inputLayout[stream]->elements[i].name).attribute;
|
||||
#endif
|
||||
vertexDesc[curAttr].InputSlot = stream;
|
||||
vertexDesc[curAttr].AlignedByteOffset = (i == 0) ? 0 : D3D12_APPEND_ALIGNED_ELEMENT;
|
||||
vertexDesc[curAttr].InputSlotClass =
|
||||
pipe->inputLayout[stream]->instanced ? D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA : D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
vertexDesc[curAttr].InstanceDataStepRate = pipe->inputLayout[stream]->instanced ? 1 : 0;
|
||||
|
||||
switch (pipe->inputLayout[stream]->elements[i].data) {
|
||||
case KINC_G4_VERTEX_DATA_F32_1X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32_FLOAT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_F32_2X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32_FLOAT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_F32_3X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32B32_FLOAT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_F32_4X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_1X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_1X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_1X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8_SNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_1X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8_UNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_2X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8G8_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_2X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8G8_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_2X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8G8_SNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_2X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8G8_UNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_4X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8G8B8A8_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_4X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8G8B8A8_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_4X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8G8B8A8_SNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_4X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_1X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_1X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_1X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16_SNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_1X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16_UNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_2X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16G16_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_2X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16G16_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_2X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16G16_SNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_2X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16G16_UNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_4X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16G16B16A16_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_4X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16G16B16A16_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_4X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16G16B16A16_SNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_4X_NORMALIZED:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I32_1X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U32_1X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I32_2X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U32_2X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I32_3X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32B32_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U32_3X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32B32_UINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I32_4X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32B32A32_SINT;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U32_4X:
|
||||
vertexDesc[curAttr].Format = DXGI_FORMAT_R32G32B32A32_UINT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
curAttr++;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
#ifdef KINC_DXC
|
||||
// hr = device->CreateRootSignature(0, pipe->vertexShader->impl.data, pipe->vertexShader->impl.length, IID_GRAPHICS_PPV_ARGS(&pipe->impl.rootSignature));
|
||||
if (hr != S_OK) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not create root signature.");
|
||||
}
|
||||
pipe->impl.vertexConstantsSize = pipe->vertexShader->impl.constantsSize;
|
||||
pipe->impl.fragmentConstantsSize = pipe->fragmentShader->impl.constantsSize;
|
||||
#endif
|
||||
|
||||
pipe->impl.textures = pipe->fragmentShader->impl.texturesCount;
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {0};
|
||||
psoDesc.VS.BytecodeLength = pipe->vertexShader->impl.length;
|
||||
psoDesc.VS.pShaderBytecode = pipe->vertexShader->impl.data;
|
||||
psoDesc.PS.BytecodeLength = pipe->fragmentShader->impl.length;
|
||||
psoDesc.PS.pShaderBytecode = pipe->fragmentShader->impl.data;
|
||||
#ifdef KINC_DXC
|
||||
// psoDesc.pRootSignature = pipe->impl.rootSignature;
|
||||
psoDesc.pRootSignature = globalRootSignature;
|
||||
#else
|
||||
psoDesc.pRootSignature = globalRootSignature;
|
||||
#endif
|
||||
psoDesc.NumRenderTargets = pipe->colorAttachmentCount;
|
||||
for (int i = 0; i < pipe->colorAttachmentCount; ++i) {
|
||||
psoDesc.RTVFormats[i] = convert_format(pipe->colorAttachment[i]);
|
||||
}
|
||||
psoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN;
|
||||
|
||||
psoDesc.InputLayout.NumElements = vertexAttributeCount;
|
||||
psoDesc.InputLayout.pInputElementDescs = vertexDesc;
|
||||
|
||||
psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
|
||||
psoDesc.RasterizerState.CullMode = convert_cull_mode(pipe->cullMode);
|
||||
psoDesc.RasterizerState.FrontCounterClockwise = FALSE;
|
||||
psoDesc.RasterizerState.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
|
||||
psoDesc.RasterizerState.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
|
||||
psoDesc.RasterizerState.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
|
||||
psoDesc.RasterizerState.DepthClipEnable = TRUE;
|
||||
psoDesc.RasterizerState.MultisampleEnable = FALSE;
|
||||
psoDesc.RasterizerState.AntialiasedLineEnable = FALSE;
|
||||
psoDesc.RasterizerState.ForcedSampleCount = 0;
|
||||
psoDesc.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
||||
|
||||
psoDesc.BlendState.AlphaToCoverageEnable = FALSE;
|
||||
psoDesc.BlendState.IndependentBlendEnable = FALSE;
|
||||
const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = {
|
||||
FALSE,
|
||||
FALSE,
|
||||
D3D12_BLEND_ONE,
|
||||
D3D12_BLEND_ZERO,
|
||||
D3D12_BLEND_OP_ADD,
|
||||
D3D12_BLEND_ONE,
|
||||
D3D12_BLEND_ZERO,
|
||||
D3D12_BLEND_OP_ADD,
|
||||
D3D12_LOGIC_OP_NOOP,
|
||||
D3D12_COLOR_WRITE_ENABLE_ALL,
|
||||
};
|
||||
for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) {
|
||||
psoDesc.BlendState.RenderTarget[i] = defaultRenderTargetBlendDesc;
|
||||
}
|
||||
|
||||
bool independentBlend = false;
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
if (pipe->colorWriteMaskRed[0] != pipe->colorWriteMaskRed[i] || pipe->colorWriteMaskGreen[0] != pipe->colorWriteMaskGreen[i] ||
|
||||
pipe->colorWriteMaskBlue[0] != pipe->colorWriteMaskBlue[i] || pipe->colorWriteMaskAlpha[0] != pipe->colorWriteMaskAlpha[i]) {
|
||||
independentBlend = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
set_blend_state(&psoDesc.BlendState, pipe, 0);
|
||||
if (independentBlend) {
|
||||
psoDesc.BlendState.IndependentBlendEnable = true;
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
set_blend_state(&psoDesc.BlendState, pipe, i);
|
||||
}
|
||||
}
|
||||
|
||||
psoDesc.DepthStencilState.DepthEnable = TRUE;
|
||||
psoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
|
||||
psoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
|
||||
psoDesc.DepthStencilState.StencilEnable = FALSE;
|
||||
psoDesc.DepthStencilState.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
||||
psoDesc.DepthStencilState.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
|
||||
const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = {D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS};
|
||||
psoDesc.DepthStencilState.FrontFace = defaultStencilOp;
|
||||
psoDesc.DepthStencilState.BackFace = defaultStencilOp;
|
||||
|
||||
psoDesc.DepthStencilState.DepthEnable = pipe->depthMode != KINC_G5_COMPARE_MODE_ALWAYS;
|
||||
psoDesc.DepthStencilState.DepthWriteMask = pipe->depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
|
||||
psoDesc.DepthStencilState.DepthFunc = convert_compare_mode(pipe->depthMode);
|
||||
psoDesc.DepthStencilState.StencilEnable = false;
|
||||
psoDesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
|
||||
psoDesc.SampleDesc.Count = 1;
|
||||
psoDesc.SampleMask = 0xFFFFFFFF;
|
||||
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
|
||||
|
||||
hr = device->CreateGraphicsPipelineState(&psoDesc, IID_GRAPHICS_PPV_ARGS(&pipe->impl.pso));
|
||||
if (hr != S_OK) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not create pipeline.");
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct kinc_g5_shader;
|
||||
|
||||
struct ID3D12PipelineState;
|
||||
struct ID3D12GraphicsCommandList;
|
||||
struct ID3D12RootSignature;
|
||||
|
||||
typedef struct {
|
||||
struct ID3D12PipelineState *pso;
|
||||
#ifdef KINC_DXC
|
||||
// struct ID3D12RootSignature *rootSignature;
|
||||
int vertexConstantsSize;
|
||||
int fragmentConstantsSize;
|
||||
#endif
|
||||
int textures;
|
||||
// ID3D11InputLayout* inputLayout;
|
||||
// ID3D11Buffer* fragmentConstantBuffer;
|
||||
// ID3D11Buffer* vertexConstantBuffer;
|
||||
// ID3D11Buffer* geometryConstantBuffer;
|
||||
// ID3D11Buffer* tessEvalConstantBuffer;
|
||||
// ID3D11Buffer* tessControlConstantBuffer;
|
||||
|
||||
// static void setConstants(ID3D12GraphicsCommandList *commandList, Graphics5::PipelineState *pipeline);
|
||||
} PipelineState5Impl;
|
||||
|
||||
typedef struct {
|
||||
struct ID3D12PipelineState *pso;
|
||||
#ifdef KINC_DXC
|
||||
struct ID3D12RootSignature *rootSignature;
|
||||
int vertexConstantsSize;
|
||||
int fragmentConstantsSize;
|
||||
#endif
|
||||
int textures;
|
||||
// ID3D11InputLayout* inputLayout;
|
||||
// ID3D11Buffer* fragmentConstantBuffer;
|
||||
// ID3D11Buffer* vertexConstantBuffer;
|
||||
// ID3D11Buffer* geometryConstantBuffer;
|
||||
// ID3D11Buffer* tessEvalConstantBuffer;
|
||||
// ID3D11Buffer* tessControlConstantBuffer;
|
||||
|
||||
// static void setConstants(ID3D12GraphicsCommandList *commandList, Graphics5::PipelineState *pipeline);
|
||||
} ComputePipelineState5Impl;
|
||||
|
||||
typedef struct {
|
||||
int vertexOffset;
|
||||
uint32_t vertexSize;
|
||||
int fragmentOffset;
|
||||
uint32_t fragmentSize;
|
||||
int computeOffset;
|
||||
uint32_t computeSize;
|
||||
int geometryOffset;
|
||||
uint32_t geometrySize;
|
||||
int tessEvalOffset;
|
||||
uint32_t tessEvalSize;
|
||||
int tessControlOffset;
|
||||
uint32_t tessControlSize;
|
||||
} ConstantLocation5Impl;
|
||||
|
||||
typedef struct {
|
||||
int nothing;
|
||||
} AttributeLocation5Impl;
|
||||
|
||||
struct kinc_g5_pipeline;
|
||||
struct kinc_g5_command_list;
|
||||
|
||||
void kinc_g5_internal_setConstants(struct kinc_g5_command_list *commandList, struct kinc_g5_pipeline *pipeline);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,486 @@
|
||||
#ifndef KINC_XBOX_ONE
|
||||
|
||||
#include <kinc/backend/graphics5/raytrace.h>
|
||||
|
||||
#include <kinc/graphics5/commandlist.h>
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
#include <kinc/graphics5/raytrace.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
|
||||
static const wchar_t *hit_group_name = L"hitgroup";
|
||||
static const wchar_t *raygen_shader_name = L"raygeneration";
|
||||
static const wchar_t *closesthit_shader_name = L"closesthit";
|
||||
static const wchar_t *miss_shader_name = L"miss";
|
||||
|
||||
static ID3D12Device5 *dxrDevice;
|
||||
static ID3D12GraphicsCommandList4 *dxrCommandList;
|
||||
static ID3D12RootSignature *dxrRootSignature;
|
||||
static ID3D12DescriptorHeap *descriptorHeap;
|
||||
static kinc_raytrace_acceleration_structure_t *accel;
|
||||
static kinc_raytrace_pipeline_t *pipeline;
|
||||
static kinc_g5_texture_t *output = NULL;
|
||||
|
||||
void kinc_raytrace_pipeline_init(kinc_raytrace_pipeline_t *pipeline, kinc_g5_command_list_t *command_list, void *ray_shader, int ray_shader_size,
|
||||
kinc_g5_constant_buffer_t *constant_buffer) {
|
||||
pipeline->_constant_buffer = constant_buffer;
|
||||
// Descriptor heap
|
||||
D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc;
|
||||
ZeroMemory(&descriptorHeapDesc, sizeof(descriptorHeapDesc));
|
||||
// Allocate a heap for 3 descriptors:
|
||||
// 2 - bottom and top level acceleration structure
|
||||
// 1 - raytracing output texture SRV
|
||||
descriptorHeapDesc.NumDescriptors = 3;
|
||||
descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||
descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
descriptorHeapDesc.NodeMask = 0;
|
||||
device->CreateDescriptorHeap(&descriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(&descriptorHeap));
|
||||
|
||||
// Device
|
||||
device->QueryInterface(IID_GRAPHICS_PPV_ARGS(&dxrDevice));
|
||||
command_list->impl._commandList->QueryInterface(IID_GRAPHICS_PPV_ARGS(&dxrCommandList));
|
||||
|
||||
// Root signatures
|
||||
// This is a root signature that is shared across all raytracing shaders invoked during a DispatchRays() call.
|
||||
D3D12_DESCRIPTOR_RANGE UAVDescriptor = {};
|
||||
UAVDescriptor.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
UAVDescriptor.NumDescriptors = 1;
|
||||
UAVDescriptor.BaseShaderRegister = 0;
|
||||
UAVDescriptor.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
|
||||
D3D12_ROOT_PARAMETER rootParameters[3] = {};
|
||||
// Output view
|
||||
rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
rootParameters[0].DescriptorTable.NumDescriptorRanges = 1;
|
||||
rootParameters[0].DescriptorTable.pDescriptorRanges = &UAVDescriptor;
|
||||
// Acceleration structure
|
||||
rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
|
||||
rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
rootParameters[1].Descriptor.ShaderRegister = 0;
|
||||
// Constant buffer
|
||||
rootParameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
rootParameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
rootParameters[2].Descriptor.ShaderRegister = 0;
|
||||
|
||||
D3D12_ROOT_SIGNATURE_DESC dxrRootSignatureDesc = {0};
|
||||
dxrRootSignatureDesc.NumParameters = ARRAYSIZE(rootParameters);
|
||||
dxrRootSignatureDesc.pParameters = rootParameters;
|
||||
ID3DBlob *blob = NULL;
|
||||
ID3DBlob *error = NULL;
|
||||
D3D12SerializeRootSignature(&dxrRootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, &error);
|
||||
device->CreateRootSignature(1, blob->GetBufferPointer(), blob->GetBufferSize(), IID_GRAPHICS_PPV_ARGS(&dxrRootSignature));
|
||||
|
||||
// Pipeline
|
||||
D3D12_STATE_OBJECT_DESC raytracingPipeline;
|
||||
ZeroMemory(&raytracingPipeline, sizeof(raytracingPipeline));
|
||||
raytracingPipeline.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE;
|
||||
|
||||
D3D12_SHADER_BYTECODE shaderBytecode = {0};
|
||||
shaderBytecode.pShaderBytecode = ray_shader;
|
||||
shaderBytecode.BytecodeLength = ray_shader_size;
|
||||
|
||||
D3D12_DXIL_LIBRARY_DESC dxilLibrary = {0};
|
||||
dxilLibrary.DXILLibrary = shaderBytecode;
|
||||
D3D12_EXPORT_DESC exports[3] = {0};
|
||||
exports[0].Name = raygen_shader_name;
|
||||
exports[1].Name = closesthit_shader_name;
|
||||
exports[2].Name = miss_shader_name;
|
||||
dxilLibrary.pExports = exports;
|
||||
dxilLibrary.NumExports = 3;
|
||||
|
||||
D3D12_HIT_GROUP_DESC hitGroup = {0};
|
||||
hitGroup.ClosestHitShaderImport = closesthit_shader_name;
|
||||
hitGroup.HitGroupExport = hit_group_name;
|
||||
hitGroup.Type = D3D12_HIT_GROUP_TYPE_TRIANGLES;
|
||||
|
||||
D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {0};
|
||||
shaderConfig.MaxPayloadSizeInBytes = 4 * sizeof(float); // float4 color
|
||||
shaderConfig.MaxAttributeSizeInBytes = 2 * sizeof(float); // float2 barycentrics
|
||||
|
||||
D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {0};
|
||||
pipelineConfig.MaxTraceRecursionDepth = 1; // ~ primary rays only
|
||||
|
||||
D3D12_STATE_SUBOBJECT subobjects[5] = {};
|
||||
subobjects[0].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY;
|
||||
subobjects[0].pDesc = &dxilLibrary;
|
||||
subobjects[1].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP;
|
||||
subobjects[1].pDesc = &hitGroup;
|
||||
subobjects[2].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG;
|
||||
subobjects[2].pDesc = &shaderConfig;
|
||||
subobjects[3].Type = D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE;
|
||||
subobjects[3].pDesc = &dxrRootSignature;
|
||||
subobjects[4].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG;
|
||||
subobjects[4].pDesc = &pipelineConfig;
|
||||
raytracingPipeline.NumSubobjects = 5;
|
||||
raytracingPipeline.pSubobjects = subobjects;
|
||||
|
||||
dxrDevice->CreateStateObject(&raytracingPipeline, IID_GRAPHICS_PPV_ARGS(&pipeline->impl.dxr_state));
|
||||
|
||||
// Shader tables
|
||||
// Get shader identifiers
|
||||
ID3D12StateObjectProperties *stateObjectProps = NULL;
|
||||
pipeline->impl.dxr_state->QueryInterface(IID_GRAPHICS_PPV_ARGS(&stateObjectProps));
|
||||
const void *rayGenShaderId = stateObjectProps->GetShaderIdentifier(raygen_shader_name);
|
||||
const void *missShaderId = stateObjectProps->GetShaderIdentifier(miss_shader_name);
|
||||
const void *hitGroupShaderId = stateObjectProps->GetShaderIdentifier(hit_group_name);
|
||||
UINT shaderIdSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES;
|
||||
int align = D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT;
|
||||
|
||||
// Ray gen shader table
|
||||
{
|
||||
UINT size = shaderIdSize + constant_buffer->impl.mySize;
|
||||
UINT shaderRecordSize = (size + (align - 1)) & ~(align - 1);
|
||||
D3D12_RESOURCE_DESC bufferDesc;
|
||||
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
|
||||
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufferDesc.Width = shaderRecordSize;
|
||||
bufferDesc.Height = 1;
|
||||
bufferDesc.DepthOrArraySize = 1;
|
||||
bufferDesc.MipLevels = 1;
|
||||
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufferDesc.SampleDesc.Count = 1;
|
||||
bufferDesc.SampleDesc.Quality = 0;
|
||||
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
D3D12_HEAP_PROPERTIES uploadHeapProperties;
|
||||
ZeroMemory(&uploadHeapProperties, sizeof(uploadHeapProperties));
|
||||
uploadHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
uploadHeapProperties.CreationNodeMask = 1;
|
||||
uploadHeapProperties.VisibleNodeMask = 1;
|
||||
|
||||
device->CreateCommittedResource(&uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&pipeline->impl.raygen_shader_table));
|
||||
|
||||
D3D12_RANGE rstRange = {0};
|
||||
rstRange.Begin = 0;
|
||||
rstRange.End = 0;
|
||||
uint8_t *byteDest;
|
||||
pipeline->impl.raygen_shader_table->Map(0, &rstRange, (void **)(&byteDest));
|
||||
|
||||
D3D12_RANGE cbRange = {0};
|
||||
cbRange.Begin = 0;
|
||||
cbRange.End = constant_buffer->impl.mySize;
|
||||
void *constantBufferData;
|
||||
constant_buffer->impl.constant_buffer->Map(0, &cbRange, (void **)&constantBufferData);
|
||||
memcpy(byteDest, rayGenShaderId, size);
|
||||
memcpy(byteDest + size, constantBufferData, constant_buffer->impl.mySize);
|
||||
pipeline->impl.raygen_shader_table->Unmap(0, NULL);
|
||||
}
|
||||
|
||||
// Miss shader table
|
||||
{
|
||||
UINT size = shaderIdSize;
|
||||
UINT shaderRecordSize = (size + (align - 1)) & ~(align - 1);
|
||||
D3D12_RESOURCE_DESC bufferDesc;
|
||||
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
|
||||
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufferDesc.Width = shaderRecordSize;
|
||||
bufferDesc.Height = 1;
|
||||
bufferDesc.DepthOrArraySize = 1;
|
||||
bufferDesc.MipLevels = 1;
|
||||
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufferDesc.SampleDesc.Count = 1;
|
||||
bufferDesc.SampleDesc.Quality = 0;
|
||||
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
D3D12_HEAP_PROPERTIES uploadHeapProperties;
|
||||
ZeroMemory(&uploadHeapProperties, sizeof(uploadHeapProperties));
|
||||
uploadHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
uploadHeapProperties.CreationNodeMask = 1;
|
||||
uploadHeapProperties.VisibleNodeMask = 1;
|
||||
|
||||
device->CreateCommittedResource(&uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&pipeline->impl.miss_shader_table));
|
||||
|
||||
D3D12_RANGE mstRange = {0};
|
||||
mstRange.Begin = 0;
|
||||
mstRange.End = 0;
|
||||
uint8_t *byteDest;
|
||||
pipeline->impl.miss_shader_table->Map(0, &mstRange, (void **)(&byteDest));
|
||||
memcpy(byteDest, missShaderId, size);
|
||||
pipeline->impl.miss_shader_table->Unmap(0, NULL);
|
||||
}
|
||||
|
||||
// Hit group shader table
|
||||
{
|
||||
UINT size = shaderIdSize;
|
||||
UINT shaderRecordSize = (size + (align - 1)) & ~(align - 1);
|
||||
D3D12_RESOURCE_DESC bufferDesc;
|
||||
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
|
||||
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufferDesc.Width = shaderRecordSize;
|
||||
bufferDesc.Height = 1;
|
||||
bufferDesc.DepthOrArraySize = 1;
|
||||
bufferDesc.MipLevels = 1;
|
||||
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufferDesc.SampleDesc.Count = 1;
|
||||
bufferDesc.SampleDesc.Quality = 0;
|
||||
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
D3D12_HEAP_PROPERTIES uploadHeapProperties;
|
||||
ZeroMemory(&uploadHeapProperties, sizeof(uploadHeapProperties));
|
||||
uploadHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
uploadHeapProperties.CreationNodeMask = 1;
|
||||
uploadHeapProperties.VisibleNodeMask = 1;
|
||||
|
||||
device->CreateCommittedResource(&uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&pipeline->impl.hitgroup_shader_table));
|
||||
|
||||
D3D12_RANGE hstRange = {0};
|
||||
hstRange.Begin = 0;
|
||||
hstRange.End = 0;
|
||||
uint8_t *byteDest;
|
||||
pipeline->impl.hitgroup_shader_table->Map(0, &hstRange, (void **)(&byteDest));
|
||||
memcpy(byteDest, hitGroupShaderId, size);
|
||||
pipeline->impl.hitgroup_shader_table->Unmap(0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_raytrace_pipeline_destroy(kinc_raytrace_pipeline_t *pipeline) {
|
||||
pipeline->impl.dxr_state->Release();
|
||||
pipeline->impl.raygen_shader_table->Release();
|
||||
pipeline->impl.miss_shader_table->Release();
|
||||
pipeline->impl.hitgroup_shader_table->Release();
|
||||
}
|
||||
|
||||
void kinc_raytrace_acceleration_structure_init(kinc_raytrace_acceleration_structure_t *accel, kinc_g5_command_list_t *command_list, kinc_g5_vertex_buffer_t *vb,
|
||||
kinc_g5_index_buffer_t *ib) {
|
||||
// Reset the command list for the acceleration structure construction
|
||||
command_list->impl._commandList->Reset(command_list->impl._commandAllocator, NULL);
|
||||
|
||||
D3D12_RAYTRACING_GEOMETRY_DESC geometryDesc = {};
|
||||
geometryDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;
|
||||
geometryDesc.Triangles.IndexBuffer = ib->impl.upload_buffer->GetGPUVirtualAddress();
|
||||
geometryDesc.Triangles.IndexCount = ib->impl.count;
|
||||
geometryDesc.Triangles.IndexFormat = ib->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
||||
geometryDesc.Triangles.Transform3x4 = 0;
|
||||
geometryDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;
|
||||
geometryDesc.Triangles.VertexCount = vb->impl.myCount;
|
||||
geometryDesc.Triangles.VertexBuffer.StartAddress = vb->impl.uploadBuffer->GetGPUVirtualAddress();
|
||||
geometryDesc.Triangles.VertexBuffer.StrideInBytes = vb->impl.uploadBuffer->GetDesc().Width / vb->impl.myCount;
|
||||
geometryDesc.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE;
|
||||
|
||||
// Get required sizes for an acceleration structure
|
||||
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS topLevelInputs = {};
|
||||
topLevelInputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
|
||||
topLevelInputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE;
|
||||
topLevelInputs.NumDescs = 1;
|
||||
topLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
|
||||
|
||||
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO topLevelPrebuildInfo = {0};
|
||||
dxrDevice->GetRaytracingAccelerationStructurePrebuildInfo(&topLevelInputs, &topLevelPrebuildInfo);
|
||||
|
||||
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO bottomLevelPrebuildInfo = {0};
|
||||
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS bottomLevelInputs = topLevelInputs;
|
||||
bottomLevelInputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;
|
||||
bottomLevelInputs.pGeometryDescs = &geometryDesc;
|
||||
bottomLevelInputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE;
|
||||
dxrDevice->GetRaytracingAccelerationStructurePrebuildInfo(&bottomLevelInputs, &bottomLevelPrebuildInfo);
|
||||
|
||||
ID3D12Resource *scratchResource;
|
||||
{
|
||||
UINT64 tlSize = topLevelPrebuildInfo.ScratchDataSizeInBytes;
|
||||
UINT64 blSize = bottomLevelPrebuildInfo.ScratchDataSizeInBytes;
|
||||
D3D12_RESOURCE_DESC bufferDesc;
|
||||
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
|
||||
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufferDesc.Width = tlSize > blSize ? tlSize : blSize;
|
||||
bufferDesc.Height = 1;
|
||||
bufferDesc.DepthOrArraySize = 1;
|
||||
bufferDesc.MipLevels = 1;
|
||||
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufferDesc.SampleDesc.Count = 1;
|
||||
bufferDesc.SampleDesc.Quality = 0;
|
||||
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
bufferDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
D3D12_HEAP_PROPERTIES uploadHeapProperties;
|
||||
ZeroMemory(&uploadHeapProperties, sizeof(uploadHeapProperties));
|
||||
uploadHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
uploadHeapProperties.CreationNodeMask = 1;
|
||||
uploadHeapProperties.VisibleNodeMask = 1;
|
||||
|
||||
device->CreateCommittedResource(&uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&scratchResource));
|
||||
}
|
||||
|
||||
// Allocate resources for acceleration structures
|
||||
// The resources that will contain acceleration structures must be created in the state D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE,
|
||||
// and must have resource flag D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS.
|
||||
{
|
||||
D3D12_RESOURCE_DESC bufferDesc = {};
|
||||
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufferDesc.Width = bottomLevelPrebuildInfo.ResultDataMaxSizeInBytes;
|
||||
bufferDesc.Height = 1;
|
||||
bufferDesc.DepthOrArraySize = 1;
|
||||
bufferDesc.MipLevels = 1;
|
||||
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufferDesc.SampleDesc.Count = 1;
|
||||
bufferDesc.SampleDesc.Quality = 0;
|
||||
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
bufferDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
D3D12_HEAP_PROPERTIES uploadHeapProperties = {};
|
||||
uploadHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
uploadHeapProperties.CreationNodeMask = 1;
|
||||
uploadHeapProperties.VisibleNodeMask = 1;
|
||||
|
||||
device->CreateCommittedResource(&uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&accel->impl.bottom_level_accel));
|
||||
}
|
||||
{
|
||||
D3D12_RESOURCE_DESC bufferDesc = {};
|
||||
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufferDesc.Width = topLevelPrebuildInfo.ResultDataMaxSizeInBytes;
|
||||
bufferDesc.Height = 1;
|
||||
bufferDesc.DepthOrArraySize = 1;
|
||||
bufferDesc.MipLevels = 1;
|
||||
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufferDesc.SampleDesc.Count = 1;
|
||||
bufferDesc.SampleDesc.Quality = 0;
|
||||
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
bufferDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
D3D12_HEAP_PROPERTIES uploadHeapProperties = {};
|
||||
uploadHeapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
uploadHeapProperties.CreationNodeMask = 1;
|
||||
uploadHeapProperties.VisibleNodeMask = 1;
|
||||
|
||||
device->CreateCommittedResource(&uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&accel->impl.top_level_accel));
|
||||
}
|
||||
|
||||
// Create an instance desc for the bottom-level acceleration structure
|
||||
ID3D12Resource *instanceDescs;
|
||||
D3D12_RAYTRACING_INSTANCE_DESC instanceDesc = {0};
|
||||
instanceDesc.Transform[0][0] = instanceDesc.Transform[1][1] = instanceDesc.Transform[2][2] = 1;
|
||||
instanceDesc.InstanceMask = 1;
|
||||
instanceDesc.AccelerationStructure = accel->impl.bottom_level_accel->GetGPUVirtualAddress();
|
||||
|
||||
D3D12_RESOURCE_DESC bufferDesc;
|
||||
ZeroMemory(&bufferDesc, sizeof(bufferDesc));
|
||||
bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
bufferDesc.Width = sizeof(instanceDesc);
|
||||
bufferDesc.Height = 1;
|
||||
bufferDesc.DepthOrArraySize = 1;
|
||||
bufferDesc.MipLevels = 1;
|
||||
bufferDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
bufferDesc.SampleDesc.Count = 1;
|
||||
bufferDesc.SampleDesc.Quality = 0;
|
||||
bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
D3D12_HEAP_PROPERTIES uploadHeapProperties = {};
|
||||
uploadHeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
uploadHeapProperties.CreationNodeMask = 1;
|
||||
uploadHeapProperties.VisibleNodeMask = 1;
|
||||
|
||||
device->CreateCommittedResource(&uploadHeapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&instanceDescs));
|
||||
void *mappedData;
|
||||
instanceDescs->Map(0, NULL, &mappedData);
|
||||
memcpy(mappedData, &instanceDesc, sizeof(instanceDesc));
|
||||
instanceDescs->Unmap(0, NULL);
|
||||
|
||||
// Bottom Level Acceleration Structure desc
|
||||
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC bottomLevelBuildDesc = {0};
|
||||
bottomLevelBuildDesc.Inputs = bottomLevelInputs;
|
||||
bottomLevelBuildDesc.ScratchAccelerationStructureData = scratchResource->GetGPUVirtualAddress();
|
||||
bottomLevelBuildDesc.DestAccelerationStructureData = accel->impl.bottom_level_accel->GetGPUVirtualAddress();
|
||||
|
||||
// Top Level Acceleration Structure desc
|
||||
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC topLevelBuildDesc = bottomLevelBuildDesc;
|
||||
topLevelInputs.InstanceDescs = instanceDescs->GetGPUVirtualAddress();
|
||||
topLevelBuildDesc.Inputs = topLevelInputs;
|
||||
topLevelBuildDesc.DestAccelerationStructureData = accel->impl.top_level_accel->GetGPUVirtualAddress();
|
||||
topLevelBuildDesc.ScratchAccelerationStructureData = scratchResource->GetGPUVirtualAddress();
|
||||
|
||||
// Build acceleration structure
|
||||
dxrCommandList->BuildRaytracingAccelerationStructure(&bottomLevelBuildDesc, 0, NULL);
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV;
|
||||
barrier.UAV.pResource = accel->impl.bottom_level_accel;
|
||||
command_list->impl._commandList->ResourceBarrier(1, &barrier);
|
||||
dxrCommandList->BuildRaytracingAccelerationStructure(&topLevelBuildDesc, 0, NULL);
|
||||
|
||||
kinc_g5_command_list_end(command_list);
|
||||
kinc_g5_command_list_execute(command_list);
|
||||
kinc_g5_command_list_wait_for_execution_to_finish(command_list);
|
||||
kinc_g5_command_list_begin(command_list);
|
||||
}
|
||||
|
||||
void kinc_raytrace_acceleration_structure_destroy(kinc_raytrace_acceleration_structure_t *accel) {
|
||||
accel->impl.bottom_level_accel->Release();
|
||||
accel->impl.top_level_accel->Release();
|
||||
}
|
||||
|
||||
void kinc_raytrace_set_acceleration_structure(kinc_raytrace_acceleration_structure_t *_accel) {
|
||||
accel = _accel;
|
||||
}
|
||||
|
||||
void kinc_raytrace_set_pipeline(kinc_raytrace_pipeline_t *_pipeline) {
|
||||
pipeline = _pipeline;
|
||||
}
|
||||
|
||||
void kinc_raytrace_set_target(kinc_g5_texture_t *_output) {
|
||||
if (_output != output) {
|
||||
output = _output;
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
device->CreateUnorderedAccessView(output->impl.image, NULL, &uavDesc, descriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_raytrace_dispatch_rays(kinc_g5_command_list_t *command_list) {
|
||||
command_list->impl._commandList->SetComputeRootSignature(dxrRootSignature);
|
||||
|
||||
// Bind the heaps, acceleration structure and dispatch rays
|
||||
command_list->impl._commandList->SetDescriptorHeaps(1, &descriptorHeap);
|
||||
command_list->impl._commandList->SetComputeRootDescriptorTable(0, descriptorHeap->GetGPUDescriptorHandleForHeapStart());
|
||||
command_list->impl._commandList->SetComputeRootShaderResourceView(1, accel->impl.top_level_accel->GetGPUVirtualAddress());
|
||||
D3D12_GPU_VIRTUAL_ADDRESS cbGpuAddress = pipeline->_constant_buffer->impl.constant_buffer->GetGPUVirtualAddress();
|
||||
command_list->impl._commandList->SetComputeRootConstantBufferView(2, cbGpuAddress);
|
||||
|
||||
// Since each shader table has only one shader record, the stride is same as the size.
|
||||
D3D12_DISPATCH_RAYS_DESC dispatchDesc = {0};
|
||||
dispatchDesc.HitGroupTable.StartAddress = pipeline->impl.hitgroup_shader_table->GetGPUVirtualAddress();
|
||||
dispatchDesc.HitGroupTable.SizeInBytes = pipeline->impl.hitgroup_shader_table->GetDesc().Width;
|
||||
dispatchDesc.HitGroupTable.StrideInBytes = dispatchDesc.HitGroupTable.SizeInBytes;
|
||||
dispatchDesc.MissShaderTable.StartAddress = pipeline->impl.miss_shader_table->GetGPUVirtualAddress();
|
||||
dispatchDesc.MissShaderTable.SizeInBytes = pipeline->impl.miss_shader_table->GetDesc().Width;
|
||||
dispatchDesc.MissShaderTable.StrideInBytes = dispatchDesc.MissShaderTable.SizeInBytes;
|
||||
dispatchDesc.RayGenerationShaderRecord.StartAddress = pipeline->impl.raygen_shader_table->GetGPUVirtualAddress();
|
||||
dispatchDesc.RayGenerationShaderRecord.SizeInBytes = pipeline->impl.raygen_shader_table->GetDesc().Width;
|
||||
dispatchDesc.Width = output->texWidth;
|
||||
dispatchDesc.Height = output->texHeight;
|
||||
dispatchDesc.Depth = 1;
|
||||
dxrCommandList->SetPipelineState1(pipeline->impl.dxr_state);
|
||||
dxrCommandList->DispatchRays(&dispatchDesc);
|
||||
}
|
||||
|
||||
void kinc_raytrace_copy(kinc_g5_command_list_t *command_list, kinc_g5_render_target_t *target, kinc_g5_texture_t *source) {
|
||||
D3D12_RESOURCE_BARRIER preCopyBarriers[2] = {};
|
||||
preCopyBarriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
preCopyBarriers[0].Transition.pResource = target->impl.renderTarget;
|
||||
preCopyBarriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
preCopyBarriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
preCopyBarriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
preCopyBarriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
preCopyBarriers[1].Transition.pResource = source->impl.image;
|
||||
preCopyBarriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
preCopyBarriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
preCopyBarriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
command_list->impl._commandList->ResourceBarrier(ARRAYSIZE(preCopyBarriers), preCopyBarriers);
|
||||
|
||||
command_list->impl._commandList->CopyResource(target->impl.renderTarget, source->impl.image);
|
||||
|
||||
D3D12_RESOURCE_BARRIER postCopyBarriers[2] = {};
|
||||
postCopyBarriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
postCopyBarriers[0].Transition.pResource = target->impl.renderTarget;
|
||||
postCopyBarriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
postCopyBarriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
postCopyBarriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
postCopyBarriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
postCopyBarriers[1].Transition.pResource = source->impl.image;
|
||||
postCopyBarriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
postCopyBarriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
|
||||
postCopyBarriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
command_list->impl._commandList->ResourceBarrier(ARRAYSIZE(postCopyBarriers), postCopyBarriers);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID3D12StateObject;
|
||||
struct ID3D12Resource;
|
||||
|
||||
typedef struct {
|
||||
struct ID3D12StateObject *dxr_state;
|
||||
struct ID3D12Resource *raygen_shader_table;
|
||||
struct ID3D12Resource *miss_shader_table;
|
||||
struct ID3D12Resource *hitgroup_shader_table;
|
||||
} kinc_raytrace_pipeline_impl_t;
|
||||
|
||||
typedef struct {
|
||||
struct ID3D12Resource *bottom_level_accel;
|
||||
struct ID3D12Resource *top_level_accel;
|
||||
} kinc_raytrace_acceleration_structure_impl_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,287 @@
|
||||
#include "rendertarget.h"
|
||||
|
||||
#include <kinc/graphics5/rendertarget.h>
|
||||
#include <kinc/graphics5/texture.h>
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
|
||||
#ifdef KINC_WINDOWS
|
||||
#include <dxgi1_4.h>
|
||||
#endif
|
||||
|
||||
#ifdef KINC_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 KINC_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;
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
|
||||
heapDesc.NumDescriptors = 1;
|
||||
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
kinc_microsoft_affirm(device->CreateDescriptorHeap(&heapDesc, IID_GRAPHICS_PPV_ARGS(&render_target->impl.renderTargetDescriptorHeap)));
|
||||
|
||||
if (framebuffer_index >= 0) {
|
||||
#ifdef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
|
||||
render_target->impl.renderTarget = swapChainRenderTargets[framebuffer_index];
|
||||
#else
|
||||
IDXGISwapChain *swapChain = kinc_dx_current_window()->swapChain;
|
||||
kinc_microsoft_affirm(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);
|
||||
}
|
||||
else {
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
kinc_microsoft_affirm(device->CreateDescriptorHeap(&descriptorHeapDesc, IID_GRAPHICS_PPV_ARGS(&render_target->impl.srvDescriptorHeap)));
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
|
||||
ZeroMemory(&shaderResourceViewDesc, sizeof(shaderResourceViewDesc));
|
||||
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;
|
||||
kinc_microsoft_affirm(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;
|
||||
kinc_microsoft_affirm(device->CreateDescriptorHeap(&srvDepthHeapDesc, IID_GRAPHICS_PPV_ARGS(&render_target->impl.srvDepthDescriptorHeap)));
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDepthViewDesc;
|
||||
ZeroMemory(&srvDepthViewDesc, sizeof(srvDepthViewDesc));
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "d3d12mini.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum RenderTargetResourceState { RenderTargetResourceStateUndefined, RenderTargetResourceStateRenderTarget, RenderTargetResourceStateTexture };
|
||||
|
||||
typedef struct {
|
||||
struct ID3D12Resource *renderTarget;
|
||||
struct ID3D12Resource *renderTargetReadback;
|
||||
struct ID3D12DescriptorHeap *renderTargetDescriptorHeap;
|
||||
struct ID3D12DescriptorHeap *srvDescriptorHeap;
|
||||
struct ID3D12DescriptorHeap *depthStencilDescriptorHeap;
|
||||
struct ID3D12DescriptorHeap *srvDepthDescriptorHeap;
|
||||
struct ID3D12Resource *depthStencilTexture;
|
||||
struct D3D12Viewport viewport;
|
||||
struct D3D12Rect scissor;
|
||||
int stage;
|
||||
int stage_depth;
|
||||
int framebuffer_index;
|
||||
} RenderTarget5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,145 @@
|
||||
#include <kinc/graphics5/sampler.h>
|
||||
|
||||
static D3D12_TEXTURE_ADDRESS_MODE convert_texture_addressing(kinc_g5_texture_addressing_t addressing) {
|
||||
switch (addressing) {
|
||||
case KINC_G5_TEXTURE_ADDRESSING_REPEAT:
|
||||
return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_MIRROR:
|
||||
return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_CLAMP:
|
||||
return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_BORDER:
|
||||
return D3D12_TEXTURE_ADDRESS_MODE_BORDER;
|
||||
default:
|
||||
assert(false);
|
||||
return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
}
|
||||
}
|
||||
|
||||
static D3D12_FILTER convert_filter(kinc_g5_texture_filter_t minification, kinc_g5_texture_filter_t magnification, kinc_g5_mipmap_filter_t mipmap) {
|
||||
switch (minification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
switch (magnification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
switch (mipmap) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_LINEAR:
|
||||
switch (mipmap) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_ANISOTROPIC:
|
||||
return D3D12_FILTER_ANISOTROPIC;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_LINEAR:
|
||||
switch (magnification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
switch (mipmap) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_LINEAR:
|
||||
switch (mipmap) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_ANISOTROPIC:
|
||||
return D3D12_FILTER_ANISOTROPIC;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_ANISOTROPIC:
|
||||
return D3D12_FILTER_ANISOTROPIC;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
}
|
||||
|
||||
static D3D12_FILTER convert_comparison_filter(kinc_g5_texture_filter_t minification, kinc_g5_texture_filter_t magnification, kinc_g5_mipmap_filter_t mipmap) {
|
||||
switch (minification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
switch (magnification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
switch (mipmap) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return D3D12_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_LINEAR:
|
||||
switch (mipmap) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return D3D12_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return D3D12_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_ANISOTROPIC:
|
||||
return D3D12_FILTER_COMPARISON_ANISOTROPIC;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_LINEAR:
|
||||
switch (magnification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
switch (mipmap) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_LINEAR:
|
||||
switch (mipmap) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_ANISOTROPIC:
|
||||
return D3D12_FILTER_COMPARISON_ANISOTROPIC;
|
||||
}
|
||||
case KINC_G5_TEXTURE_FILTER_ANISOTROPIC:
|
||||
return D3D12_FILTER_COMPARISON_ANISOTROPIC;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
|
||||
}
|
||||
|
||||
void kinc_g5_sampler_init(kinc_g5_sampler_t *sampler, const kinc_g5_sampler_options_t *options) {
|
||||
D3D12_DESCRIPTOR_HEAP_DESC descHeapSampler = {};
|
||||
descHeapSampler.NumDescriptors = 2;
|
||||
descHeapSampler.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
||||
descHeapSampler.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
device->CreateDescriptorHeap(&descHeapSampler, IID_GRAPHICS_PPV_ARGS(&sampler->impl.sampler_heap));
|
||||
|
||||
D3D12_SAMPLER_DESC samplerDesc;
|
||||
ZeroMemory(&samplerDesc, sizeof(D3D12_SAMPLER_DESC));
|
||||
samplerDesc.Filter = options->is_comparison ? convert_comparison_filter(options->minification_filter, options->magnification_filter, options->mipmap_filter)
|
||||
: convert_filter(options->minification_filter, options->magnification_filter, options->mipmap_filter);
|
||||
samplerDesc.AddressU = convert_texture_addressing(options->u_addressing);
|
||||
samplerDesc.AddressV = convert_texture_addressing(options->v_addressing);
|
||||
samplerDesc.AddressW = convert_texture_addressing(options->w_addressing);
|
||||
samplerDesc.MinLOD = options->lod_min_clamp;
|
||||
samplerDesc.MaxLOD = options->lod_max_clamp;
|
||||
samplerDesc.MipLODBias = 0.0f;
|
||||
samplerDesc.MaxAnisotropy = options->max_anisotropy;
|
||||
samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
device->CreateSampler(&samplerDesc, sampler->impl.sampler_heap->GetCPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
|
||||
void kinc_g5_sampler_destroy(kinc_g5_sampler_t *sampler) {}
|
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
struct ID3D12DescriptorHeap;
|
||||
|
||||
typedef struct kinc_g5_sampler_impl {
|
||||
struct ID3D12DescriptorHeap *sampler_heap;
|
||||
} kinc_g5_sampler_impl_t;
|
@ -0,0 +1,89 @@
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
#include <kinc/graphics5/shader.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
void kinc_g5_shader_init(kinc_g5_shader_t *shader, const void *_data, size_t length, kinc_g5_shader_type_t type) {
|
||||
memset(shader->impl.constants, 0, sizeof(shader->impl.constants));
|
||||
memset(shader->impl.attributes, 0, sizeof(shader->impl.attributes));
|
||||
memset(shader->impl.textures, 0, sizeof(shader->impl.textures));
|
||||
|
||||
unsigned index = 0;
|
||||
uint8_t *data = (uint8_t *)_data;
|
||||
|
||||
#ifndef KINC_KONG
|
||||
int attributesCount = data[index++];
|
||||
for (int i = 0; i < attributesCount; ++i) {
|
||||
char name[64];
|
||||
for (unsigned i2 = 0; i2 < 63; ++i2) {
|
||||
name[i2] = data[index++];
|
||||
if (name[i2] == 0)
|
||||
break;
|
||||
}
|
||||
strcpy(shader->impl.attributes[i].name, name);
|
||||
shader->impl.attributes[i].attribute = data[index++];
|
||||
}
|
||||
|
||||
uint8_t texCount = data[index++];
|
||||
for (unsigned i = 0; i < texCount; ++i) {
|
||||
char name[64];
|
||||
for (unsigned i2 = 0; i2 < 63; ++i2) {
|
||||
name[i2] = data[index++];
|
||||
if (name[i2] == 0)
|
||||
break;
|
||||
}
|
||||
strcpy(shader->impl.textures[i].name, name);
|
||||
shader->impl.textures[i].texture = data[index++];
|
||||
}
|
||||
shader->impl.texturesCount = texCount;
|
||||
|
||||
uint8_t constantCount = data[index++];
|
||||
shader->impl.constantsSize = 0;
|
||||
for (unsigned i = 0; i < constantCount; ++i) {
|
||||
char name[64];
|
||||
for (unsigned i2 = 0; i2 < 63; ++i2) {
|
||||
name[i2] = data[index++];
|
||||
if (name[i2] == 0)
|
||||
break;
|
||||
}
|
||||
ShaderConstant constant;
|
||||
memcpy(&constant.offset, &data[index], sizeof(constant.offset));
|
||||
index += 4;
|
||||
memcpy(&constant.size, &data[index], sizeof(constant.size));
|
||||
index += 4;
|
||||
#ifdef KINC_WINDOWS
|
||||
index += 2; // columns and rows
|
||||
#endif
|
||||
strcpy(constant.name, name);
|
||||
shader->impl.constants[i] = constant;
|
||||
shader->impl.constantsSize = constant.offset + constant.size;
|
||||
}
|
||||
#endif
|
||||
|
||||
shader->impl.length = (int)length - index;
|
||||
shader->impl.data = (uint8_t *)malloc(shader->impl.length);
|
||||
memcpy(shader->impl.data, &data[index], shader->impl.length);
|
||||
|
||||
switch (type) {
|
||||
case KINC_G5_SHADER_TYPE_VERTEX:
|
||||
// Microsoft::affirm(device->CreateVertexShader(this->data, this->length, nullptr, (ID3D11VertexShader**)&shader));
|
||||
break;
|
||||
case KINC_G5_SHADER_TYPE_FRAGMENT:
|
||||
// Microsoft::affirm(device->CreatePixelShader(this->data, this->length, nullptr, (ID3D11PixelShader**)&shader));
|
||||
break;
|
||||
case KINC_G5_SHADER_TYPE_GEOMETRY:
|
||||
// Microsoft::affirm(device->CreateGeometryShader(this->data, this->length, nullptr, (ID3D11GeometryShader**)&shader));
|
||||
break;
|
||||
case KINC_G5_SHADER_TYPE_TESSELLATION_CONTROL:
|
||||
// Microsoft::affirm(device->CreateHullShader(this->data, this->length, nullptr, (ID3D11HullShader**)&shader));
|
||||
break;
|
||||
case KINC_G5_SHADER_TYPE_TESSELLATION_EVALUATION:
|
||||
// Microsoft::affirm(device->CreateDomainShader(this->data, this->length, nullptr, (ID3D11DomainShader**)&shader));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_shader_destroy(kinc_g5_shader_t *shader) {
|
||||
free(shader->impl.data);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
} ShaderConstant;
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
int attribute;
|
||||
} ShaderAttribute;
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
int texture;
|
||||
} ShaderTexture;
|
||||
|
||||
typedef struct {
|
||||
ShaderConstant constants[32];
|
||||
int constantsSize;
|
||||
ShaderAttribute attributes[32];
|
||||
ShaderTexture textures[32];
|
||||
int texturesCount;
|
||||
void *shader;
|
||||
uint8_t *data;
|
||||
int length;
|
||||
} Shader5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,425 @@
|
||||
#include "texture.h"
|
||||
|
||||
#include <kinc/graphics5/rendertarget.h>
|
||||
#include <kinc/graphics5/texture.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static const int heapSize = 1024;
|
||||
|
||||
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
|
||||
/*static int d3d12_textureAlignment() {
|
||||
return D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
|
||||
}*/
|
||||
#else
|
||||
int d3d12_textureAlignment();
|
||||
#endif
|
||||
|
||||
void kinc_g5_internal_reset_textures(struct kinc_g5_command_list *list) {
|
||||
for (int i = 0; i < KINC_INTERNAL_G5_TEXTURE_COUNT; ++i) {
|
||||
list->impl.currentRenderTargets[i] = NULL;
|
||||
list->impl.currentTextures[i] = NULL;
|
||||
list->impl.current_samplers[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline UINT64 GetRequiredIntermediateSize(ID3D12Resource *destinationResource, UINT FirstSubresource, UINT NumSubresources) {
|
||||
D3D12_RESOURCE_DESC desc = destinationResource->GetDesc();
|
||||
UINT64 requiredSize = 0;
|
||||
device->GetCopyableFootprints(&desc, FirstSubresource, NumSubresources, 0, NULL, NULL, NULL, &requiredSize);
|
||||
device->Release();
|
||||
return requiredSize;
|
||||
}
|
||||
|
||||
static DXGI_FORMAT convertImageFormat(kinc_image_format_t format) {
|
||||
switch (format) {
|
||||
case KINC_IMAGE_FORMAT_RGBA128:
|
||||
return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case KINC_IMAGE_FORMAT_RGBA64:
|
||||
return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case KINC_IMAGE_FORMAT_RGB24:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case KINC_IMAGE_FORMAT_A32:
|
||||
return DXGI_FORMAT_R32_FLOAT;
|
||||
case KINC_IMAGE_FORMAT_A16:
|
||||
return DXGI_FORMAT_R16_FLOAT;
|
||||
case KINC_IMAGE_FORMAT_GREY8:
|
||||
return DXGI_FORMAT_R8_UNORM;
|
||||
case KINC_IMAGE_FORMAT_BGRA32:
|
||||
return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
case KINC_IMAGE_FORMAT_RGBA32:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
default:
|
||||
return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
}
|
||||
}
|
||||
|
||||
static int formatByteSize(kinc_image_format_t format) {
|
||||
switch (format) {
|
||||
case KINC_IMAGE_FORMAT_RGBA128:
|
||||
return 16;
|
||||
case KINC_IMAGE_FORMAT_RGBA64:
|
||||
return 8;
|
||||
case KINC_IMAGE_FORMAT_RGB24:
|
||||
return 4;
|
||||
case KINC_IMAGE_FORMAT_A32:
|
||||
return 4;
|
||||
case KINC_IMAGE_FORMAT_A16:
|
||||
return 2;
|
||||
case KINC_IMAGE_FORMAT_GREY8:
|
||||
return 1;
|
||||
case KINC_IMAGE_FORMAT_BGRA32:
|
||||
case KINC_IMAGE_FORMAT_RGBA32:
|
||||
return 4;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_internal_set_textures(kinc_g5_command_list_t *list) {
|
||||
if (list->impl.currentRenderTargets[0] != NULL || list->impl.currentTextures[0] != NULL) {
|
||||
int srvStep = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
int samplerStep = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
|
||||
if (list->impl.heapIndex + KINC_INTERNAL_G5_TEXTURE_COUNT >= heapSize) {
|
||||
list->impl.heapIndex = 0;
|
||||
}
|
||||
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE srvGpu = list->impl.srvHeap->GetGPUDescriptorHandleForHeapStart();
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE samplerGpu = list->impl.samplerHeap->GetGPUDescriptorHandleForHeapStart();
|
||||
srvGpu.ptr += list->impl.heapIndex * srvStep;
|
||||
samplerGpu.ptr += list->impl.heapIndex * samplerStep;
|
||||
|
||||
for (int i = 0; i < KINC_INTERNAL_G5_TEXTURE_COUNT; ++i) {
|
||||
if ((list->impl.currentRenderTargets[i] != NULL || list->impl.currentTextures[i] != NULL) && list->impl.current_samplers[i] != NULL) {
|
||||
ID3D12DescriptorHeap *samplerDescriptorHeap = list->impl.current_samplers[i]->impl.sampler_heap;
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE srvCpu = list->impl.srvHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE samplerCpu = list->impl.samplerHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
srvCpu.ptr += list->impl.heapIndex * srvStep;
|
||||
samplerCpu.ptr += list->impl.heapIndex * samplerStep;
|
||||
++list->impl.heapIndex;
|
||||
|
||||
if (list->impl.currentRenderTargets[i] != NULL) {
|
||||
bool is_depth = list->impl.currentRenderTargets[i]->impl.stage_depth == i;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE sourceCpu =
|
||||
is_depth ? list->impl.currentRenderTargets[i]->impl.srvDepthDescriptorHeap->GetCPUDescriptorHandleForHeapStart()
|
||||
: list->impl.currentRenderTargets[i]->impl.srvDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
device->CopyDescriptorsSimple(1, srvCpu, sourceCpu, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
device->CopyDescriptorsSimple(1, samplerCpu, samplerDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
}
|
||||
else {
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE sourceCpu = list->impl.currentTextures[i]->impl.srvDescriptorHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
device->CopyDescriptorsSimple(1, srvCpu, sourceCpu, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
device->CopyDescriptorsSimple(1, samplerCpu, samplerDescriptorHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ID3D12DescriptorHeap *heaps[2] = {list->impl.srvHeap, list->impl.samplerHeap};
|
||||
list->impl._commandList->SetDescriptorHeaps(2, heaps);
|
||||
if (compute_pipeline_set) {
|
||||
list->impl._commandList->SetComputeRootDescriptorTable(0, srvGpu);
|
||||
list->impl._commandList->SetComputeRootDescriptorTable(1, srvGpu);
|
||||
list->impl._commandList->SetComputeRootDescriptorTable(2, samplerGpu);
|
||||
}
|
||||
else {
|
||||
list->impl._commandList->SetGraphicsRootDescriptorTable(0, srvGpu);
|
||||
list->impl._commandList->SetGraphicsRootDescriptorTable(1, samplerGpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createHeaps(kinc_g5_command_list_t *list) {
|
||||
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
|
||||
heapDesc.NumDescriptors = heapSize;
|
||||
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
device->CreateDescriptorHeap(&heapDesc, IID_GRAPHICS_PPV_ARGS(&list->impl.srvHeap));
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC samplerHeapDesc = {};
|
||||
samplerHeapDesc.NumDescriptors = heapSize;
|
||||
samplerHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
||||
samplerHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
device->CreateDescriptorHeap(&samplerHeapDesc, IID_GRAPHICS_PPV_ARGS(&list->impl.samplerHeap));
|
||||
}
|
||||
|
||||
extern "C" void kinc_memory_emergency();
|
||||
|
||||
void kinc_g5_texture_init_from_image(kinc_g5_texture_t *texture, kinc_image_t *image) {
|
||||
memset(&texture->impl, 0, sizeof(texture->impl));
|
||||
texture->impl.stage = 0;
|
||||
texture->impl.mipmap = true;
|
||||
texture->texWidth = image->width;
|
||||
texture->texHeight = image->height;
|
||||
|
||||
DXGI_FORMAT d3dformat = convertImageFormat(image->format);
|
||||
int formatSize = formatByteSize(image->format);
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapPropertiesDefault;
|
||||
heapPropertiesDefault.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapPropertiesDefault.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapPropertiesDefault.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapPropertiesDefault.CreationNodeMask = 1;
|
||||
heapPropertiesDefault.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC resourceDescTex;
|
||||
resourceDescTex.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
resourceDescTex.Alignment = 0;
|
||||
resourceDescTex.Width = texture->texWidth;
|
||||
resourceDescTex.Height = texture->texHeight;
|
||||
resourceDescTex.DepthOrArraySize = 1;
|
||||
resourceDescTex.MipLevels = 1;
|
||||
resourceDescTex.Format = d3dformat;
|
||||
resourceDescTex.SampleDesc.Count = 1;
|
||||
resourceDescTex.SampleDesc.Quality = 0;
|
||||
resourceDescTex.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
resourceDescTex.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
HRESULT result = device->CreateCommittedResource(&heapPropertiesDefault, D3D12_HEAP_FLAG_NONE, &resourceDescTex, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
NULL, IID_GRAPHICS_PPV_ARGS(&texture->impl.image));
|
||||
if (result != S_OK) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
kinc_memory_emergency();
|
||||
result = device->CreateCommittedResource(&heapPropertiesDefault, D3D12_HEAP_FLAG_NONE, &resourceDescTex, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
NULL, IID_GRAPHICS_PPV_ARGS(&texture->impl.image));
|
||||
if (result == S_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapPropertiesUpload;
|
||||
heapPropertiesUpload.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapPropertiesUpload.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapPropertiesUpload.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapPropertiesUpload.CreationNodeMask = 1;
|
||||
heapPropertiesUpload.VisibleNodeMask = 1;
|
||||
|
||||
const UINT64 uploadBufferSize = GetRequiredIntermediateSize(texture->impl.image, 0, 1);
|
||||
D3D12_RESOURCE_DESC resourceDescBuffer;
|
||||
resourceDescBuffer.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resourceDescBuffer.Alignment = 0;
|
||||
resourceDescBuffer.Width = uploadBufferSize;
|
||||
resourceDescBuffer.Height = 1;
|
||||
resourceDescBuffer.DepthOrArraySize = 1;
|
||||
resourceDescBuffer.MipLevels = 1;
|
||||
resourceDescBuffer.Format = DXGI_FORMAT_UNKNOWN;
|
||||
resourceDescBuffer.SampleDesc.Count = 1;
|
||||
resourceDescBuffer.SampleDesc.Quality = 0;
|
||||
resourceDescBuffer.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
resourceDescBuffer.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
result = device->CreateCommittedResource(&heapPropertiesUpload, D3D12_HEAP_FLAG_NONE, &resourceDescBuffer, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&texture->impl.uploadImage));
|
||||
if (result != S_OK) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
kinc_memory_emergency();
|
||||
result = device->CreateCommittedResource(&heapPropertiesUpload, D3D12_HEAP_FLAG_NONE, &resourceDescBuffer, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&texture->impl.uploadImage));
|
||||
if (result == S_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texture->impl.stride = (int)ceilf(uploadBufferSize / (float)(image->height * d3d12_textureAlignment())) * d3d12_textureAlignment();
|
||||
|
||||
BYTE *pixel;
|
||||
texture->impl.uploadImage->Map(0, NULL, (void **)&pixel);
|
||||
int pitch = kinc_g5_texture_stride(texture);
|
||||
for (int y = 0; y < texture->texHeight; ++y) {
|
||||
memcpy(&pixel[y * pitch], &((uint8_t *)image->data)[y * texture->texWidth * formatSize], texture->texWidth * formatSize);
|
||||
}
|
||||
texture->impl.uploadImage->Unmap(0, NULL);
|
||||
|
||||
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(&texture->impl.srvDescriptorHeap));
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
|
||||
ZeroMemory(&shaderResourceViewDesc, sizeof(shaderResourceViewDesc));
|
||||
shaderResourceViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shaderResourceViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
shaderResourceViewDesc.Format = d3dformat;
|
||||
shaderResourceViewDesc.Texture2D.MipLevels = 1;
|
||||
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
|
||||
shaderResourceViewDesc.Texture2D.ResourceMinLODClamp = 0.0f;
|
||||
|
||||
device->CreateShaderResourceView(texture->impl.image, &shaderResourceViewDesc, texture->impl.srvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
|
||||
void create_texture(struct kinc_g5_texture *texture, int width, int height, kinc_image_format_t format, D3D12_RESOURCE_FLAGS flags) {
|
||||
// kinc_image_init(&texture->image, width, height, format, readable);
|
||||
memset(&texture->impl, 0, sizeof(texture->impl));
|
||||
texture->impl.stage = 0;
|
||||
texture->impl.mipmap = true;
|
||||
texture->texWidth = width;
|
||||
texture->texHeight = height;
|
||||
|
||||
DXGI_FORMAT d3dformat = convertImageFormat(format);
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapPropertiesDefault;
|
||||
heapPropertiesDefault.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapPropertiesDefault.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapPropertiesDefault.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapPropertiesDefault.CreationNodeMask = 1;
|
||||
heapPropertiesDefault.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC resourceDescTex;
|
||||
resourceDescTex.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
resourceDescTex.Alignment = 0;
|
||||
resourceDescTex.Width = texture->texWidth;
|
||||
resourceDescTex.Height = texture->texHeight;
|
||||
resourceDescTex.DepthOrArraySize = 1;
|
||||
resourceDescTex.MipLevels = 1;
|
||||
resourceDescTex.Format = d3dformat;
|
||||
resourceDescTex.SampleDesc.Count = 1;
|
||||
resourceDescTex.SampleDesc.Quality = 0;
|
||||
resourceDescTex.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
resourceDescTex.Flags = flags;
|
||||
|
||||
HRESULT result = device->CreateCommittedResource(&heapPropertiesDefault, D3D12_HEAP_FLAG_NONE, &resourceDescTex, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
NULL, IID_GRAPHICS_PPV_ARGS(&texture->impl.image));
|
||||
if (result != S_OK) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
kinc_memory_emergency();
|
||||
result = device->CreateCommittedResource(&heapPropertiesDefault, D3D12_HEAP_FLAG_NONE, &resourceDescTex, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
NULL, IID_GRAPHICS_PPV_ARGS(&texture->impl.image));
|
||||
if (result == S_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapPropertiesUpload;
|
||||
heapPropertiesUpload.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapPropertiesUpload.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapPropertiesUpload.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapPropertiesUpload.CreationNodeMask = 1;
|
||||
heapPropertiesUpload.VisibleNodeMask = 1;
|
||||
|
||||
const UINT64 uploadBufferSize = GetRequiredIntermediateSize(texture->impl.image, 0, 1);
|
||||
D3D12_RESOURCE_DESC resourceDescBuffer;
|
||||
resourceDescBuffer.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resourceDescBuffer.Alignment = 0;
|
||||
resourceDescBuffer.Width = uploadBufferSize;
|
||||
resourceDescBuffer.Height = 1;
|
||||
resourceDescBuffer.DepthOrArraySize = 1;
|
||||
resourceDescBuffer.MipLevels = 1;
|
||||
resourceDescBuffer.Format = DXGI_FORMAT_UNKNOWN;
|
||||
resourceDescBuffer.SampleDesc.Count = 1;
|
||||
resourceDescBuffer.SampleDesc.Quality = 0;
|
||||
resourceDescBuffer.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
resourceDescBuffer.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
result = device->CreateCommittedResource(&heapPropertiesUpload, D3D12_HEAP_FLAG_NONE, &resourceDescBuffer, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&texture->impl.uploadImage));
|
||||
if (result != S_OK) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
kinc_memory_emergency();
|
||||
result = device->CreateCommittedResource(&heapPropertiesUpload, D3D12_HEAP_FLAG_NONE, &resourceDescBuffer, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&texture->impl.uploadImage));
|
||||
if (result == S_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texture->impl.stride = (int)ceilf(uploadBufferSize / (float)(height * d3d12_textureAlignment())) * d3d12_textureAlignment();
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc;
|
||||
ZeroMemory(&descriptorHeapDesc, sizeof(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(&texture->impl.srvDescriptorHeap));
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc = {};
|
||||
shaderResourceViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
shaderResourceViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
shaderResourceViewDesc.Format = d3dformat;
|
||||
shaderResourceViewDesc.Texture2D.MipLevels = 1;
|
||||
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
|
||||
shaderResourceViewDesc.Texture2D.ResourceMinLODClamp = 0.0f;
|
||||
|
||||
device->CreateShaderResourceView(texture->impl.image, &shaderResourceViewDesc, texture->impl.srvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
|
||||
void kinc_g5_texture_init(struct kinc_g5_texture *texture, int width, int height, kinc_image_format_t format) {
|
||||
create_texture(texture, width, height, format, D3D12_RESOURCE_FLAG_NONE);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_init3d(kinc_g5_texture_t *texture, int width, int height, int depth, kinc_image_format_t format) {
|
||||
// kinc_image_init3d(&texture->image, width, height, depth, format, readable);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_init_non_sampled_access(struct kinc_g5_texture *texture, int width, int height, kinc_image_format_t format) {
|
||||
create_texture(texture, width, height, format, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_destroy(struct kinc_g5_texture *texture) {
|
||||
texture->impl.image->Release();
|
||||
texture->impl.uploadImage->Release();
|
||||
texture->impl.srvDescriptorHeap->Release();
|
||||
}
|
||||
|
||||
void kinc_g5_internal_texture_unmipmap(struct kinc_g5_texture *texture) {
|
||||
texture->impl.mipmap = false;
|
||||
}
|
||||
|
||||
void kinc_g5_internal_texture_set(kinc_g5_command_list_t *list, struct kinc_g5_texture *texture, int unit) {
|
||||
if (unit < 0)
|
||||
return;
|
||||
// context->PSSetShaderResources(unit.unit, 1, &view);
|
||||
texture->impl.stage = unit;
|
||||
list->impl.currentTextures[texture->impl.stage] = texture;
|
||||
list->impl.currentRenderTargets[texture->impl.stage] = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_internal_sampler_set(kinc_g5_command_list_t *list, kinc_g5_sampler_t *sampler, int unit) {
|
||||
if (unit < 0)
|
||||
return;
|
||||
|
||||
list->impl.current_samplers[unit] = sampler;
|
||||
}
|
||||
|
||||
uint8_t *kinc_g5_texture_lock(struct kinc_g5_texture *texture) {
|
||||
BYTE *pixel;
|
||||
texture->impl.uploadImage->Map(0, NULL, (void **)&pixel);
|
||||
return pixel;
|
||||
}
|
||||
|
||||
void kinc_g5_texture_unlock(struct kinc_g5_texture *texture) {
|
||||
texture->impl.uploadImage->Unmap(0, NULL);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_clear(kinc_g5_texture_t *texture, int x, int y, int z, int width, int height, int depth, unsigned color) {}
|
||||
|
||||
int kinc_g5_texture_stride(struct kinc_g5_texture *texture) {
|
||||
/*int baseStride = texture->format == KINC_IMAGE_FORMAT_RGBA32 ? (texture->texWidth * 4) : texture->texWidth;
|
||||
if (texture->format == KINC_IMAGE_FORMAT_GREY8) return texture->texWidth; // please investigate further
|
||||
for (int i = 0;; ++i) {
|
||||
if (d3d12_textureAlignment() * i >= baseStride) {
|
||||
return d3d12_textureAlignment() * i;
|
||||
}
|
||||
}*/
|
||||
return texture->impl.stride;
|
||||
}
|
||||
|
||||
void kinc_g5_texture_generate_mipmaps(struct kinc_g5_texture *texture, int levels) {}
|
||||
|
||||
void kinc_g5_texture_set_mipmap(struct kinc_g5_texture *texture, kinc_image_t *mipmap, int level) {}
|
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID3D12Resource;
|
||||
struct ID3D12DescriptorHeap;
|
||||
struct ID3D12GraphicsCommandList;
|
||||
|
||||
typedef struct {
|
||||
int unit;
|
||||
} TextureUnit5Impl;
|
||||
|
||||
typedef struct {
|
||||
bool mipmap;
|
||||
int stage;
|
||||
int stride;
|
||||
struct ID3D12Resource *image;
|
||||
struct ID3D12Resource *uploadImage;
|
||||
struct ID3D12DescriptorHeap *srvDescriptorHeap;
|
||||
} Texture5Impl;
|
||||
|
||||
struct kinc_g5_texture;
|
||||
struct kinc_g5_command_list;
|
||||
|
||||
void kinc_g5_internal_set_textures(struct kinc_g5_command_list *commandList);
|
||||
void kinc_g5_internal_texture_set(struct kinc_g5_command_list *commandList, struct kinc_g5_texture *texture, int unit);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,123 @@
|
||||
#include "vertexbuffer.h"
|
||||
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
|
||||
#include <kinc/backend/SystemMicrosoft.h>
|
||||
#include <kinc/graphics4/graphics.h>
|
||||
|
||||
kinc_g5_vertex_buffer_t *_current_vertex_buffer = NULL;
|
||||
|
||||
void kinc_g5_vertex_buffer_init(kinc_g5_vertex_buffer_t *buffer, int count, kinc_g5_vertex_structure_t *structure, bool gpuMemory, int instanceDataStepRate) {
|
||||
buffer->impl.myCount = count;
|
||||
|
||||
// static_assert(sizeof(D3D12VertexBufferView) == sizeof(D3D12_VERTEX_BUFFER_VIEW), "Something is wrong with D3D12IVertexBufferView");
|
||||
|
||||
buffer->impl.myStride = 0;
|
||||
for (int i = 0; i < structure->size; ++i) {
|
||||
buffer->impl.myStride += kinc_g4_vertex_data_size(structure->elements[i].data);
|
||||
}
|
||||
|
||||
int uploadBufferSize = buffer->impl.myStride * buffer->impl.myCount;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProperties;
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProperties.CreationNodeMask = 1;
|
||||
heapProperties.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC resourceDesc;
|
||||
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
resourceDesc.Alignment = 0;
|
||||
resourceDesc.Width = uploadBufferSize;
|
||||
resourceDesc.Height = 1;
|
||||
resourceDesc.DepthOrArraySize = 1;
|
||||
resourceDesc.MipLevels = 1;
|
||||
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
resourceDesc.SampleDesc.Count = 1;
|
||||
resourceDesc.SampleDesc.Quality = 0;
|
||||
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL,
|
||||
IID_GRAPHICS_PPV_ARGS(&buffer->impl.uploadBuffer));
|
||||
|
||||
// device_->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES (D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE,
|
||||
// &CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),
|
||||
// D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&vertexBuffer));
|
||||
|
||||
buffer->impl.view.BufferLocation = buffer->impl.uploadBuffer->GetGPUVirtualAddress();
|
||||
buffer->impl.view.SizeInBytes = uploadBufferSize;
|
||||
buffer->impl.view.StrideInBytes = buffer->impl.myStride;
|
||||
|
||||
buffer->impl.lastStart = 0;
|
||||
buffer->impl.lastCount = kinc_g5_vertex_buffer_count(buffer);
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_destroy(kinc_g5_vertex_buffer_t *buffer) {
|
||||
// buffer->impl.vertexBuffer->Release();
|
||||
buffer->impl.uploadBuffer->Release();
|
||||
}
|
||||
|
||||
float *kinc_g5_vertex_buffer_lock_all(kinc_g5_vertex_buffer_t *buffer) {
|
||||
return kinc_g5_vertex_buffer_lock(buffer, 0, kinc_g5_vertex_buffer_count(buffer));
|
||||
}
|
||||
|
||||
float *kinc_g5_vertex_buffer_lock(kinc_g5_vertex_buffer_t *buffer, int start, int count) {
|
||||
buffer->impl.lastStart = start;
|
||||
buffer->impl.lastCount = count;
|
||||
|
||||
D3D12_RANGE range;
|
||||
range.Begin = start * buffer->impl.myStride;
|
||||
range.End = (start + count) * buffer->impl.myStride;
|
||||
|
||||
void *p;
|
||||
buffer->impl.uploadBuffer->Map(0, &range, &p);
|
||||
byte *bytes = (byte *)p;
|
||||
bytes += start * buffer->impl.myStride;
|
||||
return (float *)bytes;
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_unlock_all(kinc_g5_vertex_buffer_t *buffer) {
|
||||
D3D12_RANGE range;
|
||||
range.Begin = buffer->impl.lastStart * buffer->impl.myStride;
|
||||
range.End = (buffer->impl.lastStart + buffer->impl.lastCount) * buffer->impl.myStride;
|
||||
buffer->impl.uploadBuffer->Unmap(0, &range);
|
||||
|
||||
// view.BufferLocation = uploadBuffer->GetGPUVirtualAddress() + myStart * myStride;
|
||||
|
||||
// commandList->CopyBufferRegion(vertexBuffer, 0, uploadBuffer, 0, count() * stride());
|
||||
// CD3DX12_RESOURCE_BARRIER barriers[1] = { CD3DX12_RESOURCE_BARRIER::Transition(vertexBuffer, D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
// D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) };
|
||||
// commandList->ResourceBarrier(1, barriers);
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_unlock(kinc_g5_vertex_buffer_t *buffer, int count) {
|
||||
D3D12_RANGE range;
|
||||
range.Begin = buffer->impl.lastStart * buffer->impl.myStride;
|
||||
range.End = (buffer->impl.lastStart + count) * buffer->impl.myStride;
|
||||
buffer->impl.uploadBuffer->Unmap(0, &range);
|
||||
|
||||
// view.BufferLocation = uploadBuffer->GetGPUVirtualAddress() + myStart * myStride;
|
||||
|
||||
// commandList->CopyBufferRegion(vertexBuffer, 0, uploadBuffer, 0, count() * stride());
|
||||
// CD3DX12_RESOURCE_BARRIER barriers[1] = { CD3DX12_RESOURCE_BARRIER::Transition(vertexBuffer, D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
// D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER) };
|
||||
// commandList->ResourceBarrier(1, barriers);
|
||||
}
|
||||
|
||||
int kinc_g5_internal_vertex_buffer_set(kinc_g5_vertex_buffer_t *buffer, int offset) {
|
||||
// UINT stride = myStride;
|
||||
// UINT offset = 0;
|
||||
// context->IASetVertexBuffers(0, 1, &vb, &stride, &offset);
|
||||
_current_vertex_buffer = buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kinc_g5_vertex_buffer_count(kinc_g5_vertex_buffer_t *buffer) {
|
||||
return buffer->impl.myCount;
|
||||
}
|
||||
|
||||
int kinc_g5_vertex_buffer_stride(kinc_g5_vertex_buffer_t *buffer) {
|
||||
return buffer->impl.myStride;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID3D12Resource;
|
||||
|
||||
struct D3D12VertexBufferView {
|
||||
__int64 BufferLocation;
|
||||
unsigned int SizeInBytes;
|
||||
unsigned int StrideInBytes;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// ID3D12Resource* vertexBuffer;
|
||||
struct ID3D12Resource *uploadBuffer;
|
||||
struct D3D12VertexBufferView view;
|
||||
|
||||
int myCount;
|
||||
int myStride;
|
||||
int lastStart;
|
||||
int lastCount;
|
||||
// float* vertices;
|
||||
// static VertexBuffer5Impl* _current;
|
||||
} VertexBuffer5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,67 @@
|
||||
#include <kinc/graphics4/graphics.h>
|
||||
#include <kinc/graphics4/rendertarget.h>
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
// extern kinc_g5_pipeline_t *currentProgram;
|
||||
|
||||
void kinc_g5_internal_destroy_window(int window) {
|
||||
kinc_g4_internal_destroy_window(window);
|
||||
}
|
||||
|
||||
void kinc_g5_internal_destroy() {
|
||||
kinc_g4_internal_destroy();
|
||||
}
|
||||
|
||||
void kinc_g5_internal_init() {
|
||||
kinc_g4_internal_init();
|
||||
}
|
||||
|
||||
void kinc_g5_internal_init_window(int window, int depthBufferBits, int stencilBufferBits, bool vsync) {
|
||||
kinc_g4_internal_init_window(window, depthBufferBits, stencilBufferBits, vsync);
|
||||
}
|
||||
|
||||
// void kinc_g5_draw_indexed_vertices_instanced(int instanceCount) {}
|
||||
|
||||
// void kinc_g5_draw_indexed_vertices_instanced_from_to(int instanceCount, int start, int count) {}
|
||||
|
||||
// void kinc_g5_draw_indexed_vertices_instanced_from_to_from(int instanceCount, int start, int count, int vertex_offset) {}
|
||||
|
||||
void kinc_g5_begin(kinc_g5_render_target_t *renderTarget, int window) {}
|
||||
|
||||
void kinc_g5_end(int window) {}
|
||||
|
||||
bool kinc_g5_swap_buffers() {
|
||||
return kinc_g4_swap_buffers();
|
||||
}
|
||||
|
||||
void kinc_g5_flush() {}
|
||||
|
||||
int kinc_g5_max_bound_textures(void) {
|
||||
return kinc_g4_max_bound_textures();
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_raytracing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_instanced_rendering() {
|
||||
return kinc_g4_supports_instanced_rendering();
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_compute_shaders() {
|
||||
return kinc_g4_supports_compute_shaders();
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_blend_constants() {
|
||||
return kinc_g4_supports_blend_constants();
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_non_pow2_textures() {
|
||||
return kinc_g4_supports_non_pow2_textures();
|
||||
}
|
||||
|
||||
bool kinc_g5_render_targets_inverted_y() {
|
||||
return kinc_g4_render_targets_inverted_y();
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/math/matrix.h>
|
@ -0,0 +1,402 @@
|
||||
#include <kinc/graphics4/graphics.h>
|
||||
#include <kinc/graphics5/commandlist.h>
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
|
||||
#include <kinc/log.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef KINC_MICROSOFT
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#define WRITE(type, value) \
|
||||
if (list->impl.commandIndex + sizeof(type) > KINC_G5ONG4_COMMANDS_SIZE) { \
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Trying to write too many commands to the command list."); \
|
||||
return; \
|
||||
} \
|
||||
*(type *)(&list->impl.commands[list->impl.commandIndex]) = value; \
|
||||
list->impl.commandIndex += sizeof(type);
|
||||
#define READ(type, var) \
|
||||
if (index + sizeof(type) > KINC_G5ONG4_COMMANDS_SIZE) { \
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Trying to read beyond the end of the command list?"); \
|
||||
return; \
|
||||
} \
|
||||
type var = *(type *)(&list->impl.commands[index]); \
|
||||
index += sizeof(type);
|
||||
|
||||
typedef enum command {
|
||||
Clear,
|
||||
Draw,
|
||||
SetViewport,
|
||||
SetScissor,
|
||||
SetPipeline,
|
||||
SetVertexBuffers,
|
||||
SetIndexBuffer,
|
||||
SetRenderTargets,
|
||||
SetRenderTargetFace,
|
||||
DrawInstanced,
|
||||
SetSampler,
|
||||
SetTexture,
|
||||
SetImageTexture,
|
||||
SetTextureFromRenderTarget,
|
||||
SetTextureFromRenderTargetDepth,
|
||||
SetVertexConstantBuffer,
|
||||
SetFragmentConstantBuffer,
|
||||
SetBlendConstant,
|
||||
} command_t;
|
||||
|
||||
void kinc_g4_pipeline_get_constant_locations(kinc_g4_pipeline_t *state, kinc_g4_constant_location_t *vertex_locations,
|
||||
kinc_g4_constant_location_t *fragment_locations, int *vertex_sizes, int *fragment_sizes, int *max_vertex,
|
||||
int *max_fragment);
|
||||
|
||||
void kinc_g5_command_list_init(kinc_g5_command_list_t *list) {}
|
||||
|
||||
void kinc_g5_command_list_destroy(kinc_g5_command_list_t *list) {}
|
||||
|
||||
void kinc_g5_command_list_begin(kinc_g5_command_list_t *list) {
|
||||
list->impl.commandIndex = 0;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_end(kinc_g5_command_list_t *list) {}
|
||||
|
||||
void kinc_g5_command_list_clear(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget, unsigned flags, unsigned color, float depth,
|
||||
int stencil) {
|
||||
WRITE(command_t, Clear);
|
||||
WRITE(unsigned, flags);
|
||||
WRITE(unsigned, color);
|
||||
WRITE(float, depth);
|
||||
WRITE(int, stencil);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_render_target_to_framebuffer_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
void kinc_g5_command_list_framebuffer_to_render_target_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
void kinc_g5_command_list_texture_to_render_target_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
void kinc_g5_command_list_render_target_to_texture_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices(kinc_g5_command_list_t *list) {
|
||||
kinc_g5_command_list_draw_indexed_vertices_from_to(list, 0, list->impl._indexCount);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_from_to(kinc_g5_command_list_t *list, int start, int count) {
|
||||
WRITE(command_t, Draw);
|
||||
WRITE(int, start);
|
||||
WRITE(int, count);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_instanced(kinc_g5_command_list_t *list, int instanceCount) {
|
||||
kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(list, instanceCount, 0, list->impl._indexCount);
|
||||
}
|
||||
void kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(kinc_g5_command_list_t *list, int instanceCount, int start, int count) {
|
||||
WRITE(command_t, DrawInstanced);
|
||||
WRITE(int, instanceCount);
|
||||
WRITE(int, start);
|
||||
WRITE(int, count);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_viewport(kinc_g5_command_list_t *list, int x, int y, int width, int height) {
|
||||
WRITE(command_t, SetViewport);
|
||||
WRITE(int, x);
|
||||
WRITE(int, y);
|
||||
WRITE(int, width);
|
||||
WRITE(int, height);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_scissor(kinc_g5_command_list_t *list, int x, int y, int width, int height) {
|
||||
WRITE(command_t, SetScissor);
|
||||
WRITE(int, x);
|
||||
WRITE(int, y);
|
||||
WRITE(int, width);
|
||||
WRITE(int, height);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_disable_scissor(kinc_g5_command_list_t *list) {}
|
||||
|
||||
void kinc_g5_command_list_set_pipeline(kinc_g5_command_list_t *list, struct kinc_g5_pipeline *pipeline) {
|
||||
WRITE(command_t, SetPipeline);
|
||||
WRITE(kinc_g5_pipeline_t *, pipeline);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_blend_constant(kinc_g5_command_list_t *list, float r, float g, float b, float a) {
|
||||
WRITE(command_t, SetBlendConstant);
|
||||
WRITE(float, r);
|
||||
WRITE(float, g);
|
||||
WRITE(float, b);
|
||||
WRITE(float, a);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_vertex_buffers(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer **buffers, int *offsets, int count) {
|
||||
WRITE(command_t, SetVertexBuffers);
|
||||
WRITE(int, count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
WRITE(kinc_g5_vertex_buffer_t *, buffers[i]);
|
||||
if (offsets[i] != 0) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "kinc_g5_command_list_set_vertex_buffers: offsets not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_index_buffer(kinc_g5_command_list_t *list, struct kinc_g5_index_buffer *buffer) {
|
||||
WRITE(command_t, SetIndexBuffer);
|
||||
WRITE(kinc_g5_index_buffer_t *, buffer);
|
||||
list->impl._indexCount = buffer->impl.myCount;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_render_targets(kinc_g5_command_list_t *list, struct kinc_g5_render_target **targets, int count) {
|
||||
WRITE(command_t, SetRenderTargets);
|
||||
WRITE(int, count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
WRITE(kinc_g5_render_target_t *, targets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_upload_index_buffer(kinc_g5_command_list_t *list, struct kinc_g5_index_buffer *buffer) {}
|
||||
void kinc_g5_command_list_upload_vertex_buffer(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer *buffer) {}
|
||||
void kinc_g5_command_list_upload_texture(kinc_g5_command_list_t *list, struct kinc_g5_texture *texture) {}
|
||||
|
||||
void kinc_g5_command_list_set_vertex_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size) {
|
||||
WRITE(command_t, SetVertexConstantBuffer);
|
||||
WRITE(kinc_g5_constant_buffer_t *, buffer);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_fragment_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size) {
|
||||
WRITE(command_t, SetFragmentConstantBuffer);
|
||||
WRITE(kinc_g5_constant_buffer_t *, buffer);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_execute(kinc_g5_command_list_t *list) {
|
||||
kinc_g5_pipeline_t *current_pipeline = NULL;
|
||||
int index = 0;
|
||||
while (index < list->impl.commandIndex) {
|
||||
READ(command_t, command);
|
||||
switch (command) {
|
||||
case Clear: {
|
||||
READ(unsigned, flags);
|
||||
READ(unsigned, color);
|
||||
READ(float, depth);
|
||||
READ(int, stencil);
|
||||
kinc_g4_clear(flags, color, depth, stencil);
|
||||
break;
|
||||
}
|
||||
case Draw: {
|
||||
READ(int, start);
|
||||
READ(int, count);
|
||||
kinc_g4_draw_indexed_vertices_from_to(start, count);
|
||||
break;
|
||||
}
|
||||
case SetViewport: {
|
||||
READ(int, x);
|
||||
READ(int, y);
|
||||
READ(int, width);
|
||||
READ(int, height);
|
||||
kinc_g4_viewport(x, y, width, height);
|
||||
break;
|
||||
}
|
||||
case SetScissor: {
|
||||
READ(int, x);
|
||||
READ(int, y);
|
||||
READ(int, width);
|
||||
READ(int, height);
|
||||
kinc_g4_scissor(x, y, width, height);
|
||||
break;
|
||||
}
|
||||
case SetPipeline: {
|
||||
READ(kinc_g5_pipeline_t *, pipeline);
|
||||
current_pipeline = pipeline;
|
||||
kinc_g4_set_pipeline(&pipeline->impl.pipe);
|
||||
break;
|
||||
}
|
||||
case SetVertexBuffers: {
|
||||
READ(int, count);
|
||||
#ifdef KINC_MICROSOFT
|
||||
kinc_g4_vertex_buffer_t **buffers = (kinc_g4_vertex_buffer_t **)alloca(sizeof(kinc_g4_vertex_buffer_t *) * count);
|
||||
#else
|
||||
kinc_g4_vertex_buffer_t *buffers[count];
|
||||
#endif
|
||||
for (int i = 0; i < count; ++i) {
|
||||
READ(kinc_g5_vertex_buffer_t *, buffer);
|
||||
buffers[i] = &buffer->impl.buffer;
|
||||
}
|
||||
kinc_g4_set_vertex_buffers(buffers, count);
|
||||
break;
|
||||
}
|
||||
case SetIndexBuffer: {
|
||||
READ(kinc_g5_index_buffer_t *, buffer);
|
||||
kinc_g4_set_index_buffer(&buffer->impl.buffer);
|
||||
break;
|
||||
}
|
||||
case SetRenderTargets: {
|
||||
READ(int, count);
|
||||
#ifdef KINC_MICROSOFT
|
||||
kinc_g4_render_target_t **buffers = (kinc_g4_render_target_t **)alloca(sizeof(kinc_g4_render_target_t *) * count);
|
||||
#else
|
||||
kinc_g4_render_target_t *buffers[count];
|
||||
#endif
|
||||
int first_framebuffer_index = -1;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
READ(kinc_g5_render_target_t *, buffer);
|
||||
if (i == 0) {
|
||||
first_framebuffer_index = buffer->framebuffer_index;
|
||||
}
|
||||
buffers[i] = &buffer->impl.target;
|
||||
}
|
||||
if (first_framebuffer_index >= 0) {
|
||||
if (count > 1) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Rendering to backbuffer and render targets at the same time is not supported");
|
||||
}
|
||||
kinc_g4_restore_render_target();
|
||||
}
|
||||
else {
|
||||
kinc_g4_set_render_targets(buffers, count);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SetRenderTargetFace: {
|
||||
READ(kinc_g5_render_target_t *, target);
|
||||
READ(int, face);
|
||||
kinc_g4_set_render_target_face(&target->impl.target, face);
|
||||
break;
|
||||
}
|
||||
case DrawInstanced: {
|
||||
READ(int, instanceCount);
|
||||
READ(int, start);
|
||||
READ(int, count);
|
||||
kinc_g4_draw_indexed_vertices_instanced_from_to(instanceCount, start, count);
|
||||
break;
|
||||
}
|
||||
case SetSampler: {
|
||||
assert(false);
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
case SetTexture: {
|
||||
READ(kinc_g5_texture_unit_t, unit);
|
||||
READ(kinc_g5_texture_t *, texture);
|
||||
assert(KINC_G4_SHADER_TYPE_COUNT == KINC_G5_SHADER_TYPE_COUNT);
|
||||
kinc_g4_texture_unit_t g4_unit;
|
||||
memcpy(&g4_unit.stages[0], &unit.stages[0], KINC_G4_SHADER_TYPE_COUNT * sizeof(int));
|
||||
#ifdef KINC_KONG
|
||||
kinc_g4_set_texture(g4_unit.stages[0], &texture->impl.texture);
|
||||
#else
|
||||
kinc_g4_set_texture(g4_unit, &texture->impl.texture);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case SetImageTexture: {
|
||||
READ(kinc_g5_texture_unit_t, unit);
|
||||
READ(kinc_g5_texture_t *, texture);
|
||||
assert(KINC_G4_SHADER_TYPE_COUNT == KINC_G5_SHADER_TYPE_COUNT);
|
||||
kinc_g4_texture_unit_t g4_unit;
|
||||
memcpy(&g4_unit.stages[0], &unit.stages[0], KINC_G4_SHADER_TYPE_COUNT * sizeof(int));
|
||||
kinc_g4_set_image_texture(g4_unit, &texture->impl.texture);
|
||||
break;
|
||||
}
|
||||
case SetTextureFromRenderTarget: {
|
||||
assert(false);
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
case SetTextureFromRenderTargetDepth: {
|
||||
assert(false);
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
case SetVertexConstantBuffer: {
|
||||
READ(kinc_g5_constant_buffer_t *, buffer);
|
||||
(void)buffer;
|
||||
(void)current_pipeline;
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Constant buffers are not supported on G5onG4 at the moment.");
|
||||
// if(current_pipeline == NULL) {
|
||||
// kinc_log(KINC_LOG_LEVEL_ERROR, "Please set the pipeline before setting constant buffers.");
|
||||
// } else {
|
||||
// kinc_g4_constant_location_t *constant_locations = current_pipeline->impl.pipe.vertex_locations;
|
||||
// int *sizes = current_pipeline->impl.pipe.vertex_sizes;
|
||||
// char *data = buffer->data;
|
||||
// for(int i = 0; i < current_pipeline->impl.pipe.vertex_count; ++i) {
|
||||
// // kinc_g4_set
|
||||
// // kinc_g4_set_vertex_constant_buffer(constant_locations[i], sizes[i], data);
|
||||
// data += sizes[i];
|
||||
// }
|
||||
// }
|
||||
break;
|
||||
}
|
||||
case SetFragmentConstantBuffer: {
|
||||
READ(kinc_g5_constant_buffer_t *, buffer);
|
||||
(void)buffer;
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Constant buffers are not supported on G5onG4 at the moment.");
|
||||
break;
|
||||
}
|
||||
case SetBlendConstant: {
|
||||
READ(float, r);
|
||||
READ(float, g);
|
||||
READ(float, b);
|
||||
READ(float, a);
|
||||
kinc_g4_set_blend_constant(r, g, b, a);
|
||||
}
|
||||
default:
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Unknown command %i\n", command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_wait_for_execution_to_finish(kinc_g5_command_list_t *list) {
|
||||
kinc_g4_flush();
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_get_render_target_pixels(kinc_g5_command_list_t *list, struct kinc_g5_render_target *render_target, uint8_t *data) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "kinc_g5_command_list_get_render_target_pixels not implemented");
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_render_target_face(kinc_g5_command_list_t *list, kinc_g5_render_target_t *texture, int face) {
|
||||
WRITE(command_t, SetRenderTargetFace);
|
||||
WRITE(kinc_g5_render_target_t *, texture);
|
||||
WRITE(int, face);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture) {
|
||||
WRITE(command_t, SetTexture);
|
||||
WRITE(kinc_g5_texture_unit_t, unit);
|
||||
WRITE(kinc_g5_texture_t *, texture);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_sampler(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_sampler_t *sampler) {
|
||||
WRITE(command_t, SetSampler);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_texture_from_render_target(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_render_target_t *render_target) {
|
||||
WRITE(command_t, SetTextureFromRenderTarget);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_texture_from_render_target_depth(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit,
|
||||
kinc_g5_render_target_t *render_target) {
|
||||
WRITE(command_t, SetTextureFromRenderTargetDepth);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_image_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture) {
|
||||
WRITE(command_t, SetImageTexture);
|
||||
WRITE(kinc_g5_texture_unit_t, unit);
|
||||
WRITE(kinc_g5_texture_t *, texture);
|
||||
}
|
||||
|
||||
bool kinc_g5_command_list_init_occlusion_query(kinc_g5_command_list_t *list, unsigned *occlusionQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_delete_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery) {}
|
||||
|
||||
void kinc_g5_command_list_render_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery, int triangles) {}
|
||||
|
||||
bool kinc_g5_command_list_are_query_results_available(kinc_g5_command_list_t *list, unsigned occlusionQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_get_query_result(kinc_g5_command_list_t *list, unsigned occlusionQuery, unsigned *pixelCount) {}
|
||||
|
||||
void kinc_g5_command_list_set_compute_shader(kinc_g5_command_list_t *list, struct kinc_g5_compute_shader *shader) {}
|
||||
|
||||
void kinc_g5_command_list_compute(kinc_g5_command_list_t *list, int x, int y, int z) {}
|
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct kinc_g5_pipeline;
|
||||
|
||||
#define KINC_G5ONG4_COMMANDS_SIZE 1024
|
||||
|
||||
typedef struct {
|
||||
struct kinc_g5_pipeline *_currentPipeline;
|
||||
int _indexCount;
|
||||
char commands[KINC_G5ONG4_COMMANDS_SIZE];
|
||||
int commandIndex;
|
||||
bool closed;
|
||||
} CommandList5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,30 @@
|
||||
#include <kinc/graphics5/compute.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void kinc_g5_compute_shader_init(kinc_g5_compute_shader *shader, void *source, int length) {
|
||||
kinc_g4_compute_shader_init(&shader->impl.g4, source, length);
|
||||
}
|
||||
|
||||
void kinc_g5_compute_shader_destroy(kinc_g5_compute_shader *shader) {
|
||||
kinc_g4_compute_shader_destroy(&shader->impl.g4);
|
||||
}
|
||||
|
||||
#ifndef KINC_KONG
|
||||
kinc_g5_constant_location_t kinc_g5_compute_shader_get_constant_location(kinc_g5_compute_shader *shader, const char *name) {
|
||||
kinc_g5_constant_location_t location = {0};
|
||||
location.impl.location = kinc_g4_compute_shader_get_constant_location(&shader->impl.g4, name);
|
||||
return location;
|
||||
}
|
||||
|
||||
kinc_g5_texture_unit_t kinc_g5_compute_shader_get_texture_unit(kinc_g5_compute_shader *shader, const char *name) {
|
||||
kinc_g5_texture_unit_t g5_unit = {0};
|
||||
kinc_g4_texture_unit_t g4_unit = kinc_g4_compute_shader_get_texture_unit(&shader->impl.g4, name);
|
||||
assert(KINC_G4_SHADER_TYPE_COUNT == KINC_G5_SHADER_TYPE_COUNT);
|
||||
for (int i = 0; i < KINC_G4_SHADER_TYPE_COUNT; ++i) {
|
||||
g5_unit.stages[i] = g4_unit.stages[i];
|
||||
}
|
||||
return g5_unit;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics4/compute.h>
|
||||
|
||||
typedef struct kinc_g5_compute_shader_impl {
|
||||
kinc_g4_compute_shader g4;
|
||||
} kinc_g5_compute_shader_impl;
|
@ -0,0 +1,33 @@
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool kinc_g5_transposeMat3 = false;
|
||||
bool kinc_g5_transposeMat4 = false;
|
||||
|
||||
void kinc_g5_constant_buffer_init(kinc_g5_constant_buffer_t *buffer, int size) {
|
||||
buffer->impl.mySize = size;
|
||||
buffer->data = malloc(size);
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_destroy(kinc_g5_constant_buffer_t *buffer) {
|
||||
free(buffer->data);
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_lock_all(kinc_g5_constant_buffer_t *buffer) {}
|
||||
|
||||
void kinc_g5_constant_buffer_lock(kinc_g5_constant_buffer_t *buffer, int start, int count) {}
|
||||
|
||||
void kinc_g5_constant_buffer_unlock(kinc_g5_constant_buffer_t *buffer) {}
|
||||
|
||||
int kinc_g5_constant_buffer_size(kinc_g5_constant_buffer_t *buffer) {
|
||||
return buffer->impl.mySize;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int lastStart;
|
||||
int lastCount;
|
||||
int mySize;
|
||||
} ConstantBuffer5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,10 @@
|
||||
#include "G5onG4.c.h"
|
||||
#include "commandlist.c.h"
|
||||
#include "constantbuffer.c.h"
|
||||
#include "indexbuffer.c.h"
|
||||
#include "pipeline.c.h"
|
||||
#include "rendertarget.c.h"
|
||||
#include "sampler.c.h"
|
||||
#include "shader.c.h"
|
||||
#include "texture.c.h"
|
||||
#include "vertexbuffer.c.h"
|
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/backend/graphics5/indexbuffer.h>
|
||||
#include <kinc/backend/graphics5/rendertarget.h>
|
||||
#include <kinc/backend/graphics5/texture.h>
|
||||
#include <kinc/backend/graphics5/vertexbuffer.h>
|
@ -0,0 +1,34 @@
|
||||
#include "indexbuffer.h"
|
||||
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void kinc_g5_index_buffer_init(kinc_g5_index_buffer_t *buffer, int count, kinc_g5_index_buffer_format_t format, bool gpuMemory) {
|
||||
buffer->impl.myCount = count;
|
||||
kinc_g4_index_buffer_init(&buffer->impl.buffer, count, (kinc_g4_index_buffer_format_t)format, gpuMemory ? KINC_G4_USAGE_STATIC : KINC_G4_USAGE_DYNAMIC);
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_destroy(kinc_g5_index_buffer_t *buffer) {
|
||||
kinc_g4_index_buffer_destroy(&buffer->impl.buffer);
|
||||
}
|
||||
|
||||
void *kinc_g5_index_buffer_lock_all(kinc_g5_index_buffer_t *buffer) {
|
||||
return kinc_g4_index_buffer_lock_all(&buffer->impl.buffer);
|
||||
}
|
||||
|
||||
void *kinc_g5_index_buffer_lock(kinc_g5_index_buffer_t *buffer, int start, int count) {
|
||||
return kinc_g4_index_buffer_lock(&buffer->impl.buffer, start, count);
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_unlock_all(kinc_g5_index_buffer_t *buffer) {
|
||||
kinc_g4_index_buffer_unlock_all(&buffer->impl.buffer);
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_unlock(kinc_g5_index_buffer_t *buffer, int count) {
|
||||
kinc_g4_index_buffer_unlock(&buffer->impl.buffer, count);
|
||||
}
|
||||
|
||||
int kinc_g5_index_buffer_count(kinc_g5_index_buffer_t *buffer) {
|
||||
return buffer->impl.myCount;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics4/indexbuffer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
kinc_g4_index_buffer_t buffer;
|
||||
int myCount;
|
||||
} IndexBuffer5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,65 @@
|
||||
#include <kinc/graphics4/constantlocation.h>
|
||||
#include <kinc/graphics5/constantlocation.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
#include <kinc/system.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void kinc_g4_pipeline_get_constant_locations(kinc_g4_pipeline_t *state, kinc_g4_constant_location_t *vertex_locations,
|
||||
kinc_g4_constant_location_t *fragment_locations, int *vertex_sizes, int *fragment_sizes, int *max_vertex,
|
||||
int *max_fragment);
|
||||
|
||||
void kinc_g5_pipeline_init(kinc_g5_pipeline_t *pipeline) {
|
||||
kinc_g4_pipeline_init(&pipeline->impl.pipe);
|
||||
// int vertex_count = 0;
|
||||
// int fragment_count = 0;
|
||||
// kinc_g4_pipeline_get_constant_locations(&pipeline->impl.pipe, NULL, NULL, NULL, NULL, &vertex_count, &fragment_count);
|
||||
// pipeline->impl.vertex_locations = malloc(vertex_count * sizeof(kinc_g4_constant_location_t));
|
||||
// pipeline->impl.fragment_locations = malloc(fragment_count * sizeof(kinc_g4_constant_location_t));
|
||||
// pipeline->impl.vertex_sizes = malloc(vertex_count * sizeof(int));
|
||||
// pipeline->impl.fragment_sizes = malloc(fragment_count * sizeof(int));
|
||||
// if (pipeline->impl.vertex_locations == NULL || pipeline->impl.fragment_locations == NULL || pipeline->impl.vertex_sizes == NULL ||
|
||||
// pipeline->impl.fragment_sizes == NULL) {
|
||||
// kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to allocate pipeline reflection data.");
|
||||
// kinc_stop();
|
||||
// }
|
||||
// else {
|
||||
// pipeline->impl.vertex_location_count = vertex_count;
|
||||
// pipeline->impl.fragment_location_count = fragment_count;
|
||||
// kinc_g4_pipeline_get_constant_locations(&pipeline->impl.pipe, pipeline->impl.vertex_locations, pipeline->impl.fragment_locations,
|
||||
// pipeline->impl.vertex_sizes, pipeline->impl.fragment_sizes, &vertex_count, &fragment_count);
|
||||
// }
|
||||
}
|
||||
|
||||
void kinc_g5_pipeline_destroy(kinc_g5_pipeline_t *pipe) {
|
||||
kinc_g4_pipeline_destroy(&pipe->impl.pipe);
|
||||
}
|
||||
|
||||
#ifndef KINC_KONG
|
||||
kinc_g5_constant_location_t kinc_g5_pipeline_get_constant_location(kinc_g5_pipeline_t *pipe, const char *name) {
|
||||
kinc_g5_constant_location_t location;
|
||||
location.impl.location = kinc_g4_pipeline_get_constant_location(&pipe->impl.pipe, name);
|
||||
return location;
|
||||
}
|
||||
|
||||
kinc_g5_texture_unit_t kinc_g5_pipeline_get_texture_unit(kinc_g5_pipeline_t *pipe, const char *name) {
|
||||
kinc_g4_texture_unit_t g4_unit = kinc_g4_pipeline_get_texture_unit(&pipe->impl.pipe, name);
|
||||
|
||||
assert(KINC_G4_SHADER_TYPE_COUNT == KINC_G5_SHADER_TYPE_COUNT);
|
||||
kinc_g5_texture_unit_t g5_unit;
|
||||
memcpy(&g5_unit.stages[0], &g4_unit.stages[0], KINC_G5_SHADER_TYPE_COUNT * sizeof(int));
|
||||
|
||||
return g5_unit;
|
||||
}
|
||||
#endif
|
||||
|
||||
void kinc_g5_pipeline_compile(kinc_g5_pipeline_t *pipe) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
pipe->impl.pipe.input_layout[i] = pipe->inputLayout[i];
|
||||
}
|
||||
pipe->impl.pipe.vertex_shader = &pipe->vertexShader->impl.shader;
|
||||
pipe->impl.pipe.fragment_shader = &pipe->fragmentShader->impl.shader;
|
||||
kinc_g4_pipeline_compile(&pipe->impl.pipe);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics4/pipeline.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
kinc_g4_pipeline_t pipe;
|
||||
// int vertex_location_count;
|
||||
// int fragment_location_count;
|
||||
// kinc_g4_constant_location_t *vertex_locations;
|
||||
// kinc_g4_constant_location_t *fragment_locations;
|
||||
// int *vertex_sizes;
|
||||
// int *fragment_sizes;
|
||||
} PipelineState5Impl;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
} ComputePipelineState5Impl;
|
||||
|
||||
typedef struct {
|
||||
kinc_g4_constant_location_t location;
|
||||
} ConstantLocation5Impl;
|
||||
|
||||
typedef struct {
|
||||
int nothing;
|
||||
} AttributeLocation5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,45 @@
|
||||
#include <kinc/graphics4/rendertarget.h>
|
||||
#include <kinc/graphics5/rendertarget.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
void kinc_g5_render_target_init_with_multisampling(kinc_g5_render_target_t *renderTarget, int width, int height, kinc_g5_render_target_format_t format,
|
||||
int depthBufferBits, int stencilBufferBits, int samples_per_pixel) {
|
||||
renderTarget->texWidth = renderTarget->width = width;
|
||||
renderTarget->texHeight = renderTarget->height = height;
|
||||
renderTarget->framebuffer_index = -1;
|
||||
kinc_g4_render_target_init_with_multisampling(&renderTarget->impl.target, width, height, (kinc_g4_render_target_format_t)format, depthBufferBits,
|
||||
stencilBufferBits, samples_per_pixel);
|
||||
}
|
||||
|
||||
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) {
|
||||
target->framebuffer_index = 0;
|
||||
target->width = target->texWidth = width;
|
||||
target->height = target->texHeight = height;
|
||||
}
|
||||
|
||||
void kinc_g5_render_target_init_cube_with_multisampling(kinc_g5_render_target_t *target, int cubeMapSize, kinc_g5_render_target_format_t format,
|
||||
int depthBufferBits, int stencilBufferBits, int samples_per_pixel) {
|
||||
target->texWidth = target->width = cubeMapSize;
|
||||
target->texHeight = target->height = cubeMapSize;
|
||||
target->isCubeMap = true;
|
||||
target->framebuffer_index = -1;
|
||||
kinc_g4_render_target_init_cube_with_multisampling(&target->impl.target, cubeMapSize, (kinc_g4_render_target_format_t)format, depthBufferBits,
|
||||
stencilBufferBits, samples_per_pixel);
|
||||
}
|
||||
|
||||
void kinc_g5_render_target_destroy(kinc_g5_render_target_t *renderTarget) {
|
||||
kinc_g4_render_target_destroy(&renderTarget->impl.target);
|
||||
}
|
||||
|
||||
void kinc_g5_render_target_set_depth_stencil_from(kinc_g5_render_target_t *renderTarget, kinc_g5_render_target_t *source) {
|
||||
kinc_g4_render_target_set_depth_stencil_from(&renderTarget->impl.target, &source->impl.target);
|
||||
}
|
||||
|
||||
// void kinc_g5_render_target_get_pixels(kinc_g5_render_target_t *renderTarget, uint8_t *data) {
|
||||
// kinc_g4_render_target_get_pixels(&renderTarget->impl, data);
|
||||
// }
|
||||
|
||||
// void kinc_g5_render_target_generate_mipmaps(kinc_g5_render_target_t *renderTarget, int levels) {
|
||||
// kinc_g4_render_target_generate_mipmaps(&renderTarget->impl, levels);
|
||||
// }
|
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <kinc/graphics4/rendertarget.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
kinc_g4_render_target_t target;
|
||||
} RenderTarget5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,5 @@
|
||||
#include <kinc/graphics5/sampler.h>
|
||||
|
||||
void kinc_g5_sampler_init(kinc_g5_sampler_t *sampler, const kinc_g5_sampler_options_t *options) {}
|
||||
|
||||
void kinc_g5_sampler_destroy(kinc_g5_sampler_t *sampler) {}
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct kinc_g5_sampler_impl {
|
||||
int a;
|
||||
} kinc_g5_sampler_impl_t;
|
@ -0,0 +1,10 @@
|
||||
#include <kinc/graphics4/shader.h>
|
||||
#include <kinc/graphics5/shader.h>
|
||||
|
||||
void kinc_g5_shader_init(kinc_g5_shader_t *shader, const void *source, size_t length, kinc_g5_shader_type_t type) {
|
||||
kinc_g4_shader_init(&shader->impl.shader, source, length, (kinc_g4_shader_type_t)type);
|
||||
}
|
||||
|
||||
void kinc_g5_shader_destroy(kinc_g5_shader_t *shader) {
|
||||
kinc_g4_shader_destroy(&shader->impl.shader);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics4/shader.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
kinc_g4_shader_t shader;
|
||||
} Shader5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,50 @@
|
||||
#include "texture.h"
|
||||
|
||||
#include <kinc/graphics5/texture.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
void kinc_g5_texture_init(kinc_g5_texture_t *texture, int width, int height, kinc_image_format_t format) {
|
||||
kinc_g4_texture_init(&texture->impl.texture, width, height, format);
|
||||
}
|
||||
void kinc_g5_texture_init3d(kinc_g5_texture_t *texture, int width, int height, int depth, kinc_image_format_t format) {
|
||||
kinc_g4_texture_init3d(&texture->impl.texture, width, height, depth, format);
|
||||
}
|
||||
void kinc_g5_texture_init_from_image(kinc_g5_texture_t *texture, kinc_image_t *image) {
|
||||
kinc_g4_texture_init_from_image(&texture->impl.texture, image);
|
||||
}
|
||||
void kinc_g5_texture_init_from_encoded_data(kinc_g5_texture_t *texture, void *data, int size, const char *format, bool readable) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "kinc_g5_texture_init_from_encoded_data not implemented");
|
||||
}
|
||||
void kinc_g5_texture_init_from_data(kinc_g5_texture_t *texture, void *data, int width, int height, int format, bool readable) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "kinc_g5_texture_init_from_data not implemented");
|
||||
}
|
||||
void kinc_g5_texture_init_non_sampled_access(kinc_g5_texture_t *texture, int width, int height, kinc_image_format_t format) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "kinc_g5_texture_init_non_sampled_access not implemented");
|
||||
}
|
||||
void kinc_g5_texture_destroy(kinc_g5_texture_t *texture) {
|
||||
kinc_g4_texture_destroy(&texture->impl.texture);
|
||||
}
|
||||
|
||||
uint8_t *kinc_g5_texture_lock(kinc_g5_texture_t *texture) {
|
||||
return kinc_g4_texture_lock(&texture->impl.texture);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_unlock(kinc_g5_texture_t *texture) {
|
||||
kinc_g4_texture_unlock(&texture->impl.texture);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_clear(kinc_g5_texture_t *texture, int x, int y, int z, int width, int height, int depth, unsigned color) {
|
||||
kinc_g4_texture_clear(&texture->impl.texture, x, y, z, width, height, depth, color);
|
||||
}
|
||||
|
||||
int kinc_g5_texture_stride(kinc_g5_texture_t *texture) {
|
||||
return kinc_g4_texture_stride(&texture->impl.texture);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_generate_mipmaps(kinc_g5_texture_t *texture, int levels) {
|
||||
kinc_g4_texture_generate_mipmaps(&texture->impl.texture, levels);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_set_mipmap(kinc_g5_texture_t *texture, kinc_image_t *mipmap, int level) {
|
||||
kinc_g4_texture_set_mipmap(&texture->impl.texture, mipmap, level);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics4/texture.h>
|
||||
#include <kinc/graphics4/textureunit.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
kinc_g4_texture_unit_t unit;
|
||||
} TextureUnit5Impl;
|
||||
|
||||
typedef struct {
|
||||
kinc_g4_texture_t texture;
|
||||
} Texture5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,39 @@
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
kinc_g5_vertex_buffer_t *kinc_g5_internal_current_vertex_buffer = NULL;
|
||||
|
||||
void kinc_g5_vertex_buffer_init(kinc_g5_vertex_buffer_t *buffer, int count, kinc_g5_vertex_structure_t *structure, bool gpuMemory, int instanceDataStepRate) {
|
||||
buffer->impl.myCount = count;
|
||||
buffer->impl.myStart = 0;
|
||||
kinc_g4_vertex_buffer_init(&buffer->impl.buffer, count, structure, KINC_G4_USAGE_STATIC, instanceDataStepRate);
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_destroy(kinc_g5_vertex_buffer_t *buffer) {
|
||||
kinc_g4_vertex_buffer_destroy(&buffer->impl.buffer);
|
||||
}
|
||||
|
||||
float *kinc_g5_vertex_buffer_lock_all(kinc_g5_vertex_buffer_t *buffer) {
|
||||
return kinc_g4_vertex_buffer_lock_all(&buffer->impl.buffer);
|
||||
}
|
||||
|
||||
float *kinc_g5_vertex_buffer_lock(kinc_g5_vertex_buffer_t *buffer, int start, int count) {
|
||||
return kinc_g4_vertex_buffer_lock(&buffer->impl.buffer, start, count);
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_unlock_all(kinc_g5_vertex_buffer_t *buffer) {
|
||||
kinc_g4_vertex_buffer_unlock_all(&buffer->impl.buffer);
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_unlock(kinc_g5_vertex_buffer_t *buffer, int count) {
|
||||
kinc_g4_vertex_buffer_unlock(&buffer->impl.buffer, count);
|
||||
}
|
||||
|
||||
int kinc_g5_vertex_buffer_count(kinc_g5_vertex_buffer_t *buffer) {
|
||||
return buffer->impl.myCount;
|
||||
}
|
||||
|
||||
int kinc_g5_vertex_buffer_stride(kinc_g5_vertex_buffer_t *buffer) {
|
||||
return kinc_g4_vertex_buffer_stride(&buffer->impl.buffer);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics4/vertexbuffer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
kinc_g4_vertex_buffer_t buffer;
|
||||
int myCount;
|
||||
int myStart;
|
||||
} VertexBuffer5Impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/image.h>
|
||||
#include <kinc/math/matrix.h>
|
@ -0,0 +1,253 @@
|
||||
#include "Metal.h"
|
||||
|
||||
#include <kinc/color.h>
|
||||
#include <kinc/system.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
#include <kinc/graphics5/commandlist.h>
|
||||
#include <kinc/graphics5/rendertarget.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalKit/MTKView.h>
|
||||
|
||||
id getMetalLayer(void);
|
||||
id getMetalDevice(void);
|
||||
id getMetalQueue(void);
|
||||
|
||||
int renderTargetWidth;
|
||||
int renderTargetHeight;
|
||||
int newRenderTargetWidth;
|
||||
int newRenderTargetHeight;
|
||||
|
||||
id<CAMetalDrawable> drawable;
|
||||
id<MTLTexture> depthTexture;
|
||||
int depthBits;
|
||||
int stencilBits;
|
||||
|
||||
static kinc_g5_render_target_t fallback_render_target;
|
||||
|
||||
id getMetalEncoder(void) {
|
||||
return render_command_encoder;
|
||||
}
|
||||
|
||||
void kinc_g5_internal_destroy_window(int window) {}
|
||||
|
||||
void kinc_g5_internal_destroy(void) {}
|
||||
|
||||
extern void kinc_g4_on_g5_internal_resize(int, int, int);
|
||||
|
||||
void kinc_internal_resize(int window, int width, int height) {
|
||||
kinc_g4_on_g5_internal_resize(window, width, height);
|
||||
}
|
||||
|
||||
void kinc_g5_internal_init(void) {}
|
||||
|
||||
void kinc_g5_internal_init_window(int window, int depthBufferBits, int stencilBufferBits, bool vsync) {
|
||||
depthBits = depthBufferBits;
|
||||
stencilBits = stencilBufferBits;
|
||||
kinc_g5_render_target_init(&fallback_render_target, 32, 32, KINC_G5_RENDER_TARGET_FORMAT_32BIT, 0, 0);
|
||||
}
|
||||
|
||||
void kinc_g5_flush(void) {}
|
||||
|
||||
void kinc_g5_draw_indexed_vertices_instanced(int instanceCount) {}
|
||||
|
||||
void kinc_g5_draw_indexed_vertices_instanced_from_to(int instanceCount, int start, int count) {}
|
||||
|
||||
bool kinc_internal_metal_has_depth = false;
|
||||
|
||||
bool kinc_internal_current_render_target_has_depth(void) {
|
||||
return kinc_internal_metal_has_depth;
|
||||
}
|
||||
|
||||
static void start_render_pass(void) {
|
||||
id<MTLTexture> texture = drawable.texture;
|
||||
MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
renderPassDescriptor.colorAttachments[0].texture = texture;
|
||||
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||
renderPassDescriptor.depthAttachment.clearDepth = 1;
|
||||
renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
|
||||
renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;
|
||||
renderPassDescriptor.depthAttachment.texture = depthTexture;
|
||||
renderPassDescriptor.stencilAttachment.clearStencil = 0;
|
||||
renderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionDontCare;
|
||||
renderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionDontCare;
|
||||
renderPassDescriptor.stencilAttachment.texture = depthTexture;
|
||||
|
||||
render_command_encoder = [command_buffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||
}
|
||||
|
||||
static void end_render_pass(void) {
|
||||
[render_command_encoder endEncoding];
|
||||
render_command_encoder = nil;
|
||||
}
|
||||
|
||||
void kinc_g5_begin(kinc_g5_render_target_t *renderTarget, int window) {
|
||||
CAMetalLayer *metalLayer = getMetalLayer();
|
||||
drawable = [metalLayer nextDrawable];
|
||||
|
||||
if (depthBits > 0 && (depthTexture == nil || depthTexture.width != drawable.texture.width || depthTexture.height != drawable.texture.height)) {
|
||||
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor new];
|
||||
descriptor.textureType = MTLTextureType2D;
|
||||
descriptor.width = drawable.texture.width;
|
||||
descriptor.height = drawable.texture.height;
|
||||
descriptor.depth = 1;
|
||||
descriptor.pixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||
descriptor.arrayLength = 1;
|
||||
descriptor.mipmapLevelCount = 1;
|
||||
descriptor.resourceOptions = MTLResourceStorageModePrivate;
|
||||
descriptor.usage = MTLTextureUsageRenderTarget;
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
depthTexture = [device newTextureWithDescriptor:descriptor];
|
||||
kinc_internal_metal_has_depth = true;
|
||||
}
|
||||
else {
|
||||
kinc_internal_metal_has_depth = false;
|
||||
}
|
||||
|
||||
id<MTLTexture> texture = drawable.texture;
|
||||
MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
renderPassDescriptor.colorAttachments[0].texture = texture;
|
||||
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
||||
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||
renderPassDescriptor.depthAttachment.clearDepth = 1;
|
||||
renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
|
||||
renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;
|
||||
renderPassDescriptor.depthAttachment.texture = depthTexture;
|
||||
renderPassDescriptor.stencilAttachment.clearStencil = 0;
|
||||
renderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionDontCare;
|
||||
renderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionDontCare;
|
||||
renderPassDescriptor.stencilAttachment.texture = depthTexture;
|
||||
|
||||
if (command_buffer != nil && render_command_encoder != nil) {
|
||||
[render_command_encoder endEncoding];
|
||||
[command_buffer commit];
|
||||
}
|
||||
|
||||
id<MTLCommandQueue> commandQueue = getMetalQueue();
|
||||
command_buffer = [commandQueue commandBuffer];
|
||||
render_command_encoder = [command_buffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||
}
|
||||
|
||||
void kinc_g5_end(int window) {}
|
||||
|
||||
bool kinc_g5_swap_buffers(void) {
|
||||
if (command_buffer != nil && render_command_encoder != nil) {
|
||||
[render_command_encoder endEncoding];
|
||||
[command_buffer presentDrawable:drawable];
|
||||
[command_buffer commit];
|
||||
}
|
||||
drawable = nil;
|
||||
command_buffer = nil;
|
||||
render_command_encoder = nil;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_window_vsynced(int window) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void kinc_g5_internal_new_render_pass(kinc_g5_render_target_t **renderTargets, int count, bool wait, unsigned clear_flags, unsigned color, float depth,
|
||||
int stencil) {
|
||||
if (command_buffer != nil && render_command_encoder != nil) {
|
||||
[render_command_encoder endEncoding];
|
||||
[command_buffer commit];
|
||||
if (wait) {
|
||||
[command_buffer waitUntilCompleted];
|
||||
}
|
||||
}
|
||||
|
||||
MTLRenderPassDescriptor *renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (renderTargets == NULL) {
|
||||
if (drawable == nil) {
|
||||
renderPassDescriptor.colorAttachments[i].texture = (__bridge id<MTLTexture>)fallback_render_target.impl._tex;
|
||||
renderPassDescriptor.depthAttachment.texture = nil;
|
||||
renderPassDescriptor.stencilAttachment.texture = nil;
|
||||
kinc_internal_metal_has_depth = false;
|
||||
}
|
||||
else {
|
||||
renderPassDescriptor.colorAttachments[i].texture = drawable.texture;
|
||||
renderPassDescriptor.depthAttachment.texture = depthTexture;
|
||||
renderPassDescriptor.stencilAttachment.texture = depthTexture;
|
||||
kinc_internal_metal_has_depth = depthTexture != nil;
|
||||
}
|
||||
}
|
||||
else {
|
||||
renderPassDescriptor.colorAttachments[i].texture = (__bridge id<MTLTexture>)renderTargets[i]->impl._tex;
|
||||
renderPassDescriptor.depthAttachment.texture = (__bridge id<MTLTexture>)renderTargets[0]->impl._depthTex;
|
||||
renderPassDescriptor.stencilAttachment.texture = (__bridge id<MTLTexture>)renderTargets[0]->impl._depthTex;
|
||||
kinc_internal_metal_has_depth = renderTargets[0]->impl._depthTex != nil;
|
||||
}
|
||||
if (clear_flags & KINC_G5_CLEAR_COLOR) {
|
||||
float red, green, blue, alpha;
|
||||
kinc_color_components(color, &red, &green, &blue, &alpha);
|
||||
renderPassDescriptor.colorAttachments[i].loadAction = MTLLoadActionClear;
|
||||
renderPassDescriptor.colorAttachments[i].storeAction = MTLStoreActionStore;
|
||||
renderPassDescriptor.colorAttachments[i].clearColor = MTLClearColorMake(red, green, blue, alpha);
|
||||
}
|
||||
else {
|
||||
renderPassDescriptor.colorAttachments[i].loadAction = MTLLoadActionLoad;
|
||||
renderPassDescriptor.colorAttachments[i].storeAction = MTLStoreActionStore;
|
||||
renderPassDescriptor.colorAttachments[i].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (clear_flags & KINC_G5_CLEAR_DEPTH) {
|
||||
renderPassDescriptor.depthAttachment.clearDepth = depth;
|
||||
renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
|
||||
renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;
|
||||
}
|
||||
else {
|
||||
renderPassDescriptor.depthAttachment.clearDepth = 1;
|
||||
renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||
renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionStore;
|
||||
}
|
||||
|
||||
if (clear_flags & KINC_G5_CLEAR_STENCIL) {
|
||||
renderPassDescriptor.stencilAttachment.clearStencil = stencil;
|
||||
renderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionClear;
|
||||
renderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionStore;
|
||||
}
|
||||
else {
|
||||
renderPassDescriptor.stencilAttachment.clearStencil = 0;
|
||||
renderPassDescriptor.stencilAttachment.loadAction = MTLLoadActionDontCare;
|
||||
renderPassDescriptor.stencilAttachment.storeAction = MTLStoreActionDontCare;
|
||||
}
|
||||
|
||||
id<MTLCommandQueue> commandQueue = getMetalQueue();
|
||||
command_buffer = [commandQueue commandBuffer];
|
||||
render_command_encoder = [command_buffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_raytracing(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_instanced_rendering(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_compute_shaders(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_blend_constants(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_g5_supports_non_pow2_textures(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kinc_g5_render_targets_inverted_y(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int kinc_g5_max_bound_textures(void) {
|
||||
return 16;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
struct kinc_g5_index_buffer;
|
||||
|
||||
typedef struct {
|
||||
struct kinc_g5_index_buffer *current_index_buffer;
|
||||
} CommandList5Impl;
|
@ -0,0 +1,393 @@
|
||||
#include <kinc/graphics5/commandlist.h>
|
||||
#include <kinc/graphics5/compute.h>
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
#include <kinc/window.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalKit/MTKView.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
id getMetalQueue(void);
|
||||
id getMetalEncoder(void);
|
||||
|
||||
void kinc_g5_internal_new_render_pass(kinc_g5_render_target_t **renderTargets, int count, bool wait, unsigned clear_flags, unsigned color, float depth,
|
||||
int stencil);
|
||||
void kinc_g5_internal_pipeline_set(kinc_g5_pipeline_t *pipeline);
|
||||
|
||||
void kinc_g5_command_list_init(kinc_g5_command_list_t *list) {
|
||||
list->impl.current_index_buffer = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_destroy(kinc_g5_command_list_t *list) {}
|
||||
|
||||
static kinc_g5_render_target_t *lastRenderTargets[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
|
||||
static kinc_g5_pipeline_t *lastPipeline = NULL;
|
||||
|
||||
static int formatSize(MTLPixelFormat format) {
|
||||
switch (format) {
|
||||
case MTLPixelFormatRGBA32Float:
|
||||
return 16;
|
||||
case MTLPixelFormatRGBA16Float:
|
||||
return 8;
|
||||
case MTLPixelFormatR16Float:
|
||||
return 2;
|
||||
case MTLPixelFormatR8Unorm:
|
||||
return 1;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_begin(kinc_g5_command_list_t *list) {
|
||||
list->impl.current_index_buffer = NULL;
|
||||
lastRenderTargets[0] = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_end(kinc_g5_command_list_t *list) {}
|
||||
|
||||
void kinc_g5_command_list_clear(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget, unsigned flags, unsigned color, float depth,
|
||||
int stencil) {
|
||||
if (renderTarget->framebuffer_index >= 0) {
|
||||
kinc_g5_internal_new_render_pass(NULL, 1, false, flags, color, depth, stencil);
|
||||
}
|
||||
else {
|
||||
kinc_g5_internal_new_render_pass(&renderTarget, 1, false, flags, color, depth, stencil);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_render_target_to_framebuffer_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
|
||||
void kinc_g5_command_list_framebuffer_to_render_target_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices(kinc_g5_command_list_t *list) {
|
||||
kinc_g5_command_list_draw_indexed_vertices_from_to(list, 0, kinc_g5_index_buffer_count(list->impl.current_index_buffer));
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_from_to(kinc_g5_command_list_t *list, int start, int count) {
|
||||
id<MTLBuffer> indexBuffer = (__bridge id<MTLBuffer>)list->impl.current_index_buffer->impl.metal_buffer;
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:count
|
||||
indexType:(list->impl.current_index_buffer->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32)
|
||||
indexBuffer:indexBuffer
|
||||
indexBufferOffset:start * 4];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_from_to_from(kinc_g5_command_list_t *list, int start, int count, int vertex_offset) {
|
||||
id<MTLBuffer> indexBuffer = (__bridge id<MTLBuffer>)list->impl.current_index_buffer->impl.metal_buffer;
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:count
|
||||
indexType:(list->impl.current_index_buffer->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32)
|
||||
indexBuffer:indexBuffer
|
||||
indexBufferOffset:start * 4
|
||||
instanceCount:1
|
||||
baseVertex:vertex_offset
|
||||
baseInstance:0];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_instanced(kinc_g5_command_list_t *list, int instanceCount) {
|
||||
kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(list, instanceCount, 0, kinc_g5_index_buffer_count(list->impl.current_index_buffer));
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(kinc_g5_command_list_t *list, int instanceCount, int start, int count) {
|
||||
id<MTLBuffer> indexBuffer = (__bridge id<MTLBuffer>)list->impl.current_index_buffer->impl.metal_buffer;
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
[encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:count
|
||||
indexType:(list->impl.current_index_buffer->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32)
|
||||
indexBuffer:indexBuffer
|
||||
indexBufferOffset:start * 4
|
||||
instanceCount:instanceCount
|
||||
baseVertex:0
|
||||
baseInstance:0];
|
||||
}
|
||||
void kinc_g5_command_list_viewport(kinc_g5_command_list_t *list, int x, int y, int width, int height) {
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
MTLViewport viewport;
|
||||
viewport.originX = x;
|
||||
viewport.originY = y;
|
||||
viewport.width = width;
|
||||
viewport.height = height;
|
||||
[encoder setViewport:viewport];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_scissor(kinc_g5_command_list_t *list, int x, int y, int width, int height) {
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
MTLScissorRect scissor;
|
||||
scissor.x = x;
|
||||
scissor.y = y;
|
||||
int target_w = -1;
|
||||
int target_h = -1;
|
||||
if (lastRenderTargets[0] != NULL) {
|
||||
target_w = lastRenderTargets[0]->texWidth;
|
||||
target_h = lastRenderTargets[0]->texHeight;
|
||||
}
|
||||
else {
|
||||
target_w = kinc_window_width(0);
|
||||
target_h = kinc_window_height(0);
|
||||
}
|
||||
scissor.width = (x + width <= target_w) ? width : target_w - x;
|
||||
scissor.height = (y + height <= target_h) ? height : target_h - y;
|
||||
[encoder setScissorRect:scissor];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_disable_scissor(kinc_g5_command_list_t *list) {
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
MTLScissorRect scissor;
|
||||
scissor.x = 0;
|
||||
scissor.y = 0;
|
||||
if (lastRenderTargets[0] != NULL) {
|
||||
scissor.width = lastRenderTargets[0]->texWidth;
|
||||
scissor.height = lastRenderTargets[0]->texHeight;
|
||||
}
|
||||
else {
|
||||
scissor.width = kinc_window_width(0);
|
||||
scissor.height = kinc_window_height(0);
|
||||
}
|
||||
[encoder setScissorRect:scissor];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_pipeline(kinc_g5_command_list_t *list, struct kinc_g5_pipeline *pipeline) {
|
||||
kinc_g5_internal_pipeline_set(pipeline);
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_blend_constant(kinc_g5_command_list_t *list, float r, float g, float b, float a) {
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
[encoder setBlendColorRed:r green:g blue:b alpha:a];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_vertex_buffers(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer **buffers, int *offsets, int count) {
|
||||
kinc_g5_internal_vertex_buffer_set(buffers[0], offsets[0]);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_index_buffer(kinc_g5_command_list_t *list, struct kinc_g5_index_buffer *buffer) {
|
||||
list->impl.current_index_buffer = buffer;
|
||||
}
|
||||
|
||||
extern bool kinc_internal_metal_has_depth;
|
||||
|
||||
void kinc_g5_command_list_set_render_targets(kinc_g5_command_list_t *list, struct kinc_g5_render_target **targets, int count) {
|
||||
if (targets[0]->framebuffer_index >= 0) {
|
||||
for (int i = 0; i < 8; ++i)
|
||||
lastRenderTargets[i] = NULL;
|
||||
kinc_g5_internal_new_render_pass(NULL, 1, false, 0, 0, 0.0f, 0);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < count; ++i)
|
||||
lastRenderTargets[i] = targets[i];
|
||||
for (int i = count; i < 8; ++i)
|
||||
lastRenderTargets[i] = NULL;
|
||||
kinc_g5_internal_new_render_pass(targets, count, false, 0, 0, 0.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_upload_index_buffer(kinc_g5_command_list_t *list, struct kinc_g5_index_buffer *buffer) {}
|
||||
|
||||
void kinc_g5_command_list_upload_vertex_buffer(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer *buffer) {}
|
||||
|
||||
void kinc_g5_command_list_upload_texture(kinc_g5_command_list_t *list, struct kinc_g5_texture *texture) {}
|
||||
|
||||
void kinc_g5_command_list_get_render_target_pixels(kinc_g5_command_list_t *list, kinc_g5_render_target_t *render_target, uint8_t *data) {
|
||||
// Create readback buffer
|
||||
if (render_target->impl._texReadback == NULL) {
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor new];
|
||||
descriptor.textureType = MTLTextureType2D;
|
||||
descriptor.width = render_target->texWidth;
|
||||
descriptor.height = render_target->texHeight;
|
||||
descriptor.depth = 1;
|
||||
descriptor.pixelFormat = [(__bridge id<MTLTexture>)render_target->impl._tex pixelFormat];
|
||||
descriptor.arrayLength = 1;
|
||||
descriptor.mipmapLevelCount = 1;
|
||||
descriptor.usage = MTLTextureUsageUnknown;
|
||||
#ifdef KINC_APPLE_SOC
|
||||
descriptor.resourceOptions = MTLResourceStorageModeShared;
|
||||
#else
|
||||
descriptor.resourceOptions = MTLResourceStorageModeManaged;
|
||||
#endif
|
||||
render_target->impl._texReadback = (__bridge_retained void *)[device newTextureWithDescriptor:descriptor];
|
||||
}
|
||||
|
||||
// Copy render target to readback buffer
|
||||
id<MTLCommandQueue> commandQueue = getMetalQueue();
|
||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
||||
id<MTLBlitCommandEncoder> commandEncoder = [commandBuffer blitCommandEncoder];
|
||||
[commandEncoder copyFromTexture:(__bridge id<MTLTexture>)render_target->impl._tex
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||
sourceSize:MTLSizeMake(render_target->texWidth, render_target->texHeight, 1)
|
||||
toTexture:(__bridge id<MTLTexture>)render_target->impl._texReadback
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
#ifndef KINC_APPLE_SOC
|
||||
[commandEncoder synchronizeResource:(__bridge id<MTLTexture>)render_target->impl._texReadback];
|
||||
#endif
|
||||
[commandEncoder endEncoding];
|
||||
[commandBuffer commit];
|
||||
[commandBuffer waitUntilCompleted];
|
||||
|
||||
// Read buffer
|
||||
id<MTLTexture> tex = (__bridge id<MTLTexture>)render_target->impl._texReadback;
|
||||
int formatByteSize = formatSize([(__bridge id<MTLTexture>)render_target->impl._tex pixelFormat]);
|
||||
MTLRegion region = MTLRegionMake2D(0, 0, render_target->texWidth, render_target->texHeight);
|
||||
[tex getBytes:data bytesPerRow:formatByteSize * render_target->texWidth fromRegion:region mipmapLevel:0];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_execute(kinc_g5_command_list_t *list) {
|
||||
if (lastRenderTargets[0] == NULL) {
|
||||
kinc_g5_internal_new_render_pass(NULL, 1, false, 0, 0, 0.0f, 0);
|
||||
}
|
||||
else {
|
||||
int count = 1;
|
||||
while (lastRenderTargets[count] != NULL)
|
||||
count++;
|
||||
kinc_g5_internal_new_render_pass(lastRenderTargets, count, false, 0, 0, 0.0f, 0);
|
||||
}
|
||||
if (lastPipeline != NULL)
|
||||
kinc_g5_internal_pipeline_set(lastPipeline);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_wait_for_execution_to_finish(kinc_g5_command_list_t *list) {
|
||||
id<MTLCommandQueue> commandQueue = getMetalQueue();
|
||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
||||
[commandBuffer commit];
|
||||
[commandBuffer waitUntilCompleted];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_vertex_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size) {
|
||||
id<MTLBuffer> buf = (__bridge id<MTLBuffer>)buffer->impl._buffer;
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
[encoder setVertexBuffer:buf offset:offset atIndex:1];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_fragment_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size) {
|
||||
id<MTLBuffer> buf = (__bridge id<MTLBuffer>)buffer->impl._buffer;
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
[encoder setFragmentBuffer:buf offset:offset atIndex:0];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_compute_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size) {
|
||||
assert(compute_command_encoder != nil);
|
||||
id<MTLBuffer> buf = (__bridge id<MTLBuffer>)buffer->impl._buffer;
|
||||
[compute_command_encoder setBuffer:buf offset:offset atIndex:1];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_render_target_to_texture_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {
|
||||
#ifndef KINC_APPLE_SOC
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
[encoder textureBarrier];
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_texture_to_render_target_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
|
||||
void kinc_g5_command_list_set_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture) {
|
||||
id<MTLTexture> tex = (__bridge id<MTLTexture>)texture->impl._tex;
|
||||
if (compute_command_encoder != nil) {
|
||||
[compute_command_encoder setTexture:tex atIndex:unit.stages[KINC_G5_SHADER_TYPE_COMPUTE]];
|
||||
}
|
||||
else {
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
[render_command_encoder setVertexTexture:tex atIndex:unit.stages[KINC_G5_SHADER_TYPE_VERTEX]];
|
||||
}
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
[render_command_encoder setFragmentTexture:tex atIndex:unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_image_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture) {
|
||||
kinc_g5_command_list_set_texture(list, unit, texture);
|
||||
}
|
||||
|
||||
bool kinc_g5_command_list_init_occlusion_query(kinc_g5_command_list_t *list, unsigned *occlusionQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_delete_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery) {}
|
||||
|
||||
void kinc_g5_command_list_render_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery, int triangles) {}
|
||||
|
||||
bool kinc_g5_command_list_are_query_results_available(kinc_g5_command_list_t *list, unsigned occlusionQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_get_query_result(kinc_g5_command_list_t *list, unsigned occlusionQuery, unsigned *pixelCount) {}
|
||||
|
||||
void kinc_g5_command_list_set_render_target_face(kinc_g5_command_list_t *list, kinc_g5_render_target_t *texture, int face) {}
|
||||
|
||||
void kinc_g5_command_list_set_texture_from_render_target(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_render_target_t *target) {
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
id<MTLTexture> tex = (__bridge id<MTLTexture>)target->impl._tex;
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
[encoder setVertexTexture:tex atIndex:unit.stages[KINC_G5_SHADER_TYPE_VERTEX]];
|
||||
}
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
[encoder setFragmentTexture:tex atIndex:unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]];
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_texture_from_render_target_depth(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_render_target_t *target) {
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
id<MTLTexture> depth_tex = (__bridge id<MTLTexture>)target->impl._depthTex;
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
[encoder setVertexTexture:depth_tex atIndex:unit.stages[KINC_G5_SHADER_TYPE_VERTEX]];
|
||||
}
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
[encoder setFragmentTexture:depth_tex atIndex:unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]];
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_sampler(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_sampler_t *sampler) {
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
id<MTLSamplerState> mtl_sampler = (__bridge id<MTLSamplerState>)sampler->impl.sampler;
|
||||
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_VERTEX] >= 0) {
|
||||
[encoder setVertexSamplerState:mtl_sampler atIndex:unit.stages[KINC_G5_SHADER_TYPE_VERTEX]];
|
||||
}
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
[encoder setFragmentSamplerState:mtl_sampler atIndex:unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]];
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_compute_shader(kinc_g5_command_list_t *list, kinc_g5_compute_shader *shader) {
|
||||
if (compute_command_encoder == nil) {
|
||||
end_render_pass();
|
||||
compute_command_encoder = [command_buffer computeCommandEncoder];
|
||||
}
|
||||
|
||||
id<MTLComputePipelineState> pipeline = (__bridge id<MTLComputePipelineState>)shader->impl._pipeline;
|
||||
[compute_command_encoder setComputePipelineState:pipeline];
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_compute(kinc_g5_command_list_t *list, int x, int y, int z) {
|
||||
assert(compute_command_encoder != nil);
|
||||
|
||||
MTLSize perGrid;
|
||||
perGrid.width = x;
|
||||
perGrid.height = y;
|
||||
perGrid.depth = z;
|
||||
MTLSize perGroup;
|
||||
perGroup.width = 16;
|
||||
perGroup.height = 16;
|
||||
perGroup.depth = 1;
|
||||
[compute_command_encoder dispatchThreadgroups:perGrid threadsPerThreadgroup:perGroup];
|
||||
|
||||
[compute_command_encoder endEncoding];
|
||||
|
||||
compute_command_encoder = nil;
|
||||
|
||||
start_render_pass();
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct kinc_g5_compute_shader_impl {
|
||||
char name[1024];
|
||||
void *_function;
|
||||
void *_pipeline;
|
||||
void *_reflection;
|
||||
} kinc_g5_compute_shader_impl;
|
@ -0,0 +1,112 @@
|
||||
#include <kinc/graphics5/compute.h>
|
||||
#include <kinc/graphics4/texture.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
id getMetalLibrary(void);
|
||||
|
||||
void kinc_g5_compute_shader_init(kinc_g5_compute_shader *shader, void *_data, int length) {
|
||||
shader->impl.name[0] = 0;
|
||||
|
||||
{
|
||||
uint8_t *data = (uint8_t *)_data;
|
||||
if (length > 1 && data[0] == '>') {
|
||||
memcpy(shader->impl.name, data + 1, length - 1);
|
||||
shader->impl.name[length - 1] = 0;
|
||||
}
|
||||
else {
|
||||
for (int i = 3; i < length; ++i) {
|
||||
if (data[i] == '\n') {
|
||||
shader->impl.name[i - 3] = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
shader->impl.name[i - 3] = data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *data = (char *)_data;
|
||||
id<MTLLibrary> library = nil;
|
||||
if (length > 1 && data[0] == '>') {
|
||||
library = getMetalLibrary();
|
||||
}
|
||||
else {
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
library = [device newLibraryWithSource:[[NSString alloc] initWithBytes:data length:length encoding:NSUTF8StringEncoding] options:nil error:nil];
|
||||
}
|
||||
id<MTLFunction> function = [library newFunctionWithName:[NSString stringWithCString:shader->impl.name encoding:NSUTF8StringEncoding]];
|
||||
assert(function != nil);
|
||||
shader->impl._function = (__bridge_retained void *)function;
|
||||
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
MTLComputePipelineReflection *reflection = nil;
|
||||
NSError *error = nil;
|
||||
shader->impl._pipeline = (__bridge_retained void *)[device newComputePipelineStateWithFunction:function
|
||||
options:MTLPipelineOptionBufferTypeInfo
|
||||
reflection:&reflection
|
||||
error:&error];
|
||||
if (error != nil)
|
||||
NSLog(@"%@", [error localizedDescription]);
|
||||
assert(shader->impl._pipeline != NULL && !error);
|
||||
shader->impl._reflection = (__bridge_retained void *)reflection;
|
||||
}
|
||||
|
||||
void kinc_g5_compute_shader_destroy(kinc_g5_compute_shader *shader) {
|
||||
id<MTLFunction> function = (__bridge_transfer id<MTLFunction>)shader->impl._function;
|
||||
function = nil;
|
||||
shader->impl._function = NULL;
|
||||
|
||||
id<MTLComputePipelineState> pipeline = (__bridge_transfer id<MTLComputePipelineState>)shader->impl._pipeline;
|
||||
pipeline = nil;
|
||||
shader->impl._pipeline = NULL;
|
||||
|
||||
MTLComputePipelineReflection *reflection = (__bridge_transfer MTLComputePipelineReflection *)shader->impl._reflection;
|
||||
reflection = nil;
|
||||
shader->impl._reflection = NULL;
|
||||
}
|
||||
|
||||
kinc_g5_constant_location_t kinc_g5_compute_shader_get_constant_location(kinc_g5_compute_shader *shader, const char *name) {
|
||||
kinc_g5_constant_location_t location;
|
||||
location.impl.vertexOffset = -1;
|
||||
location.impl.fragmentOffset = -1;
|
||||
location.impl.computeOffset = -1;
|
||||
|
||||
MTLComputePipelineReflection *reflection = (__bridge MTLComputePipelineReflection *)shader->impl._reflection;
|
||||
|
||||
for (MTLArgument *arg in reflection.arguments) {
|
||||
if (arg.type == MTLArgumentTypeBuffer && [arg.name isEqualToString:@"uniforms"]) {
|
||||
if ([arg bufferDataType] == MTLDataTypeStruct) {
|
||||
MTLStructType *structObj = [arg bufferStructType];
|
||||
for (MTLStructMember *member in structObj.members) {
|
||||
if (strcmp([[member name] UTF8String], name) == 0) {
|
||||
location.impl.computeOffset = (int)[member offset];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
kinc_g5_texture_unit_t kinc_g5_compute_shader_get_texture_unit(kinc_g5_compute_shader *shader, const char *name) {
|
||||
kinc_g5_texture_unit_t unit;
|
||||
for (int i = 0; i < KINC_G5_SHADER_TYPE_COUNT; ++i) {
|
||||
unit.stages[i] = -1;
|
||||
}
|
||||
|
||||
MTLComputePipelineReflection *reflection = (__bridge MTLComputePipelineReflection *)shader->impl._reflection;
|
||||
for (MTLArgument *arg in reflection.arguments) {
|
||||
if ([arg type] == MTLArgumentTypeTexture && strcmp([[arg name] UTF8String], name) == 0) {
|
||||
unit.stages[KINC_G5_SHADER_TYPE_COMPUTE] = (int)[arg index];
|
||||
}
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
void *_buffer;
|
||||
int lastStart;
|
||||
int lastCount;
|
||||
int mySize;
|
||||
} ConstantBuffer5Impl;
|
@ -0,0 +1,40 @@
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
|
||||
bool kinc_g5_transposeMat3 = true;
|
||||
bool kinc_g5_transposeMat4 = true;
|
||||
|
||||
void kinc_g5_constant_buffer_init(kinc_g5_constant_buffer_t *buffer, int size) {
|
||||
buffer->impl.mySize = size;
|
||||
buffer->data = NULL;
|
||||
buffer->impl._buffer = (__bridge_retained void *)[getMetalDevice() newBufferWithLength:size options:MTLResourceOptionCPUCacheModeDefault];
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_destroy(kinc_g5_constant_buffer_t *buffer) {
|
||||
id<MTLBuffer> buf = (__bridge_transfer id<MTLBuffer>)buffer->impl._buffer;
|
||||
buf = nil;
|
||||
buffer->impl._buffer = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_lock_all(kinc_g5_constant_buffer_t *buffer) {
|
||||
kinc_g5_constant_buffer_lock(buffer, 0, kinc_g5_constant_buffer_size(buffer));
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_lock(kinc_g5_constant_buffer_t *buffer, int start, int count) {
|
||||
buffer->impl.lastStart = start;
|
||||
buffer->impl.lastCount = count;
|
||||
id<MTLBuffer> buf = (__bridge id<MTLBuffer>)buffer->impl._buffer;
|
||||
uint8_t *data = (uint8_t *)[buf contents];
|
||||
buffer->data = &data[start];
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_unlock(kinc_g5_constant_buffer_t *buffer) {
|
||||
buffer->data = NULL;
|
||||
}
|
||||
|
||||
int kinc_g5_constant_buffer_size(kinc_g5_constant_buffer_t *buffer) {
|
||||
return buffer->impl.mySize;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/backend/graphics5/indexbuffer.h>
|
||||
#include <kinc/backend/graphics5/rendertarget.h>
|
||||
#include <kinc/backend/graphics5/texture.h>
|
||||
#include <kinc/backend/graphics5/vertexbuffer.h>
|
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
void *metal_buffer;
|
||||
int count;
|
||||
bool gpu_memory;
|
||||
int format;
|
||||
int last_start;
|
||||
int last_count;
|
||||
} IndexBuffer5Impl;
|
@ -0,0 +1,73 @@
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
|
||||
void kinc_g5_index_buffer_init(kinc_g5_index_buffer_t *buffer, int indexCount, kinc_g5_index_buffer_format_t format, bool gpuMemory) {
|
||||
buffer->impl.count = indexCount;
|
||||
buffer->impl.gpu_memory = gpuMemory;
|
||||
buffer->impl.format = format;
|
||||
buffer->impl.last_start = 0;
|
||||
buffer->impl.last_count = indexCount;
|
||||
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
MTLResourceOptions options = MTLResourceCPUCacheModeWriteCombined;
|
||||
#ifdef KINC_APPLE_SOC
|
||||
options |= MTLResourceStorageModeShared;
|
||||
#else
|
||||
if (gpuMemory) {
|
||||
options |= MTLResourceStorageModeManaged;
|
||||
}
|
||||
else {
|
||||
options |= MTLResourceStorageModeShared;
|
||||
}
|
||||
#endif
|
||||
buffer->impl.metal_buffer = (__bridge_retained void *)[device
|
||||
newBufferWithLength:(format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? sizeof(uint16_t) * indexCount : sizeof(uint32_t) * indexCount)
|
||||
options:options];
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_destroy(kinc_g5_index_buffer_t *buffer) {
|
||||
id<MTLBuffer> buf = (__bridge_transfer id<MTLBuffer>)buffer->impl.metal_buffer;
|
||||
buf = nil;
|
||||
buffer->impl.metal_buffer = NULL;
|
||||
}
|
||||
|
||||
static int kinc_g5_internal_index_buffer_stride(kinc_g5_index_buffer_t *buffer) {
|
||||
return buffer->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? 2 : 4;
|
||||
}
|
||||
|
||||
void *kinc_g5_index_buffer_lock_all(kinc_g5_index_buffer_t *buffer) {
|
||||
return kinc_g5_index_buffer_lock(buffer, 0, kinc_g5_index_buffer_count(buffer));
|
||||
}
|
||||
|
||||
void *kinc_g5_index_buffer_lock(kinc_g5_index_buffer_t *buffer, int start, int count) {
|
||||
buffer->impl.last_start = start;
|
||||
buffer->impl.last_count = count;
|
||||
|
||||
id<MTLBuffer> metal_buffer = (__bridge id<MTLBuffer>)buffer->impl.metal_buffer;
|
||||
uint8_t *data = (uint8_t *)[metal_buffer contents];
|
||||
return &data[start * kinc_g5_internal_index_buffer_stride(buffer)];
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_unlock_all(kinc_g5_index_buffer_t *buffer) {
|
||||
kinc_g5_index_buffer_unlock(buffer, buffer->impl.last_count);
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_unlock(kinc_g5_index_buffer_t *buffer, int count) {
|
||||
#ifndef KINC_APPLE_SOC
|
||||
if (buffer->impl.gpu_memory) {
|
||||
id<MTLBuffer> metal_buffer = (__bridge id<MTLBuffer>)buffer->impl.metal_buffer;
|
||||
NSRange range;
|
||||
range.location = buffer->impl.last_start * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
range.length = count * kinc_g5_internal_index_buffer_stride(buffer);
|
||||
[metal_buffer didModifyRange:range];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int kinc_g5_index_buffer_count(kinc_g5_index_buffer_t *buffer) {
|
||||
return buffer->impl.count;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
#import <Metal/Metal.h>
|
||||
#import <MetalKit/MTKView.h>
|
||||
|
||||
static id<MTLCommandBuffer> command_buffer = nil;
|
||||
static id<MTLRenderCommandEncoder> render_command_encoder = nil;
|
||||
static id<MTLComputeCommandEncoder> compute_command_encoder = nil;
|
||||
|
||||
static void start_render_pass(void);
|
||||
static void end_render_pass(void);
|
||||
|
||||
#include "Metal.m.h"
|
||||
#include "commandlist.m.h"
|
||||
#include "compute.m.h"
|
||||
#include "constantbuffer.m.h"
|
||||
#include "indexbuffer.m.h"
|
||||
#include "pipeline.m.h"
|
||||
#include "raytrace.m.h"
|
||||
#include "rendertarget.m.h"
|
||||
#include "sampler.m.h"
|
||||
#include "shader.m.h"
|
||||
#include "texture.m.h"
|
||||
#include "vertexbuffer.m.h"
|
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
struct kinc_g5_shader;
|
||||
|
||||
typedef struct {
|
||||
struct kinc_g5_shader *vertexShader;
|
||||
struct kinc_g5_shader *fragmentShader;
|
||||
void *_pipeline;
|
||||
void *_pipelineDepth;
|
||||
void *_reflection;
|
||||
void *_depthStencil;
|
||||
void *_depthStencilNone;
|
||||
// void _set();
|
||||
} PipelineState5Impl;
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
} ComputePipelineState5Impl;
|
||||
|
||||
typedef struct {
|
||||
int vertexOffset;
|
||||
int fragmentOffset;
|
||||
int computeOffset;
|
||||
} ConstantLocation5Impl;
|
@ -0,0 +1,433 @@
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/graphics5/shader.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
id getMetalEncoder(void);
|
||||
|
||||
static MTLBlendFactor convert_blending_factor(kinc_g5_blending_factor_t factor) {
|
||||
switch (factor) {
|
||||
case KINC_G5_BLEND_ONE:
|
||||
return MTLBlendFactorOne;
|
||||
case KINC_G5_BLEND_ZERO:
|
||||
return MTLBlendFactorZero;
|
||||
case KINC_G5_BLEND_SOURCE_ALPHA:
|
||||
return MTLBlendFactorSourceAlpha;
|
||||
case KINC_G5_BLEND_DEST_ALPHA:
|
||||
return MTLBlendFactorDestinationAlpha;
|
||||
case KINC_G5_BLEND_INV_SOURCE_ALPHA:
|
||||
return MTLBlendFactorOneMinusSourceAlpha;
|
||||
case KINC_G5_BLEND_INV_DEST_ALPHA:
|
||||
return MTLBlendFactorOneMinusDestinationAlpha;
|
||||
case KINC_G5_BLEND_SOURCE_COLOR:
|
||||
return MTLBlendFactorSourceColor;
|
||||
case KINC_G5_BLEND_DEST_COLOR:
|
||||
return MTLBlendFactorDestinationColor;
|
||||
case KINC_G5_BLEND_INV_SOURCE_COLOR:
|
||||
return MTLBlendFactorOneMinusSourceColor;
|
||||
case KINC_G5_BLEND_INV_DEST_COLOR:
|
||||
return MTLBlendFactorOneMinusDestinationColor;
|
||||
case KINC_G5_BLEND_CONSTANT:
|
||||
return MTLBlendFactorBlendColor;
|
||||
case KINC_G5_BLEND_INV_CONSTANT:
|
||||
return MTLBlendFactorOneMinusBlendColor;
|
||||
}
|
||||
}
|
||||
|
||||
static MTLBlendOperation convert_blending_operation(kinc_g5_blending_operation_t op) {
|
||||
switch (op) {
|
||||
case KINC_G5_BLENDOP_ADD:
|
||||
return MTLBlendOperationAdd;
|
||||
case KINC_G5_BLENDOP_SUBTRACT:
|
||||
return MTLBlendOperationSubtract;
|
||||
case KINC_G5_BLENDOP_REVERSE_SUBTRACT:
|
||||
return MTLBlendOperationReverseSubtract;
|
||||
case KINC_G5_BLENDOP_MIN:
|
||||
return MTLBlendOperationMin;
|
||||
case KINC_G5_BLENDOP_MAX:
|
||||
return MTLBlendOperationMax;
|
||||
}
|
||||
}
|
||||
|
||||
static MTLCompareFunction convert_compare_mode(kinc_g5_compare_mode_t compare) {
|
||||
switch (compare) {
|
||||
case KINC_G5_COMPARE_MODE_ALWAYS:
|
||||
return MTLCompareFunctionAlways;
|
||||
case KINC_G5_COMPARE_MODE_NEVER:
|
||||
return MTLCompareFunctionNever;
|
||||
case KINC_G5_COMPARE_MODE_EQUAL:
|
||||
return MTLCompareFunctionEqual;
|
||||
case KINC_G5_COMPARE_MODE_NOT_EQUAL:
|
||||
return MTLCompareFunctionNotEqual;
|
||||
case KINC_G5_COMPARE_MODE_LESS:
|
||||
return MTLCompareFunctionLess;
|
||||
case KINC_G5_COMPARE_MODE_LESS_EQUAL:
|
||||
return MTLCompareFunctionLessEqual;
|
||||
case KINC_G5_COMPARE_MODE_GREATER:
|
||||
return MTLCompareFunctionGreater;
|
||||
case KINC_G5_COMPARE_MODE_GREATER_EQUAL:
|
||||
return MTLCompareFunctionGreaterEqual;
|
||||
}
|
||||
}
|
||||
|
||||
static MTLCullMode convert_cull_mode(kinc_g5_cull_mode_t cull) {
|
||||
switch (cull) {
|
||||
case KINC_G5_CULL_MODE_CLOCKWISE:
|
||||
return MTLCullModeFront;
|
||||
case KINC_G5_CULL_MODE_COUNTERCLOCKWISE:
|
||||
return MTLCullModeBack;
|
||||
case KINC_G5_CULL_MODE_NEVER:
|
||||
return MTLCullModeNone;
|
||||
}
|
||||
}
|
||||
|
||||
static MTLPixelFormat convert_render_target_format(kinc_g5_render_target_format_t format) {
|
||||
switch (format) {
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_128BIT_FLOAT:
|
||||
return MTLPixelFormatRGBA32Float;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_64BIT_FLOAT:
|
||||
return MTLPixelFormatRGBA16Float;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT:
|
||||
return MTLPixelFormatR32Float;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT:
|
||||
return MTLPixelFormatR16Float;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_8BIT_RED:
|
||||
return MTLPixelFormatR8Unorm;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_32BIT:
|
||||
default:
|
||||
return MTLPixelFormatBGRA8Unorm;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_pipeline_init(kinc_g5_pipeline_t *pipeline) {
|
||||
memset(&pipeline->impl, 0, sizeof(pipeline->impl));
|
||||
}
|
||||
|
||||
void kinc_g5_pipeline_destroy(kinc_g5_pipeline_t *pipeline) {
|
||||
pipeline->impl._reflection = NULL;
|
||||
pipeline->impl._depthStencil = NULL;
|
||||
|
||||
id<MTLRenderPipelineState> pipe = (__bridge_transfer id<MTLRenderPipelineState>)pipeline->impl._pipeline;
|
||||
pipe = nil;
|
||||
pipeline->impl._pipeline = NULL;
|
||||
|
||||
MTLRenderPipelineReflection *reflection = (__bridge_transfer MTLRenderPipelineReflection *)pipeline->impl._reflection;
|
||||
reflection = nil;
|
||||
pipeline->impl._reflection = NULL;
|
||||
|
||||
id<MTLRenderPipelineState> pipeDepth = (__bridge_transfer id<MTLRenderPipelineState>)pipeline->impl._pipelineDepth;
|
||||
pipeDepth = nil;
|
||||
pipeline->impl._pipelineDepth = NULL;
|
||||
|
||||
id<MTLDepthStencilState> depthStencil = (__bridge_transfer id<MTLDepthStencilState>)pipeline->impl._depthStencil;
|
||||
depthStencil = nil;
|
||||
pipeline->impl._depthStencil = NULL;
|
||||
|
||||
id<MTLDepthStencilState> depthStencilNone = (__bridge_transfer id<MTLDepthStencilState>)pipeline->impl._depthStencilNone;
|
||||
depthStencilNone = nil;
|
||||
pipeline->impl._depthStencilNone = NULL;
|
||||
}
|
||||
|
||||
static int findAttributeIndex(NSArray<MTLVertexAttribute *> *attributes, const char *name) {
|
||||
for (MTLVertexAttribute *attribute in attributes) {
|
||||
if (strcmp(name, [[attribute name] UTF8String]) == 0) {
|
||||
return (int)[attribute attributeIndex];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void kinc_g5_pipeline_compile(kinc_g5_pipeline_t *pipeline) {
|
||||
MTLRenderPipelineDescriptor *renderPipelineDesc = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
renderPipelineDesc.vertexFunction = (__bridge id<MTLFunction>)pipeline->vertexShader->impl.mtlFunction;
|
||||
renderPipelineDesc.fragmentFunction = (__bridge id<MTLFunction>)pipeline->fragmentShader->impl.mtlFunction;
|
||||
for (int i = 0; i < pipeline->colorAttachmentCount; ++i) {
|
||||
renderPipelineDesc.colorAttachments[i].pixelFormat = convert_render_target_format(pipeline->colorAttachment[i]);
|
||||
renderPipelineDesc.colorAttachments[i].blendingEnabled =
|
||||
pipeline->blend_source != KINC_G5_BLEND_ONE || pipeline->blend_destination != KINC_G5_BLEND_ZERO ||
|
||||
pipeline->alpha_blend_source != KINC_G5_BLEND_ONE || pipeline->alpha_blend_destination != KINC_G5_BLEND_ZERO;
|
||||
renderPipelineDesc.colorAttachments[i].sourceRGBBlendFactor = convert_blending_factor(pipeline->blend_source);
|
||||
renderPipelineDesc.colorAttachments[i].destinationRGBBlendFactor = convert_blending_factor(pipeline->blend_destination);
|
||||
renderPipelineDesc.colorAttachments[i].rgbBlendOperation = convert_blending_operation(pipeline->blend_operation);
|
||||
renderPipelineDesc.colorAttachments[i].sourceAlphaBlendFactor = convert_blending_factor(pipeline->alpha_blend_source);
|
||||
renderPipelineDesc.colorAttachments[i].destinationAlphaBlendFactor = convert_blending_factor(pipeline->alpha_blend_destination);
|
||||
renderPipelineDesc.colorAttachments[i].alphaBlendOperation = convert_blending_operation(pipeline->alpha_blend_operation);
|
||||
renderPipelineDesc.colorAttachments[i].writeMask =
|
||||
(pipeline->colorWriteMaskRed[i] ? MTLColorWriteMaskRed : 0) | (pipeline->colorWriteMaskGreen[i] ? MTLColorWriteMaskGreen : 0) |
|
||||
(pipeline->colorWriteMaskBlue[i] ? MTLColorWriteMaskBlue : 0) | (pipeline->colorWriteMaskAlpha[i] ? MTLColorWriteMaskAlpha : 0);
|
||||
}
|
||||
renderPipelineDesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||
renderPipelineDesc.stencilAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||
|
||||
float offset = 0;
|
||||
MTLVertexDescriptor *vertexDescriptor = [[MTLVertexDescriptor alloc] init];
|
||||
|
||||
for (int i = 0; i < pipeline->inputLayout[0]->size; ++i) {
|
||||
int index = findAttributeIndex(renderPipelineDesc.vertexFunction.vertexAttributes, pipeline->inputLayout[0]->elements[i].name);
|
||||
|
||||
if (index < 0) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not find vertex attribute %s\n", pipeline->inputLayout[0]->elements[i].name);
|
||||
}
|
||||
|
||||
if (index >= 0) {
|
||||
vertexDescriptor.attributes[index].bufferIndex = 0;
|
||||
vertexDescriptor.attributes[index].offset = offset;
|
||||
}
|
||||
|
||||
offset += kinc_g4_vertex_data_size(pipeline->inputLayout[0]->elements[i].data);
|
||||
if (index >= 0) {
|
||||
switch (pipeline->inputLayout[0]->elements[i].data) {
|
||||
case KINC_G4_VERTEX_DATA_NONE:
|
||||
assert(false);
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_F32_1X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatFloat;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_F32_2X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatFloat2;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_F32_3X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatFloat3;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_F32_4X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatFloat4;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_F32_4X4:
|
||||
assert(false);
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_1X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatChar;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_1X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUChar;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_1X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatCharNormalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_1X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUCharNormalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_2X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatChar2;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_2X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUChar2;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_2X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatChar2Normalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_2X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUChar2Normalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_4X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatChar4;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_4X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUChar4;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I8_4X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatChar4Normalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U8_4X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUChar4Normalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_1X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatShort;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_1X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUShort;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_1X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatShortNormalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_1X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUShortNormalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_2X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatShort2;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_2X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUShort2;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_2X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatShort2Normalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_2X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUShort2Normalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_4X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatShort4;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_4X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUShort4;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I16_4X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatShort4Normalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U16_4X_NORMALIZED:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUShort4Normalized;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I32_1X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatInt;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U32_1X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUInt;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I32_2X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatInt2;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U32_2X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUInt2;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I32_3X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatInt3;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U32_3X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUInt3;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_I32_4X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatInt4;
|
||||
break;
|
||||
case KINC_G4_VERTEX_DATA_U32_4X:
|
||||
vertexDescriptor.attributes[index].format = MTLVertexFormatUInt4;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vertexDescriptor.layouts[0].stride = offset;
|
||||
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||
|
||||
renderPipelineDesc.vertexDescriptor = vertexDescriptor;
|
||||
|
||||
NSError *errors = nil;
|
||||
MTLRenderPipelineReflection *reflection = nil;
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
|
||||
pipeline->impl._pipeline = (__bridge_retained void *)[device newRenderPipelineStateWithDescriptor:renderPipelineDesc
|
||||
options:MTLPipelineOptionBufferTypeInfo
|
||||
reflection:&reflection
|
||||
error:&errors];
|
||||
if (errors != nil)
|
||||
NSLog(@"%@", [errors localizedDescription]);
|
||||
assert(pipeline->impl._pipeline && !errors);
|
||||
|
||||
renderPipelineDesc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||
renderPipelineDesc.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||
pipeline->impl._pipelineDepth = (__bridge_retained void *)[device newRenderPipelineStateWithDescriptor:renderPipelineDesc
|
||||
options:MTLPipelineOptionBufferTypeInfo
|
||||
reflection:&reflection
|
||||
error:&errors];
|
||||
if (errors != nil)
|
||||
NSLog(@"%@", [errors localizedDescription]);
|
||||
assert(pipeline->impl._pipelineDepth && !errors);
|
||||
|
||||
pipeline->impl._reflection = (__bridge_retained void *)reflection;
|
||||
|
||||
MTLDepthStencilDescriptor *depthStencilDescriptor = [MTLDepthStencilDescriptor new];
|
||||
depthStencilDescriptor.depthCompareFunction = convert_compare_mode(pipeline->depthMode);
|
||||
depthStencilDescriptor.depthWriteEnabled = pipeline->depthWrite;
|
||||
pipeline->impl._depthStencil = (__bridge_retained void *)[device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
||||
|
||||
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
|
||||
depthStencilDescriptor.depthWriteEnabled = false;
|
||||
pipeline->impl._depthStencilNone = (__bridge_retained void *)[device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
||||
}
|
||||
|
||||
bool kinc_internal_current_render_target_has_depth(void);
|
||||
|
||||
void kinc_g5_internal_pipeline_set(kinc_g5_pipeline_t *pipeline) {
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
if (kinc_internal_current_render_target_has_depth()) {
|
||||
id<MTLRenderPipelineState> pipe = (__bridge id<MTLRenderPipelineState>)pipeline->impl._pipelineDepth;
|
||||
[encoder setRenderPipelineState:pipe];
|
||||
id<MTLDepthStencilState> depthStencil = (__bridge id<MTLDepthStencilState>)pipeline->impl._depthStencil;
|
||||
[encoder setDepthStencilState:depthStencil];
|
||||
}
|
||||
else {
|
||||
id<MTLRenderPipelineState> pipe = (__bridge id<MTLRenderPipelineState>)pipeline->impl._pipeline;
|
||||
[encoder setRenderPipelineState:pipe];
|
||||
id<MTLDepthStencilState> depthStencil = (__bridge id<MTLDepthStencilState>)pipeline->impl._depthStencilNone;
|
||||
[encoder setDepthStencilState:depthStencil];
|
||||
}
|
||||
[encoder setFrontFacingWinding:MTLWindingClockwise];
|
||||
[encoder setCullMode:convert_cull_mode(pipeline->cullMode)];
|
||||
}
|
||||
|
||||
kinc_g5_constant_location_t kinc_g5_pipeline_get_constant_location(kinc_g5_pipeline_t *pipeline, const char *name) {
|
||||
if (strcmp(name, "bias") == 0) {
|
||||
name = "bias0";
|
||||
}
|
||||
|
||||
kinc_g5_constant_location_t location;
|
||||
location.impl.vertexOffset = -1;
|
||||
location.impl.fragmentOffset = -1;
|
||||
location.impl.computeOffset = -1;
|
||||
|
||||
MTLRenderPipelineReflection *reflection = (__bridge MTLRenderPipelineReflection *)pipeline->impl._reflection;
|
||||
|
||||
for (MTLArgument *arg in reflection.vertexArguments) {
|
||||
if (arg.type == MTLArgumentTypeBuffer && [arg.name isEqualToString:@"uniforms"]) {
|
||||
if ([arg bufferDataType] == MTLDataTypeStruct) {
|
||||
MTLStructType *structObj = [arg bufferStructType];
|
||||
for (MTLStructMember *member in structObj.members) {
|
||||
if (strcmp([[member name] UTF8String], name) == 0) {
|
||||
location.impl.vertexOffset = (int)[member offset];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (MTLArgument *arg in reflection.fragmentArguments) {
|
||||
if ([arg type] == MTLArgumentTypeBuffer && [[arg name] isEqualToString:@"uniforms"]) {
|
||||
if ([arg bufferDataType] == MTLDataTypeStruct) {
|
||||
MTLStructType *structObj = [arg bufferStructType];
|
||||
for (MTLStructMember *member in structObj.members) {
|
||||
if (strcmp([[member name] UTF8String], name) == 0) {
|
||||
location.impl.fragmentOffset = (int)[member offset];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
kinc_g5_texture_unit_t kinc_g5_pipeline_get_texture_unit(kinc_g5_pipeline_t *pipeline, const char *name) {
|
||||
kinc_g5_texture_unit_t unit = {0};
|
||||
for (int i = 0; i < KINC_G5_SHADER_TYPE_COUNT; ++i) {
|
||||
unit.stages[i] = -1;
|
||||
}
|
||||
|
||||
MTLRenderPipelineReflection *reflection = (__bridge MTLRenderPipelineReflection *)pipeline->impl._reflection;
|
||||
for (MTLArgument *arg in reflection.fragmentArguments) {
|
||||
if ([arg type] == MTLArgumentTypeTexture && strcmp([[arg name] UTF8String], name) == 0) {
|
||||
unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] = (int)[arg index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (MTLArgument *arg in reflection.vertexArguments) {
|
||||
if ([arg type] == MTLArgumentTypeTexture && strcmp([[arg name] UTF8String], name) == 0) {
|
||||
unit.stages[KINC_G5_SHADER_TYPE_VERTEX] = (int)[arg index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
void *_raytracingPipeline;
|
||||
} kinc_raytrace_pipeline_impl_t;
|
||||
|
||||
typedef struct {
|
||||
void *_accelerationStructure;
|
||||
} kinc_raytrace_acceleration_structure_impl_t;
|
@ -0,0 +1,174 @@
|
||||
#include <kinc/backend/graphics5/raytrace.h>
|
||||
#include <kinc/graphics5/commandlist.h>
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
#include <kinc/graphics5/raytrace.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
|
||||
static kinc_raytrace_acceleration_structure_t *accel;
|
||||
static kinc_raytrace_pipeline_t *pipeline;
|
||||
static kinc_g5_texture_t *output = NULL;
|
||||
static kinc_g5_constant_buffer_t *constant_buf;
|
||||
|
||||
id getMetalDevice(void);
|
||||
id getMetalQueue(void);
|
||||
|
||||
id<MTLComputePipelineState> _raytracing_pipeline;
|
||||
NSMutableArray *_primitive_accels;
|
||||
id<MTLAccelerationStructure> _instance_accel;
|
||||
dispatch_semaphore_t _sem;
|
||||
|
||||
void kinc_raytrace_pipeline_init(kinc_raytrace_pipeline_t *pipeline, kinc_g5_command_list_t *command_list, void *ray_shader, int ray_shader_size,
|
||||
kinc_g5_constant_buffer_t *constant_buffer) {
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
constant_buf = constant_buffer;
|
||||
|
||||
NSError *error = nil;
|
||||
id<MTLLibrary> library = [device newLibraryWithSource:[[NSString alloc] initWithBytes:ray_shader length:ray_shader_size encoding:NSUTF8StringEncoding]
|
||||
options:nil
|
||||
error:&error];
|
||||
if (library == nil) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "%s", error.localizedDescription.UTF8String);
|
||||
}
|
||||
|
||||
MTLComputePipelineDescriptor *descriptor = [[MTLComputePipelineDescriptor alloc] init];
|
||||
descriptor.computeFunction = [library newFunctionWithName:@"raytracingKernel"];
|
||||
descriptor.threadGroupSizeIsMultipleOfThreadExecutionWidth = YES;
|
||||
_raytracing_pipeline = [device newComputePipelineStateWithDescriptor:descriptor options:0 reflection:nil error:&error];
|
||||
_sem = dispatch_semaphore_create(2);
|
||||
}
|
||||
|
||||
void kinc_raytrace_pipeline_destroy(kinc_raytrace_pipeline_t *pipeline) {}
|
||||
|
||||
id<MTLAccelerationStructure> create_acceleration_sctructure(MTLAccelerationStructureDescriptor *descriptor) {
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
id<MTLCommandQueue> queue = getMetalQueue();
|
||||
|
||||
MTLAccelerationStructureSizes accel_sizes = [device accelerationStructureSizesWithDescriptor:descriptor];
|
||||
id<MTLAccelerationStructure> acceleration_structure = [device newAccelerationStructureWithSize:accel_sizes.accelerationStructureSize];
|
||||
|
||||
id<MTLBuffer> scratch_buffer = [device newBufferWithLength:accel_sizes.buildScratchBufferSize options:MTLResourceStorageModePrivate];
|
||||
id<MTLCommandBuffer> command_buffer = [queue commandBuffer];
|
||||
id<MTLAccelerationStructureCommandEncoder> command_encoder = [command_buffer accelerationStructureCommandEncoder];
|
||||
id<MTLBuffer> compacteds_size_buffer = [device newBufferWithLength:sizeof(uint32_t) options:MTLResourceStorageModeShared];
|
||||
|
||||
[command_encoder buildAccelerationStructure:acceleration_structure descriptor:descriptor scratchBuffer:scratch_buffer scratchBufferOffset:0];
|
||||
|
||||
[command_encoder writeCompactedAccelerationStructureSize:acceleration_structure toBuffer:compacteds_size_buffer offset:0];
|
||||
|
||||
[command_encoder endEncoding];
|
||||
[command_buffer commit];
|
||||
[command_buffer waitUntilCompleted];
|
||||
|
||||
uint32_t compacted_size = *(uint32_t *)compacteds_size_buffer.contents;
|
||||
id<MTLAccelerationStructure> compacted_acceleration_structure = [device newAccelerationStructureWithSize:compacted_size];
|
||||
command_buffer = [queue commandBuffer];
|
||||
command_encoder = [command_buffer accelerationStructureCommandEncoder];
|
||||
[command_encoder copyAndCompactAccelerationStructure:acceleration_structure toAccelerationStructure:compacted_acceleration_structure];
|
||||
[command_encoder endEncoding];
|
||||
[command_buffer commit];
|
||||
|
||||
return compacted_acceleration_structure;
|
||||
}
|
||||
|
||||
void kinc_raytrace_acceleration_structure_init(kinc_raytrace_acceleration_structure_t *accel, kinc_g5_command_list_t *command_list, kinc_g5_vertex_buffer_t *vb,
|
||||
kinc_g5_index_buffer_t *ib) {
|
||||
#if !TARGET_OS_IPHONE
|
||||
MTLResourceOptions options = MTLResourceStorageModeManaged;
|
||||
#else
|
||||
MTLResourceOptions options = MTLResourceStorageModeShared;
|
||||
#endif
|
||||
|
||||
MTLAccelerationStructureTriangleGeometryDescriptor *descriptor = [MTLAccelerationStructureTriangleGeometryDescriptor descriptor];
|
||||
descriptor.indexType = MTLIndexTypeUInt32;
|
||||
descriptor.indexBuffer = (__bridge id<MTLBuffer>)ib->impl.metal_buffer;
|
||||
descriptor.vertexBuffer = (__bridge id<MTLBuffer>)vb->impl.mtlBuffer;
|
||||
descriptor.vertexStride = vb->impl.myStride;
|
||||
descriptor.triangleCount = ib->impl.count / 3;
|
||||
|
||||
MTLPrimitiveAccelerationStructureDescriptor *accel_descriptor = [MTLPrimitiveAccelerationStructureDescriptor descriptor];
|
||||
accel_descriptor.geometryDescriptors = @[ descriptor ];
|
||||
id<MTLAccelerationStructure> acceleration_structure = create_acceleration_sctructure(accel_descriptor);
|
||||
_primitive_accels = [[NSMutableArray alloc] init];
|
||||
[_primitive_accels addObject:acceleration_structure];
|
||||
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
id<MTLBuffer> instance_buffer = [device newBufferWithLength:sizeof(MTLAccelerationStructureInstanceDescriptor) * 1 options:options];
|
||||
|
||||
MTLAccelerationStructureInstanceDescriptor *instance_descriptors = (MTLAccelerationStructureInstanceDescriptor *)instance_buffer.contents;
|
||||
instance_descriptors[0].accelerationStructureIndex = 0;
|
||||
instance_descriptors[0].options = MTLAccelerationStructureInstanceOptionOpaque;
|
||||
instance_descriptors[0].mask = 1;
|
||||
instance_descriptors[0].transformationMatrix.columns[0] = MTLPackedFloat3Make(1, 0, 0);
|
||||
instance_descriptors[0].transformationMatrix.columns[1] = MTLPackedFloat3Make(0, 1, 0);
|
||||
instance_descriptors[0].transformationMatrix.columns[2] = MTLPackedFloat3Make(0, 0, 1);
|
||||
instance_descriptors[0].transformationMatrix.columns[3] = MTLPackedFloat3Make(0, 0, 0);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
[instance_buffer didModifyRange:NSMakeRange(0, instance_buffer.length)];
|
||||
#endif
|
||||
|
||||
MTLInstanceAccelerationStructureDescriptor *inst_accel_descriptor = [MTLInstanceAccelerationStructureDescriptor descriptor];
|
||||
inst_accel_descriptor.instancedAccelerationStructures = _primitive_accels;
|
||||
inst_accel_descriptor.instanceCount = 1;
|
||||
inst_accel_descriptor.instanceDescriptorBuffer = instance_buffer;
|
||||
_instance_accel = create_acceleration_sctructure(inst_accel_descriptor);
|
||||
}
|
||||
|
||||
void kinc_raytrace_acceleration_structure_destroy(kinc_raytrace_acceleration_structure_t *accel) {}
|
||||
|
||||
void kinc_raytrace_set_acceleration_structure(kinc_raytrace_acceleration_structure_t *_accel) {
|
||||
accel = _accel;
|
||||
}
|
||||
|
||||
void kinc_raytrace_set_pipeline(kinc_raytrace_pipeline_t *_pipeline) {
|
||||
pipeline = _pipeline;
|
||||
}
|
||||
|
||||
void kinc_raytrace_set_target(kinc_g5_texture_t *_output) {
|
||||
output = _output;
|
||||
}
|
||||
|
||||
void kinc_raytrace_dispatch_rays(kinc_g5_command_list_t *command_list) {
|
||||
dispatch_semaphore_wait(_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
id<MTLCommandQueue> queue = getMetalQueue();
|
||||
id<MTLCommandBuffer> command_buffer = [queue commandBuffer];
|
||||
__block dispatch_semaphore_t sem = _sem;
|
||||
[command_buffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
|
||||
dispatch_semaphore_signal(sem);
|
||||
}];
|
||||
|
||||
NSUInteger width = output->texWidth;
|
||||
NSUInteger height = output->texHeight;
|
||||
MTLSize threads_per_threadgroup = MTLSizeMake(8, 8, 1);
|
||||
MTLSize threadgroups = MTLSizeMake((width + threads_per_threadgroup.width - 1) / threads_per_threadgroup.width,
|
||||
(height + threads_per_threadgroup.height - 1) / threads_per_threadgroup.height, 1);
|
||||
|
||||
id<MTLComputeCommandEncoder> compute_encoder = [command_buffer computeCommandEncoder];
|
||||
[compute_encoder setBuffer:(__bridge id<MTLBuffer>)constant_buf->impl._buffer offset:0 atIndex:0];
|
||||
[compute_encoder setAccelerationStructure:_instance_accel atBufferIndex:1];
|
||||
[compute_encoder setTexture:(__bridge id<MTLTexture>)output->impl._tex atIndex:0];
|
||||
|
||||
for (id<MTLAccelerationStructure> primitive_accel in _primitive_accels)
|
||||
[compute_encoder useResource:primitive_accel usage:MTLResourceUsageRead];
|
||||
|
||||
[compute_encoder setComputePipelineState:_raytracing_pipeline];
|
||||
[compute_encoder dispatchThreadgroups:threadgroups threadsPerThreadgroup:threads_per_threadgroup];
|
||||
[compute_encoder endEncoding];
|
||||
[command_buffer commit];
|
||||
}
|
||||
|
||||
void kinc_raytrace_copy(kinc_g5_command_list_t *command_list, kinc_g5_render_target_t *target, kinc_g5_texture_t *source) {
|
||||
id<MTLCommandQueue> queue = getMetalQueue();
|
||||
id<MTLCommandBuffer> command_buffer = [queue commandBuffer];
|
||||
id<MTLBlitCommandEncoder> command_encoder = [command_buffer blitCommandEncoder];
|
||||
[command_encoder copyFromTexture:(__bridge id<MTLTexture>)source->impl._tex toTexture:(__bridge id<MTLTexture>)target->impl._tex];
|
||||
#ifndef KINC_APPLE_SOC
|
||||
[command_encoder synchronizeResource:(__bridge id<MTLTexture>)target->impl._tex];
|
||||
#endif
|
||||
[command_encoder endEncoding];
|
||||
[command_buffer commit];
|
||||
[command_buffer waitUntilCompleted];
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
void *_tex;
|
||||
void *_texReadback;
|
||||
void *_depthTex;
|
||||
} RenderTarget5Impl;
|
@ -0,0 +1,164 @@
|
||||
#include <kinc/graphics5/rendertarget.h>
|
||||
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/rendertarget.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
id getMetalEncoder(void);
|
||||
|
||||
static MTLPixelFormat convert_format(kinc_g5_render_target_format_t format) {
|
||||
switch (format) {
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_128BIT_FLOAT:
|
||||
return MTLPixelFormatRGBA32Float;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_64BIT_FLOAT:
|
||||
return MTLPixelFormatRGBA16Float;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT:
|
||||
return MTLPixelFormatR32Float;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT:
|
||||
return MTLPixelFormatR16Float;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_8BIT_RED:
|
||||
return MTLPixelFormatR8Unorm;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_32BIT:
|
||||
default:
|
||||
return MTLPixelFormatBGRA8Unorm;
|
||||
}
|
||||
}
|
||||
|
||||
static void render_target_init(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, int framebuffer_index) {
|
||||
memset(target, 0, sizeof(kinc_g5_render_target_t));
|
||||
|
||||
target->texWidth = width;
|
||||
target->texHeight = height;
|
||||
|
||||
target->framebuffer_index = framebuffer_index;
|
||||
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
|
||||
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor new];
|
||||
descriptor.textureType = MTLTextureType2D;
|
||||
descriptor.width = width;
|
||||
descriptor.height = height;
|
||||
descriptor.depth = 1;
|
||||
descriptor.pixelFormat = convert_format(format);
|
||||
descriptor.arrayLength = 1;
|
||||
descriptor.mipmapLevelCount = 1;
|
||||
descriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
descriptor.resourceOptions = MTLResourceStorageModePrivate;
|
||||
|
||||
target->impl._tex = (__bridge_retained void *)[device newTextureWithDescriptor:descriptor];
|
||||
|
||||
if (depthBufferBits > 0) {
|
||||
MTLTextureDescriptor *depthDescriptor = [MTLTextureDescriptor new];
|
||||
depthDescriptor.textureType = MTLTextureType2D;
|
||||
depthDescriptor.width = width;
|
||||
depthDescriptor.height = height;
|
||||
depthDescriptor.depth = 1;
|
||||
depthDescriptor.pixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
||||
depthDescriptor.arrayLength = 1;
|
||||
depthDescriptor.mipmapLevelCount = 1;
|
||||
depthDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
depthDescriptor.resourceOptions = MTLResourceStorageModePrivate;
|
||||
|
||||
target->impl._depthTex = (__bridge_retained void *)[device newTextureWithDescriptor:depthDescriptor];
|
||||
}
|
||||
|
||||
target->impl._texReadback = NULL;
|
||||
}
|
||||
|
||||
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 *target, int cubeMapSize, kinc_g5_render_target_format_t format,
|
||||
int depthBufferBits, int stencilBufferBits, int samples_per_pixel) {
|
||||
target->impl._tex = NULL;
|
||||
target->impl._depthTex = NULL;
|
||||
target->impl._texReadback = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_render_target_destroy(kinc_g5_render_target_t *target) {
|
||||
id<MTLTexture> tex = (__bridge_transfer id<MTLTexture>)target->impl._tex;
|
||||
tex = nil;
|
||||
target->impl._tex = NULL;
|
||||
|
||||
id<MTLTexture> depthTex = (__bridge_transfer id<MTLTexture>)target->impl._depthTex;
|
||||
depthTex = nil;
|
||||
target->impl._depthTex = NULL;
|
||||
|
||||
id<MTLTexture> texReadback = (__bridge_transfer id<MTLTexture>)target->impl._texReadback;
|
||||
texReadback = nil;
|
||||
target->impl._texReadback = NULL;
|
||||
|
||||
if (target->framebuffer_index >= 0) {
|
||||
framebuffer_count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void kinc_g5_set_render_target_descriptor(kinc_g5_render_target_t *renderTarget, kinc_g5_texture_descriptor_t descriptor) {
|
||||
MTLSamplerDescriptor* desc = (MTLSamplerDescriptor*) renderTarget->impl._samplerDesc;
|
||||
switch(descriptor.filter_minification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
desc.minFilter = MTLSamplerMinMagFilterNearest;
|
||||
break;
|
||||
default:
|
||||
desc.minFilter = MTLSamplerMinMagFilterLinear;
|
||||
}
|
||||
|
||||
switch(descriptor.filter_magnification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
desc.magFilter = MTLSamplerMinMagFilterNearest;
|
||||
break;
|
||||
default:
|
||||
desc.minFilter = MTLSamplerMinMagFilterLinear;
|
||||
}
|
||||
|
||||
switch(descriptor.addressing_u) {
|
||||
case KINC_G5_TEXTURE_ADDRESSING_REPEAT:
|
||||
desc.sAddressMode = MTLSamplerAddressModeRepeat;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_MIRROR:
|
||||
desc.sAddressMode = MTLSamplerAddressModeMirrorRepeat;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_CLAMP:
|
||||
desc.sAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_BORDER:
|
||||
desc.sAddressMode = MTLSamplerAddressModeClampToBorderColor;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(descriptor.addressing_v) {
|
||||
case KINC_G5_TEXTURE_ADDRESSING_REPEAT:
|
||||
desc.tAddressMode = MTLSamplerAddressModeRepeat;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_MIRROR:
|
||||
desc.tAddressMode = MTLSamplerAddressModeMirrorRepeat;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_CLAMP:
|
||||
desc.tAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_BORDER:
|
||||
desc.tAddressMode = MTLSamplerAddressModeClampToBorderColor;
|
||||
break;
|
||||
}
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
renderTarget->impl._sampler = [device newSamplerStateWithDescriptor:desc];
|
||||
}
|
||||
#endif
|
||||
|
||||
void kinc_g5_render_target_set_depth_stencil_from(kinc_g5_render_target_t *target, kinc_g5_render_target_t *source) {
|
||||
target->impl._depthTex = source->impl._depthTex;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct kinc_g5_sampler_impl {
|
||||
void *sampler;
|
||||
} kinc_g5_sampler_impl_t;
|
@ -0,0 +1,67 @@
|
||||
#include <kinc/graphics5/sampler.h>
|
||||
|
||||
static MTLSamplerAddressMode convert_addressing(kinc_g5_texture_addressing_t mode) {
|
||||
switch (mode) {
|
||||
case KINC_G5_TEXTURE_ADDRESSING_REPEAT:
|
||||
return MTLSamplerAddressModeRepeat;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_BORDER:
|
||||
return MTLSamplerAddressModeClampToBorderColor;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_CLAMP:
|
||||
return MTLSamplerAddressModeClampToEdge;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_MIRROR:
|
||||
return MTLSamplerAddressModeMirrorRepeat;
|
||||
default:
|
||||
assert(false);
|
||||
return MTLSamplerAddressModeRepeat;
|
||||
}
|
||||
}
|
||||
|
||||
static MTLSamplerMipFilter convert_mipmap_mode(kinc_g5_mipmap_filter_t filter) {
|
||||
switch (filter) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
return MTLSamplerMipFilterNotMipmapped;
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return MTLSamplerMipFilterNearest;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return MTLSamplerMipFilterLinear;
|
||||
default:
|
||||
assert(false);
|
||||
return MTLSamplerMipFilterNearest;
|
||||
}
|
||||
}
|
||||
|
||||
static MTLSamplerMinMagFilter convert_texture_filter(kinc_g5_texture_filter_t filter) {
|
||||
switch (filter) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
return MTLSamplerMinMagFilterNearest;
|
||||
case KINC_G5_TEXTURE_FILTER_LINEAR:
|
||||
return MTLSamplerMinMagFilterLinear;
|
||||
case KINC_G5_TEXTURE_FILTER_ANISOTROPIC:
|
||||
return MTLSamplerMinMagFilterLinear; // ?
|
||||
default:
|
||||
assert(false);
|
||||
return MTLSamplerMinMagFilterNearest;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_sampler_init(kinc_g5_sampler_t *sampler, const kinc_g5_sampler_options_t *options) {
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)[[MTLSamplerDescriptor alloc] init];
|
||||
desc.minFilter = convert_texture_filter(options->minification_filter);
|
||||
desc.magFilter = convert_texture_filter(options->magnification_filter);
|
||||
desc.sAddressMode = convert_addressing(options->u_addressing);
|
||||
desc.tAddressMode = convert_addressing(options->v_addressing);
|
||||
desc.mipFilter = convert_mipmap_mode(options->mipmap_filter);
|
||||
desc.maxAnisotropy = options->max_anisotropy;
|
||||
desc.normalizedCoordinates = YES;
|
||||
desc.lodMinClamp = options->lod_min_clamp;
|
||||
desc.lodMaxClamp = options->lod_max_clamp;
|
||||
|
||||
sampler->impl.sampler = (__bridge_retained void *)[device newSamplerStateWithDescriptor:desc];
|
||||
}
|
||||
|
||||
void kinc_g5_sampler_destroy(kinc_g5_sampler_t *sampler) {
|
||||
id<MTLSamplerState> mtl_sampler = (__bridge_transfer id<MTLSamplerState>)sampler->impl.sampler;
|
||||
mtl_sampler = nil;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
char name[1024];
|
||||
void *mtlFunction;
|
||||
} Shader5Impl;
|
@ -0,0 +1,61 @@
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/shader.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
#include <Metal/Metal.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
id getMetalLibrary(void);
|
||||
|
||||
void kinc_g5_shader_destroy(kinc_g5_shader_t *shader) {
|
||||
id<MTLFunction> function = (__bridge_transfer id<MTLFunction>)shader->impl.mtlFunction;
|
||||
function = nil;
|
||||
shader->impl.mtlFunction = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_shader_init(kinc_g5_shader_t *shader, const void *source, size_t length, kinc_g5_shader_type_t type) {
|
||||
#ifdef KINC_KONG
|
||||
strcpy(shader->impl.name, (const char *)source);
|
||||
shader->impl.mtlFunction = (__bridge_retained void *)[getMetalLibrary() newFunctionWithName:[NSString stringWithCString:shader->impl.name
|
||||
encoding:NSUTF8StringEncoding]];
|
||||
#else
|
||||
shader->impl.name[0] = 0;
|
||||
|
||||
{
|
||||
uint8_t *data = (uint8_t *)source;
|
||||
if (length > 1 && data[0] == '>') {
|
||||
memcpy(shader->impl.name, data + 1, length - 1);
|
||||
shader->impl.name[length - 1] = 0;
|
||||
}
|
||||
else {
|
||||
for (int i = 3; i < length; ++i) {
|
||||
if (data[i] == '\n') {
|
||||
shader->impl.name[i - 3] = 0;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
shader->impl.name[i - 3] = data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *data = (char *)source;
|
||||
id<MTLLibrary> library = nil;
|
||||
if (length > 1 && data[0] == '>') {
|
||||
library = getMetalLibrary();
|
||||
}
|
||||
else {
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
NSError *error = nil;
|
||||
library = [device newLibraryWithSource:[[NSString alloc] initWithBytes:data length:length encoding:NSUTF8StringEncoding] options:nil error:&error];
|
||||
if (library == nil) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "%s", error.localizedDescription.UTF8String);
|
||||
}
|
||||
}
|
||||
shader->impl.mtlFunction = (__bridge_retained void *)[library newFunctionWithName:[NSString stringWithCString:shader->impl.name
|
||||
encoding:NSUTF8StringEncoding]];
|
||||
#endif
|
||||
assert(shader->impl.mtlFunction);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/image.h>
|
||||
|
||||
typedef struct {
|
||||
int index;
|
||||
bool vertex;
|
||||
} TextureUnit5Impl;
|
||||
|
||||
typedef struct {
|
||||
void *_tex;
|
||||
void *data;
|
||||
bool has_mipmaps;
|
||||
} Texture5Impl;
|
@ -0,0 +1,291 @@
|
||||
#include <kinc/graphics5/texture.h>
|
||||
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/texture.h>
|
||||
#include <kinc/image.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
|
||||
static MTLPixelFormat convert_image_format(kinc_image_format_t format) {
|
||||
switch (format) {
|
||||
case KINC_IMAGE_FORMAT_RGBA32:
|
||||
return MTLPixelFormatRGBA8Unorm;
|
||||
case KINC_IMAGE_FORMAT_GREY8:
|
||||
return MTLPixelFormatR8Unorm;
|
||||
case KINC_IMAGE_FORMAT_RGB24:
|
||||
return MTLPixelFormatRGBA8Unorm;
|
||||
case KINC_IMAGE_FORMAT_RGBA128:
|
||||
return MTLPixelFormatRGBA32Float;
|
||||
case KINC_IMAGE_FORMAT_RGBA64:
|
||||
return MTLPixelFormatRGBA16Float;
|
||||
case KINC_IMAGE_FORMAT_A32:
|
||||
return MTLPixelFormatR32Float;
|
||||
case KINC_IMAGE_FORMAT_BGRA32:
|
||||
return MTLPixelFormatBGRA8Unorm;
|
||||
case KINC_IMAGE_FORMAT_A16:
|
||||
return MTLPixelFormatR16Float;
|
||||
}
|
||||
}
|
||||
|
||||
static int formatByteSize(kinc_image_format_t format) {
|
||||
switch (format) {
|
||||
case KINC_IMAGE_FORMAT_RGBA128:
|
||||
return 16;
|
||||
case KINC_IMAGE_FORMAT_RGBA64:
|
||||
return 8;
|
||||
case KINC_IMAGE_FORMAT_RGB24:
|
||||
return 4;
|
||||
case KINC_IMAGE_FORMAT_A32:
|
||||
return 4;
|
||||
case KINC_IMAGE_FORMAT_A16:
|
||||
return 2;
|
||||
case KINC_IMAGE_FORMAT_GREY8:
|
||||
return 1;
|
||||
case KINC_IMAGE_FORMAT_BGRA32:
|
||||
case KINC_IMAGE_FORMAT_RGBA32:
|
||||
return 4;
|
||||
default:
|
||||
assert(false);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void create(kinc_g5_texture_t *texture, int width, int height, int format, bool writable) {
|
||||
texture->impl.has_mipmaps = false;
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
|
||||
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:convert_image_format((kinc_image_format_t)format)
|
||||
width:width
|
||||
height:height
|
||||
mipmapped:NO];
|
||||
descriptor.textureType = MTLTextureType2D;
|
||||
descriptor.width = width;
|
||||
descriptor.height = height;
|
||||
descriptor.depth = 1;
|
||||
descriptor.pixelFormat = convert_image_format((kinc_image_format_t)format);
|
||||
descriptor.arrayLength = 1;
|
||||
descriptor.mipmapLevelCount = 1;
|
||||
// TODO: Make less textures writable
|
||||
if (writable) {
|
||||
descriptor.usage = MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead;
|
||||
}
|
||||
|
||||
texture->impl._tex = (__bridge_retained void *)[device newTextureWithDescriptor:descriptor];
|
||||
}
|
||||
|
||||
/*void Graphics5::Texture::_init(const char* format, bool readable) {
|
||||
texWidth = width;
|
||||
texHeight = height;
|
||||
|
||||
create(width, height, Image::RGBA32, false);
|
||||
lock();
|
||||
unlock();
|
||||
}*/
|
||||
|
||||
void kinc_g5_texture_init(kinc_g5_texture_t *texture, int width, int height, kinc_image_format_t format) {
|
||||
// Image(width, height, format, readable);
|
||||
texture->texWidth = width;
|
||||
texture->texHeight = height;
|
||||
texture->format = format;
|
||||
texture->impl.data = malloc(width * height * (format == KINC_IMAGE_FORMAT_GREY8 ? 1 : 4));
|
||||
create(texture, width, height, format, true);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_init3d(kinc_g5_texture_t *texture, int width, int height, int depth, kinc_image_format_t format) {}
|
||||
|
||||
void kinc_g5_texture_init_from_image(kinc_g5_texture_t *texture, struct kinc_image *image) {
|
||||
texture->texWidth = image->width;
|
||||
texture->texHeight = image->height;
|
||||
texture->format = image->format;
|
||||
texture->impl.data = NULL;
|
||||
create(texture, image->width, image->height, image->format, true);
|
||||
id<MTLTexture> tex = (__bridge id<MTLTexture>)texture->impl._tex;
|
||||
[tex replaceRegion:MTLRegionMake2D(0, 0, texture->texWidth, texture->texHeight)
|
||||
mipmapLevel:0
|
||||
slice:0
|
||||
withBytes:image->data
|
||||
bytesPerRow:kinc_g5_texture_stride(texture)
|
||||
bytesPerImage:kinc_g5_texture_stride(texture) * texture->texHeight];
|
||||
}
|
||||
|
||||
void kinc_g5_texture_init_non_sampled_access(kinc_g5_texture_t *texture, int width, int height, kinc_image_format_t format) {
|
||||
texture->texWidth = width;
|
||||
texture->texHeight = height;
|
||||
texture->format = format;
|
||||
texture->impl.data = malloc(width * height * (format == KINC_IMAGE_FORMAT_GREY8 ? 1 : 4));
|
||||
create(texture, width, height, format, true);
|
||||
}
|
||||
|
||||
void kinc_g5_texture_destroy(kinc_g5_texture_t *texture) {
|
||||
id<MTLTexture> tex = (__bridge_transfer id<MTLTexture>)texture->impl._tex;
|
||||
tex = nil;
|
||||
texture->impl._tex = NULL;
|
||||
|
||||
if (texture->impl.data != NULL) {
|
||||
free(texture->impl.data);
|
||||
texture->impl.data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
id getMetalDevice(void);
|
||||
id getMetalEncoder(void);
|
||||
|
||||
#if 0
|
||||
void kinc_g5_internal_set_texture_descriptor(kinc_g5_texture_t *texture, kinc_g5_texture_descriptor_t descriptor) {
|
||||
MTLSamplerDescriptor* desc = (MTLSamplerDescriptor*) texture->impl._samplerDesc;
|
||||
switch(descriptor.filter_minification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
desc.minFilter = MTLSamplerMinMagFilterNearest;
|
||||
break;
|
||||
default:
|
||||
desc.minFilter = MTLSamplerMinMagFilterLinear;
|
||||
}
|
||||
|
||||
switch(descriptor.filter_magnification) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
desc.magFilter = MTLSamplerMinMagFilterNearest;
|
||||
break;
|
||||
default:
|
||||
desc.minFilter = MTLSamplerMinMagFilterLinear;
|
||||
}
|
||||
|
||||
switch(descriptor.addressing_u) {
|
||||
case KINC_G5_TEXTURE_ADDRESSING_REPEAT:
|
||||
desc.sAddressMode = MTLSamplerAddressModeRepeat;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_MIRROR:
|
||||
desc.sAddressMode = MTLSamplerAddressModeMirrorRepeat;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_CLAMP:
|
||||
desc.sAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_BORDER:
|
||||
desc.sAddressMode = MTLSamplerAddressModeClampToBorderColor;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(descriptor.addressing_v) {
|
||||
case KINC_G5_TEXTURE_ADDRESSING_REPEAT:
|
||||
desc.tAddressMode = MTLSamplerAddressModeRepeat;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_MIRROR:
|
||||
desc.tAddressMode = MTLSamplerAddressModeMirrorRepeat;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_CLAMP:
|
||||
desc.tAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
break;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_BORDER:
|
||||
desc.tAddressMode = MTLSamplerAddressModeClampToBorderColor;
|
||||
break;
|
||||
}
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
texture->impl._sampler = [device newSamplerStateWithDescriptor:desc];
|
||||
}
|
||||
#endif
|
||||
|
||||
int kinc_g5_texture_stride(kinc_g5_texture_t *texture) {
|
||||
switch (texture->format) {
|
||||
case KINC_IMAGE_FORMAT_GREY8:
|
||||
return texture->texWidth;
|
||||
case KINC_IMAGE_FORMAT_RGBA32:
|
||||
case KINC_IMAGE_FORMAT_BGRA32:
|
||||
case KINC_IMAGE_FORMAT_RGB24:
|
||||
return texture->texWidth * 4;
|
||||
case KINC_IMAGE_FORMAT_RGBA64:
|
||||
return texture->texWidth * 8;
|
||||
case KINC_IMAGE_FORMAT_RGBA128:
|
||||
return texture->texWidth * 16;
|
||||
case KINC_IMAGE_FORMAT_A16:
|
||||
return texture->texWidth * 2;
|
||||
case KINC_IMAGE_FORMAT_A32:
|
||||
return texture->texWidth * 4;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *kinc_g5_texture_lock(kinc_g5_texture_t *texture) {
|
||||
return (uint8_t *)texture->impl.data;
|
||||
}
|
||||
|
||||
void kinc_g5_texture_unlock(kinc_g5_texture_t *tex) {
|
||||
id<MTLTexture> texture = (__bridge id<MTLTexture>)tex->impl._tex;
|
||||
[texture replaceRegion:MTLRegionMake2D(0, 0, tex->texWidth, tex->texHeight)
|
||||
mipmapLevel:0
|
||||
slice:0
|
||||
withBytes:tex->impl.data
|
||||
bytesPerRow:kinc_g5_texture_stride(tex)
|
||||
bytesPerImage:kinc_g5_texture_stride(tex) * tex->texHeight];
|
||||
}
|
||||
|
||||
void kinc_g5_texture_clear(kinc_g5_texture_t *texture, int x, int y, int z, int width, int height, int depth, unsigned color) {}
|
||||
|
||||
void kinc_g5_texture_generate_mipmaps(kinc_g5_texture_t *texture, int levels) {}
|
||||
|
||||
void kinc_g5_texture_set_mipmap(kinc_g5_texture_t *texture, kinc_image_t *mipmap, int level) {
|
||||
if (!texture->impl.has_mipmaps) {
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:convert_image_format((kinc_image_format_t)texture->format)
|
||||
width:texture->texWidth
|
||||
height:texture->texHeight
|
||||
mipmapped:YES];
|
||||
descriptor.textureType = MTLTextureType2D;
|
||||
descriptor.width = texture->texWidth;
|
||||
descriptor.height = texture->texHeight;
|
||||
descriptor.depth = 1;
|
||||
descriptor.pixelFormat = convert_image_format((kinc_image_format_t)texture->format);
|
||||
descriptor.arrayLength = 1;
|
||||
bool writable = true;
|
||||
if (writable) {
|
||||
descriptor.usage = MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead;
|
||||
}
|
||||
void *mipmaptex = (__bridge_retained void *)[device newTextureWithDescriptor:descriptor];
|
||||
|
||||
id<MTLCommandQueue> commandQueue = getMetalQueue();
|
||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
||||
id<MTLBlitCommandEncoder> commandEncoder = [commandBuffer blitCommandEncoder];
|
||||
[commandEncoder copyFromTexture:(__bridge id<MTLTexture>)texture->impl._tex
|
||||
sourceSlice:0
|
||||
sourceLevel:0
|
||||
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||
sourceSize:MTLSizeMake(texture->texWidth, texture->texHeight, 1)
|
||||
toTexture:(__bridge id<MTLTexture>)mipmaptex
|
||||
destinationSlice:0
|
||||
destinationLevel:0
|
||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||
#ifndef KINC_APPLE_SOC
|
||||
[commandEncoder synchronizeResource:(__bridge id<MTLTexture>)mipmaptex];
|
||||
#endif
|
||||
[commandEncoder endEncoding];
|
||||
[commandBuffer commit];
|
||||
[commandBuffer waitUntilCompleted];
|
||||
|
||||
id<MTLTexture> tex = (__bridge_transfer id<MTLTexture>)texture->impl._tex;
|
||||
tex = nil;
|
||||
texture->impl._tex = mipmaptex;
|
||||
|
||||
texture->impl.has_mipmaps = true;
|
||||
}
|
||||
|
||||
id<MTLTexture> tex = (__bridge id<MTLTexture>)texture->impl._tex;
|
||||
[tex replaceRegion:MTLRegionMake2D(0, 0, mipmap->width, mipmap->height)
|
||||
mipmapLevel:level
|
||||
withBytes:mipmap->data
|
||||
bytesPerRow:mipmap->width * formatByteSize(mipmap->format)];
|
||||
}
|
||||
|
||||
#include <kinc/graphics4/texture.h>
|
||||
|
||||
#if defined(KINC_IOS) || defined(KINC_MACOS)
|
||||
void kinc_g4_texture_upload(kinc_g4_texture_t *texture_g4, uint8_t *data, int stride) {
|
||||
kinc_g5_texture_t *tex = &texture_g4->impl._texture;
|
||||
id<MTLTexture> texture = (__bridge id<MTLTexture>)tex->impl._tex;
|
||||
[texture replaceRegion:MTLRegionMake2D(0, 0, tex->texWidth, tex->texHeight)
|
||||
mipmapLevel:0
|
||||
slice:0
|
||||
withBytes:data
|
||||
bytesPerRow:stride
|
||||
bytesPerImage:stride * tex->texHeight];
|
||||
}
|
||||
#endif
|
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/graphics5/vertexstructure.h>
|
||||
|
||||
typedef struct {
|
||||
// void unset();
|
||||
int myCount;
|
||||
int myStride;
|
||||
void *mtlBuffer;
|
||||
bool gpuMemory;
|
||||
int lastStart;
|
||||
int lastCount;
|
||||
// static Graphics5::VertexBuffer* current;
|
||||
} VertexBuffer5Impl;
|
@ -0,0 +1,111 @@
|
||||
#include <kinc/graphics5/shader.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
id getMetalDevice(void);
|
||||
id getMetalEncoder(void);
|
||||
|
||||
kinc_g5_vertex_buffer_t *currentVertexBuffer = NULL;
|
||||
|
||||
static void vertex_buffer_unset(kinc_g5_vertex_buffer_t *buffer) {
|
||||
if (currentVertexBuffer == buffer)
|
||||
currentVertexBuffer = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_init(kinc_g5_vertex_buffer_t *buffer, int count, kinc_g5_vertex_structure_t *structure, bool gpuMemory, int instanceDataStepRate) {
|
||||
memset(&buffer->impl, 0, sizeof(buffer->impl));
|
||||
buffer->impl.myCount = count;
|
||||
buffer->impl.gpuMemory = gpuMemory;
|
||||
for (int i = 0; i < structure->size; ++i) {
|
||||
kinc_g5_vertex_element_t element = structure->elements[i];
|
||||
buffer->impl.myStride += kinc_g4_vertex_data_size(element.data);
|
||||
}
|
||||
|
||||
id<MTLDevice> device = getMetalDevice();
|
||||
MTLResourceOptions options = MTLResourceCPUCacheModeWriteCombined;
|
||||
#ifdef KINC_APPLE_SOC
|
||||
options |= MTLResourceStorageModeShared;
|
||||
#else
|
||||
if (gpuMemory) {
|
||||
options |= MTLResourceStorageModeManaged;
|
||||
}
|
||||
else {
|
||||
options |= MTLResourceStorageModeShared;
|
||||
}
|
||||
#endif
|
||||
id<MTLBuffer> buf = [device newBufferWithLength:count * buffer->impl.myStride options:options];
|
||||
buffer->impl.mtlBuffer = (__bridge_retained void *)buf;
|
||||
|
||||
buffer->impl.lastStart = 0;
|
||||
buffer->impl.lastCount = 0;
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_destroy(kinc_g5_vertex_buffer_t *buf) {
|
||||
id<MTLBuffer> buffer = (__bridge_transfer id<MTLBuffer>)buf->impl.mtlBuffer;
|
||||
buffer = nil;
|
||||
buf->impl.mtlBuffer = NULL;
|
||||
vertex_buffer_unset(buf);
|
||||
}
|
||||
|
||||
float *kinc_g5_vertex_buffer_lock_all(kinc_g5_vertex_buffer_t *buf) {
|
||||
buf->impl.lastStart = 0;
|
||||
buf->impl.lastCount = kinc_g5_vertex_buffer_count(buf);
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)buf->impl.mtlBuffer;
|
||||
float *floats = (float *)[buffer contents];
|
||||
return floats;
|
||||
}
|
||||
|
||||
float *kinc_g5_vertex_buffer_lock(kinc_g5_vertex_buffer_t *buf, int start, int count) {
|
||||
buf->impl.lastStart = start;
|
||||
buf->impl.lastCount = count;
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)buf->impl.mtlBuffer;
|
||||
float *floats = (float *)[buffer contents];
|
||||
return &floats[start * buf->impl.myStride / sizeof(float)];
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_unlock_all(kinc_g5_vertex_buffer_t *buf) {
|
||||
#ifndef KINC_APPLE_SOC
|
||||
if (buf->impl.gpuMemory) {
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)buf->impl.mtlBuffer;
|
||||
NSRange range;
|
||||
range.location = buf->impl.lastStart * buf->impl.myStride;
|
||||
range.length = buf->impl.lastCount * buf->impl.myStride;
|
||||
[buffer didModifyRange:range];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void kinc_g5_vertex_buffer_unlock(kinc_g5_vertex_buffer_t *buf, int count) {
|
||||
#ifndef KINC_APPLE_SOC
|
||||
if (buf->impl.gpuMemory) {
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)buf->impl.mtlBuffer;
|
||||
NSRange range;
|
||||
range.location = buf->impl.lastStart * buf->impl.myStride;
|
||||
range.length = count * buf->impl.myStride;
|
||||
[buffer didModifyRange:range];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int kinc_g5_internal_vertex_buffer_set(kinc_g5_vertex_buffer_t *buf, int offset_) {
|
||||
currentVertexBuffer = buf;
|
||||
|
||||
id<MTLRenderCommandEncoder> encoder = getMetalEncoder();
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)buf->impl.mtlBuffer;
|
||||
[encoder setVertexBuffer:buffer offset:offset_ * buf->impl.myStride atIndex:0];
|
||||
|
||||
return offset_;
|
||||
}
|
||||
|
||||
int kinc_g5_vertex_buffer_count(kinc_g5_vertex_buffer_t *buffer) {
|
||||
return buffer->impl.myCount;
|
||||
}
|
||||
|
||||
int kinc_g5_vertex_buffer_stride(kinc_g5_vertex_buffer_t *buffer) {
|
||||
return buffer->impl.myStride;
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
@ -0,0 +1,11 @@
|
||||
#include "ShaderHash.h"
|
||||
|
||||
// djb2
|
||||
uint32_t kinc_internal_hash_name(unsigned char *str) {
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
while (c = *str++) {
|
||||
hash = hash * 33 ^ c;
|
||||
}
|
||||
return hash;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t hash;
|
||||
uint32_t index;
|
||||
} kinc_internal_hash_index_t;
|
||||
|
||||
uint32_t kinc_internal_hash_name(unsigned char *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,945 @@
|
||||
#include "kinc/graphics5/sampler.h"
|
||||
#include "vulkan.h"
|
||||
|
||||
#include <kinc/graphics5/commandlist.h>
|
||||
#include <kinc/graphics5/compute.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/window.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
extern kinc_g5_texture_t *vulkanTextures[16];
|
||||
extern kinc_g5_render_target_t *vulkanRenderTargets[16];
|
||||
VkDescriptorSet getDescriptorSet(void);
|
||||
static VkDescriptorSet get_compute_descriptor_set(void);
|
||||
bool memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
|
||||
void setImageLayout(VkCommandBuffer _buffer, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout);
|
||||
|
||||
VkRenderPassBeginInfo currentRenderPassBeginInfo;
|
||||
VkPipeline currentVulkanPipeline;
|
||||
kinc_g5_render_target_t *currentRenderTargets[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
|
||||
|
||||
static bool onBackBuffer = false;
|
||||
static uint32_t lastVertexConstantBufferOffset = 0;
|
||||
static uint32_t lastFragmentConstantBufferOffset = 0;
|
||||
static uint32_t lastComputeConstantBufferOffset = 0;
|
||||
static kinc_g5_pipeline_t *currentPipeline = NULL;
|
||||
static kinc_g5_compute_shader *current_compute_shader = NULL;
|
||||
static int mrtIndex = 0;
|
||||
static VkFramebuffer mrtFramebuffer[16];
|
||||
static VkRenderPass mrtRenderPass[16];
|
||||
|
||||
static bool in_render_pass = false;
|
||||
|
||||
static void endPass(kinc_g5_command_list_t *list) {
|
||||
if (in_render_pass) {
|
||||
vkCmdEndRenderPass(list->impl._buffer);
|
||||
in_render_pass = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
vulkanTextures[i] = NULL;
|
||||
vulkanRenderTargets[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int formatSize(VkFormat format) {
|
||||
switch (format) {
|
||||
case VK_FORMAT_R32G32B32A32_SFLOAT:
|
||||
return 16;
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT:
|
||||
return 8;
|
||||
case VK_FORMAT_R16_SFLOAT:
|
||||
return 2;
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
return 1;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
void set_image_layout(VkImage image, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkImageLayout new_image_layout) {
|
||||
VkResult err;
|
||||
|
||||
if (vk_ctx.setup_cmd == VK_NULL_HANDLE) {
|
||||
VkCommandBufferAllocateInfo cmd = {0};
|
||||
cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
cmd.pNext = NULL;
|
||||
cmd.commandPool = vk_ctx.cmd_pool;
|
||||
cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
cmd.commandBufferCount = 1;
|
||||
|
||||
err = vkAllocateCommandBuffers(vk_ctx.device, &cmd, &vk_ctx.setup_cmd);
|
||||
assert(!err);
|
||||
|
||||
VkCommandBufferBeginInfo cmd_buf_info = {0};
|
||||
cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
cmd_buf_info.pNext = NULL;
|
||||
cmd_buf_info.flags = 0;
|
||||
cmd_buf_info.pInheritanceInfo = NULL;
|
||||
|
||||
err = vkBeginCommandBuffer(vk_ctx.setup_cmd, &cmd_buf_info);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
VkImageMemoryBarrier image_memory_barrier = {0};
|
||||
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_memory_barrier.pNext = NULL;
|
||||
image_memory_barrier.srcAccessMask = 0;
|
||||
image_memory_barrier.dstAccessMask = 0;
|
||||
image_memory_barrier.oldLayout = old_image_layout;
|
||||
image_memory_barrier.newLayout = new_image_layout;
|
||||
image_memory_barrier.image = image;
|
||||
image_memory_barrier.subresourceRange.aspectMask = aspectMask;
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = 0;
|
||||
image_memory_barrier.subresourceRange.levelCount = 1;
|
||||
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
|
||||
image_memory_barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
if (old_image_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||
image_memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
}
|
||||
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
}
|
||||
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
// Make sure anything that was copying from this image has completed
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
}
|
||||
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
// Make sure any Copy or CPU writes to image are flushed
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
}
|
||||
if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(vk_ctx.setup_cmd, srcStageMask, dstStageMask, 0, 0, NULL, 0, NULL, 1, &image_memory_barrier);
|
||||
}
|
||||
|
||||
void setup_init_cmd() {
|
||||
if (vk_ctx.setup_cmd == VK_NULL_HANDLE) {
|
||||
VkCommandBufferAllocateInfo cmd = {0};
|
||||
cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
cmd.pNext = NULL;
|
||||
cmd.commandPool = vk_ctx.cmd_pool;
|
||||
cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
cmd.commandBufferCount = 1;
|
||||
|
||||
VkResult err = vkAllocateCommandBuffers(vk_ctx.device, &cmd, &vk_ctx.setup_cmd);
|
||||
assert(!err);
|
||||
|
||||
VkCommandBufferBeginInfo cmd_buf_info = {0};
|
||||
cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
cmd_buf_info.pNext = NULL;
|
||||
cmd_buf_info.flags = 0;
|
||||
cmd_buf_info.pInheritanceInfo = NULL;
|
||||
|
||||
err = vkBeginCommandBuffer(vk_ctx.setup_cmd, &cmd_buf_info);
|
||||
assert(!err);
|
||||
}
|
||||
}
|
||||
|
||||
void flush_init_cmd() {
|
||||
VkResult err;
|
||||
|
||||
if (vk_ctx.setup_cmd == VK_NULL_HANDLE)
|
||||
return;
|
||||
|
||||
err = vkEndCommandBuffer(vk_ctx.setup_cmd);
|
||||
assert(!err);
|
||||
|
||||
const VkCommandBuffer cmd_bufs[] = {vk_ctx.setup_cmd};
|
||||
VkFence nullFence = {VK_NULL_HANDLE};
|
||||
VkSubmitInfo submit_info = {0};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.pNext = NULL;
|
||||
submit_info.waitSemaphoreCount = 0;
|
||||
submit_info.pWaitSemaphores = NULL;
|
||||
submit_info.pWaitDstStageMask = NULL;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = cmd_bufs;
|
||||
submit_info.signalSemaphoreCount = 0;
|
||||
submit_info.pSignalSemaphores = NULL;
|
||||
|
||||
err = vkQueueSubmit(vk_ctx.queue, 1, &submit_info, nullFence);
|
||||
assert(!err);
|
||||
|
||||
err = vkQueueWaitIdle(vk_ctx.queue);
|
||||
assert(!err);
|
||||
|
||||
vkFreeCommandBuffers(vk_ctx.device, vk_ctx.cmd_pool, 1, cmd_bufs);
|
||||
vk_ctx.setup_cmd = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void set_viewport_and_scissor(kinc_g5_command_list_t *list) {
|
||||
VkViewport viewport;
|
||||
memset(&viewport, 0, sizeof(viewport));
|
||||
VkRect2D scissor;
|
||||
memset(&scissor, 0, sizeof(scissor));
|
||||
|
||||
if (currentRenderTargets[0] == NULL || currentRenderTargets[0]->framebuffer_index >= 0) {
|
||||
viewport.x = 0;
|
||||
viewport.y = (float)kinc_window_height(vk_ctx.current_window);
|
||||
viewport.width = (float)kinc_window_width(vk_ctx.current_window);
|
||||
viewport.height = -(float)kinc_window_height(vk_ctx.current_window);
|
||||
viewport.minDepth = (float)0.0f;
|
||||
viewport.maxDepth = (float)1.0f;
|
||||
scissor.extent.width = kinc_window_width(vk_ctx.current_window);
|
||||
scissor.extent.height = kinc_window_height(vk_ctx.current_window);
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
}
|
||||
else {
|
||||
viewport.x = 0;
|
||||
viewport.y = (float)currentRenderTargets[0]->height;
|
||||
viewport.width = (float)currentRenderTargets[0]->width;
|
||||
viewport.height = -(float)currentRenderTargets[0]->height;
|
||||
viewport.minDepth = (float)0.0f;
|
||||
viewport.maxDepth = (float)1.0f;
|
||||
scissor.extent.width = currentRenderTargets[0]->width;
|
||||
scissor.extent.height = currentRenderTargets[0]->height;
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
}
|
||||
|
||||
vkCmdSetViewport(list->impl._buffer, 0, 1, &viewport);
|
||||
vkCmdSetScissor(list->impl._buffer, 0, 1, &scissor);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_init(kinc_g5_command_list_t *list) {
|
||||
VkCommandBufferAllocateInfo cmd = {0};
|
||||
cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
cmd.pNext = NULL;
|
||||
cmd.commandPool = vk_ctx.cmd_pool;
|
||||
cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
cmd.commandBufferCount = 1;
|
||||
|
||||
VkResult err = vkAllocateCommandBuffers(vk_ctx.device, &cmd, &list->impl._buffer);
|
||||
assert(!err);
|
||||
|
||||
VkFenceCreateInfo fenceInfo = {0};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.pNext = NULL;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
err = vkCreateFence(vk_ctx.device, &fenceInfo, NULL, &list->impl.fence);
|
||||
assert(!err);
|
||||
|
||||
list->impl._indexCount = 0;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_destroy(kinc_g5_command_list_t *list) {
|
||||
vkFreeCommandBuffers(vk_ctx.device, vk_ctx.cmd_pool, 1, &list->impl._buffer);
|
||||
vkDestroyFence(vk_ctx.device, list->impl.fence, NULL);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_begin(kinc_g5_command_list_t *list) {
|
||||
VkResult err = vkWaitForFences(vk_ctx.device, 1, &list->impl.fence, VK_TRUE, UINT64_MAX);
|
||||
assert(!err);
|
||||
|
||||
vkResetCommandBuffer(list->impl._buffer, 0);
|
||||
VkCommandBufferBeginInfo cmd_buf_info = {0};
|
||||
cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
cmd_buf_info.pNext = NULL;
|
||||
cmd_buf_info.flags = 0;
|
||||
cmd_buf_info.pInheritanceInfo = NULL;
|
||||
|
||||
VkClearValue clear_values[2];
|
||||
memset(clear_values, 0, sizeof(VkClearValue) * 2);
|
||||
clear_values[0].color.float32[0] = 0.0f;
|
||||
clear_values[0].color.float32[1] = 0.0f;
|
||||
clear_values[0].color.float32[2] = 0.0f;
|
||||
clear_values[0].color.float32[3] = 1.0f;
|
||||
if (vk_ctx.windows[vk_ctx.current_window].depth_bits > 0) {
|
||||
clear_values[1].depthStencil.depth = 1.0;
|
||||
clear_values[1].depthStencil.stencil = 0;
|
||||
}
|
||||
|
||||
VkRenderPassBeginInfo rp_begin = {0};
|
||||
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
rp_begin.pNext = NULL;
|
||||
rp_begin.renderPass = vk_ctx.windows[vk_ctx.current_window].framebuffer_render_pass;
|
||||
rp_begin.framebuffer = vk_ctx.windows[vk_ctx.current_window].framebuffers[vk_ctx.windows[vk_ctx.current_window].current_image];
|
||||
rp_begin.renderArea.offset.x = 0;
|
||||
rp_begin.renderArea.offset.y = 0;
|
||||
rp_begin.renderArea.extent.width = vk_ctx.windows[vk_ctx.current_window].width;
|
||||
rp_begin.renderArea.extent.height = vk_ctx.windows[vk_ctx.current_window].height;
|
||||
rp_begin.clearValueCount = vk_ctx.windows[vk_ctx.current_window].depth_bits > 0 ? 2 : 1;
|
||||
rp_begin.pClearValues = clear_values;
|
||||
|
||||
err = vkBeginCommandBuffer(list->impl._buffer, &cmd_buf_info);
|
||||
assert(!err);
|
||||
|
||||
VkImageMemoryBarrier prePresentBarrier = {0};
|
||||
prePresentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
prePresentBarrier.pNext = NULL;
|
||||
prePresentBarrier.srcAccessMask = 0;
|
||||
prePresentBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
prePresentBarrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
prePresentBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
prePresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
prePresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
prePresentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
prePresentBarrier.subresourceRange.baseMipLevel = 0;
|
||||
prePresentBarrier.subresourceRange.levelCount = 1;
|
||||
prePresentBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
prePresentBarrier.subresourceRange.layerCount = 1;
|
||||
|
||||
prePresentBarrier.image = vk_ctx.windows[vk_ctx.current_window].images[vk_ctx.windows[vk_ctx.current_window].current_image];
|
||||
VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier;
|
||||
vkCmdPipelineBarrier(list->impl._buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1,
|
||||
pmemory_barrier);
|
||||
|
||||
vkCmdBeginRenderPass(list->impl._buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
currentRenderPassBeginInfo = rp_begin;
|
||||
in_render_pass = true;
|
||||
|
||||
set_viewport_and_scissor(list);
|
||||
|
||||
onBackBuffer = true;
|
||||
|
||||
for (int i = 0; i < mrtIndex; ++i) {
|
||||
vkDestroyFramebuffer(vk_ctx.device, mrtFramebuffer[i], NULL);
|
||||
vkDestroyRenderPass(vk_ctx.device, mrtRenderPass[i], NULL);
|
||||
}
|
||||
mrtIndex = 0;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_end(kinc_g5_command_list_t *list) {
|
||||
vkCmdEndRenderPass(list->impl._buffer);
|
||||
|
||||
VkImageMemoryBarrier prePresentBarrier = {0};
|
||||
prePresentBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
prePresentBarrier.pNext = NULL;
|
||||
prePresentBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
prePresentBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
prePresentBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
prePresentBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
prePresentBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
prePresentBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
prePresentBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
prePresentBarrier.subresourceRange.baseMipLevel = 0;
|
||||
prePresentBarrier.subresourceRange.levelCount = 1;
|
||||
prePresentBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
prePresentBarrier.subresourceRange.layerCount = 1;
|
||||
|
||||
prePresentBarrier.image = vk_ctx.windows[vk_ctx.current_window].images[vk_ctx.windows[vk_ctx.current_window].current_image];
|
||||
VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier;
|
||||
vkCmdPipelineBarrier(list->impl._buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, pmemory_barrier);
|
||||
|
||||
VkResult err = vkEndCommandBuffer(list->impl._buffer);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_clear(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget, unsigned flags, unsigned color, float depth,
|
||||
int stencil) {
|
||||
VkClearRect clearRect = {0};
|
||||
clearRect.rect.offset.x = 0;
|
||||
clearRect.rect.offset.y = 0;
|
||||
clearRect.rect.extent.width = renderTarget->width;
|
||||
clearRect.rect.extent.height = renderTarget->height;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = 1;
|
||||
|
||||
int count = 0;
|
||||
VkClearAttachment attachments[2];
|
||||
if (flags & KINC_G5_CLEAR_COLOR) {
|
||||
VkClearColorValue clearColor = {0};
|
||||
clearColor.float32[0] = ((color & 0x00ff0000) >> 16) / 255.0f;
|
||||
clearColor.float32[1] = ((color & 0x0000ff00) >> 8) / 255.0f;
|
||||
clearColor.float32[2] = (color & 0x000000ff) / 255.0f;
|
||||
clearColor.float32[3] = ((color & 0xff000000) >> 24) / 255.0f;
|
||||
attachments[count].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
attachments[count].colorAttachment = 0;
|
||||
attachments[count].clearValue.color = clearColor;
|
||||
count++;
|
||||
}
|
||||
if (((flags & KINC_G5_CLEAR_DEPTH) || (flags & KINC_G5_CLEAR_STENCIL)) && renderTarget->impl.depthBufferBits > 0) {
|
||||
attachments[count].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; // | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
attachments[count].clearValue.depthStencil.depth = depth;
|
||||
attachments[count].clearValue.depthStencil.stencil = stencil;
|
||||
count++;
|
||||
}
|
||||
vkCmdClearAttachments(list->impl._buffer, count, attachments, 1, &clearRect);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_render_target_to_framebuffer_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
|
||||
void kinc_g5_command_list_framebuffer_to_render_target_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices(kinc_g5_command_list_t *list) {
|
||||
kinc_g5_command_list_draw_indexed_vertices_from_to(list, 0, list->impl._indexCount);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_from_to(kinc_g5_command_list_t *list, int start, int count) {
|
||||
vkCmdDrawIndexed(list->impl._buffer, count, 1, start, 0, 0);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_from_to_from(kinc_g5_command_list_t *list, int start, int count, int vertex_offset) {
|
||||
vkCmdDrawIndexed(list->impl._buffer, count, 1, start, vertex_offset, 0);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_instanced(kinc_g5_command_list_t *list, int instanceCount) {
|
||||
kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(list, instanceCount, 0, list->impl._indexCount);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(kinc_g5_command_list_t *list, int instanceCount, int start, int count) {
|
||||
vkCmdDrawIndexed(list->impl._buffer, count, instanceCount, start, 0, 0);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_viewport(kinc_g5_command_list_t *list, int x, int y, int width, int height) {
|
||||
VkViewport viewport;
|
||||
memset(&viewport, 0, sizeof(viewport));
|
||||
viewport.x = (float)x;
|
||||
viewport.y = y + (float)height;
|
||||
viewport.width = (float)width;
|
||||
viewport.height = (float)-height;
|
||||
viewport.minDepth = (float)0.0f;
|
||||
viewport.maxDepth = (float)1.0f;
|
||||
vkCmdSetViewport(list->impl._buffer, 0, 1, &viewport);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_scissor(kinc_g5_command_list_t *list, int x, int y, int width, int height) {
|
||||
VkRect2D scissor;
|
||||
memset(&scissor, 0, sizeof(scissor));
|
||||
scissor.extent.width = width;
|
||||
scissor.extent.height = height;
|
||||
scissor.offset.x = x;
|
||||
scissor.offset.y = y;
|
||||
vkCmdSetScissor(list->impl._buffer, 0, 1, &scissor);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_disable_scissor(kinc_g5_command_list_t *list) {
|
||||
VkRect2D scissor;
|
||||
memset(&scissor, 0, sizeof(scissor));
|
||||
if (currentRenderTargets[0] == NULL || currentRenderTargets[0]->framebuffer_index >= 0) {
|
||||
scissor.extent.width = kinc_window_width(vk_ctx.current_window);
|
||||
scissor.extent.height = kinc_window_height(vk_ctx.current_window);
|
||||
}
|
||||
else {
|
||||
scissor.extent.width = currentRenderTargets[0]->width;
|
||||
scissor.extent.height = currentRenderTargets[0]->height;
|
||||
}
|
||||
vkCmdSetScissor(list->impl._buffer, 0, 1, &scissor);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_pipeline(kinc_g5_command_list_t *list, struct kinc_g5_pipeline *pipeline) {
|
||||
currentPipeline = pipeline;
|
||||
lastVertexConstantBufferOffset = 0;
|
||||
lastFragmentConstantBufferOffset = 0;
|
||||
|
||||
if (onBackBuffer) {
|
||||
currentVulkanPipeline = currentPipeline->impl.framebuffer_pipeline;
|
||||
vkCmdBindPipeline(list->impl._buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, currentPipeline->impl.framebuffer_pipeline);
|
||||
}
|
||||
else {
|
||||
currentVulkanPipeline = currentPipeline->impl.rendertarget_pipeline;
|
||||
vkCmdBindPipeline(list->impl._buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, currentPipeline->impl.rendertarget_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_blend_constant(kinc_g5_command_list_t *list, float r, float g, float b, float a) {
|
||||
const float blendConstants[4] = {r, g, b, a};
|
||||
vkCmdSetBlendConstants(list->impl._buffer, blendConstants);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_vertex_buffers(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer **vertexBuffers, int *offsets_, int count) {
|
||||
// this seems to be a no-op function?
|
||||
// kinc_g5_internal_vertex_buffer_set(vertexBuffers[0], 0);
|
||||
#ifdef KINC_WINDOWS
|
||||
VkBuffer *buffers = (VkBuffer *)alloca(sizeof(VkBuffer) * count);
|
||||
VkDeviceSize *offsets = (VkDeviceSize *)alloca(sizeof(VkDeviceSize) * count);
|
||||
#else
|
||||
VkBuffer buffers[count];
|
||||
VkDeviceSize offsets[count];
|
||||
#endif
|
||||
for (int i = 0; i < count; ++i) {
|
||||
buffers[i] = vertexBuffers[i]->impl.vertices.buf;
|
||||
offsets[i] = (VkDeviceSize)(offsets_[i] * kinc_g5_vertex_buffer_stride(vertexBuffers[i]));
|
||||
}
|
||||
vkCmdBindVertexBuffers(list->impl._buffer, 0, count, buffers, offsets);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_index_buffer(kinc_g5_command_list_t *list, struct kinc_g5_index_buffer *indexBuffer) {
|
||||
list->impl._indexCount = kinc_g5_index_buffer_count(indexBuffer);
|
||||
vkCmdBindIndexBuffer(list->impl._buffer, indexBuffer->impl.buf, 0,
|
||||
indexBuffer->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);
|
||||
}
|
||||
|
||||
void kinc_internal_restore_render_target(kinc_g5_command_list_t *list, struct kinc_g5_render_target *target) {
|
||||
VkViewport viewport;
|
||||
memset(&viewport, 0, sizeof(viewport));
|
||||
viewport.x = 0;
|
||||
viewport.y = (float)kinc_window_height(vk_ctx.current_window);
|
||||
viewport.width = (float)kinc_window_width(vk_ctx.current_window);
|
||||
viewport.height = -(float)kinc_window_height(vk_ctx.current_window);
|
||||
viewport.minDepth = (float)0.0f;
|
||||
viewport.maxDepth = (float)1.0f;
|
||||
vkCmdSetViewport(list->impl._buffer, 0, 1, &viewport);
|
||||
VkRect2D scissor;
|
||||
memset(&scissor, 0, sizeof(scissor));
|
||||
scissor.extent.width = kinc_window_width(vk_ctx.current_window);
|
||||
scissor.extent.height = kinc_window_height(vk_ctx.current_window);
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
vkCmdSetScissor(list->impl._buffer, 0, 1, &scissor);
|
||||
|
||||
if (onBackBuffer && in_render_pass) {
|
||||
return;
|
||||
}
|
||||
|
||||
endPass(list);
|
||||
|
||||
currentRenderTargets[0] = NULL;
|
||||
onBackBuffer = true;
|
||||
|
||||
VkClearValue clear_values[2];
|
||||
memset(clear_values, 0, sizeof(VkClearValue) * 2);
|
||||
clear_values[0].color.float32[0] = 0.0f;
|
||||
clear_values[0].color.float32[1] = 0.0f;
|
||||
clear_values[0].color.float32[2] = 0.0f;
|
||||
clear_values[0].color.float32[3] = 1.0f;
|
||||
clear_values[1].depthStencil.depth = 1.0;
|
||||
clear_values[1].depthStencil.stencil = 0;
|
||||
VkRenderPassBeginInfo rp_begin = {0};
|
||||
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
rp_begin.pNext = NULL;
|
||||
rp_begin.renderPass = vk_ctx.windows[vk_ctx.current_window].framebuffer_render_pass;
|
||||
rp_begin.framebuffer = vk_ctx.windows[vk_ctx.current_window].framebuffers[vk_ctx.windows[vk_ctx.current_window].current_image];
|
||||
rp_begin.renderArea.offset.x = 0;
|
||||
rp_begin.renderArea.offset.y = 0;
|
||||
rp_begin.renderArea.extent.width = kinc_window_width(vk_ctx.current_window);
|
||||
rp_begin.renderArea.extent.height = kinc_window_height(vk_ctx.current_window);
|
||||
rp_begin.clearValueCount = 2;
|
||||
rp_begin.pClearValues = clear_values;
|
||||
vkCmdBeginRenderPass(list->impl._buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
currentRenderPassBeginInfo = rp_begin;
|
||||
in_render_pass = true;
|
||||
|
||||
if (currentPipeline != NULL) {
|
||||
currentVulkanPipeline = currentPipeline->impl.framebuffer_pipeline;
|
||||
vkCmdBindPipeline(list->impl._buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, currentPipeline->impl.framebuffer_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_render_targets(kinc_g5_command_list_t *list, struct kinc_g5_render_target **targets, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
currentRenderTargets[i] = targets[i];
|
||||
}
|
||||
for (int i = count; i < 8; ++i) {
|
||||
currentRenderTargets[i] = NULL;
|
||||
}
|
||||
|
||||
if (targets[0]->framebuffer_index >= 0) {
|
||||
kinc_internal_restore_render_target(list, targets[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
endPass(list);
|
||||
|
||||
onBackBuffer = false;
|
||||
|
||||
VkClearValue clear_values[9];
|
||||
memset(clear_values, 0, sizeof(VkClearValue));
|
||||
for (int i = 0; i < count; ++i) {
|
||||
clear_values[i].color.float32[0] = 0.0f;
|
||||
clear_values[i].color.float32[1] = 0.0f;
|
||||
clear_values[i].color.float32[2] = 0.0f;
|
||||
clear_values[i].color.float32[3] = 1.0f;
|
||||
}
|
||||
clear_values[count].depthStencil.depth = 1.0;
|
||||
clear_values[count].depthStencil.stencil = 0;
|
||||
|
||||
VkRenderPassBeginInfo rp_begin = {0};
|
||||
rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
rp_begin.pNext = NULL;
|
||||
rp_begin.renderArea.offset.x = 0;
|
||||
rp_begin.renderArea.offset.y = 0;
|
||||
rp_begin.renderArea.extent.width = targets[0]->width;
|
||||
rp_begin.renderArea.extent.height = targets[0]->height;
|
||||
rp_begin.clearValueCount = count + 1;
|
||||
rp_begin.pClearValues = clear_values;
|
||||
|
||||
if (count == 1) {
|
||||
if (targets[0]->impl.depthBufferBits > 0) {
|
||||
rp_begin.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass_with_depth;
|
||||
}
|
||||
else {
|
||||
rp_begin.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass;
|
||||
}
|
||||
rp_begin.framebuffer = targets[0]->impl.framebuffer;
|
||||
}
|
||||
else {
|
||||
VkAttachmentDescription attachments[9];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
attachments[i].format = targets[i]->impl.format;
|
||||
attachments[i].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[i].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
attachments[i].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
attachments[i].flags = 0;
|
||||
}
|
||||
|
||||
if (targets[0]->impl.depthBufferBits > 0) {
|
||||
attachments[count].format = VK_FORMAT_D16_UNORM;
|
||||
attachments[count].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[count].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[count].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachments[count].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[count].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[count].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
attachments[count].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[count].flags = 0;
|
||||
}
|
||||
|
||||
VkAttachmentReference color_references[8];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
color_references[i].attachment = i;
|
||||
color_references[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
VkAttachmentReference depth_reference = {0};
|
||||
depth_reference.attachment = count;
|
||||
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass = {0};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.flags = 0;
|
||||
subpass.inputAttachmentCount = 0;
|
||||
subpass.pInputAttachments = NULL;
|
||||
subpass.colorAttachmentCount = count;
|
||||
subpass.pColorAttachments = color_references;
|
||||
subpass.pResolveAttachments = NULL;
|
||||
subpass.pDepthStencilAttachment = targets[0]->impl.depthBufferBits > 0 ? &depth_reference : NULL;
|
||||
subpass.preserveAttachmentCount = 0;
|
||||
subpass.pPreserveAttachments = NULL;
|
||||
|
||||
VkSubpassDependency dependencies[2];
|
||||
memset(&dependencies, 0, sizeof(dependencies));
|
||||
|
||||
// TODO: For multi-targets-rendering
|
||||
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependencies[0].dstSubpass = 0;
|
||||
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
dependencies[1].srcSubpass = 0;
|
||||
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
|
||||
|
||||
VkRenderPassCreateInfo rp_info = {0};
|
||||
rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
rp_info.pNext = NULL;
|
||||
rp_info.attachmentCount = targets[0]->impl.depthBufferBits > 0 ? count + 1 : count;
|
||||
rp_info.pAttachments = attachments;
|
||||
rp_info.subpassCount = 1;
|
||||
rp_info.pSubpasses = &subpass;
|
||||
rp_info.dependencyCount = 2;
|
||||
rp_info.pDependencies = dependencies;
|
||||
|
||||
VkResult err = vkCreateRenderPass(vk_ctx.device, &rp_info, NULL, &mrtRenderPass[mrtIndex]);
|
||||
assert(!err);
|
||||
|
||||
VkImageView attachmentsViews[9];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
attachmentsViews[i] = targets[i]->impl.sourceView;
|
||||
}
|
||||
if (targets[0]->impl.depthBufferBits > 0) {
|
||||
attachmentsViews[count] = targets[0]->impl.depthView;
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo fbufCreateInfo = {0};
|
||||
fbufCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
fbufCreateInfo.pNext = NULL;
|
||||
fbufCreateInfo.renderPass = mrtRenderPass[mrtIndex];
|
||||
fbufCreateInfo.attachmentCount = targets[0]->impl.depthBufferBits > 0 ? count + 1 : count;
|
||||
fbufCreateInfo.pAttachments = attachmentsViews;
|
||||
fbufCreateInfo.width = targets[0]->width;
|
||||
fbufCreateInfo.height = targets[0]->height;
|
||||
fbufCreateInfo.layers = 1;
|
||||
|
||||
err = vkCreateFramebuffer(vk_ctx.device, &fbufCreateInfo, NULL, &mrtFramebuffer[mrtIndex]);
|
||||
assert(!err);
|
||||
|
||||
rp_begin.renderPass = mrtRenderPass[mrtIndex];
|
||||
rp_begin.framebuffer = mrtFramebuffer[mrtIndex];
|
||||
mrtIndex++;
|
||||
}
|
||||
|
||||
vkCmdBeginRenderPass(list->impl._buffer, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
currentRenderPassBeginInfo = rp_begin;
|
||||
in_render_pass = true;
|
||||
|
||||
VkViewport viewport;
|
||||
memset(&viewport, 0, sizeof(viewport));
|
||||
viewport.x = 0;
|
||||
viewport.y = (float)targets[0]->height;
|
||||
viewport.width = (float)targets[0]->width;
|
||||
viewport.height = -(float)targets[0]->height;
|
||||
viewport.minDepth = (float)0.0f;
|
||||
viewport.maxDepth = (float)1.0f;
|
||||
vkCmdSetViewport(list->impl._buffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor;
|
||||
memset(&scissor, 0, sizeof(scissor));
|
||||
scissor.extent.width = targets[0]->width;
|
||||
scissor.extent.height = targets[0]->height;
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
vkCmdSetScissor(list->impl._buffer, 0, 1, &scissor);
|
||||
|
||||
if (currentPipeline != NULL) {
|
||||
currentVulkanPipeline = currentPipeline->impl.rendertarget_pipeline;
|
||||
vkCmdBindPipeline(list->impl._buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, currentPipeline->impl.rendertarget_pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_upload_index_buffer(kinc_g5_command_list_t *list, struct kinc_g5_index_buffer *buffer) {}
|
||||
|
||||
void kinc_g5_command_list_upload_vertex_buffer(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer *buffer) {}
|
||||
|
||||
void kinc_g5_command_list_upload_texture(kinc_g5_command_list_t *list, struct kinc_g5_texture *texture) {}
|
||||
|
||||
void kinc_g5_command_list_get_render_target_pixels(kinc_g5_command_list_t *list, kinc_g5_render_target_t *render_target, uint8_t *data) {
|
||||
VkFormat format = render_target->impl.format;
|
||||
int formatByteSize = formatSize(format);
|
||||
|
||||
// Create readback buffer
|
||||
if (!render_target->impl.readbackBufferCreated) {
|
||||
VkBufferCreateInfo buf_info = {0};
|
||||
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buf_info.pNext = NULL;
|
||||
buf_info.size = render_target->width * render_target->height * formatByteSize;
|
||||
buf_info.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
buf_info.flags = 0;
|
||||
vkCreateBuffer(vk_ctx.device, &buf_info, NULL, &render_target->impl.readbackBuffer);
|
||||
|
||||
VkMemoryRequirements mem_reqs = {0};
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, render_target->impl.readbackBuffer, &mem_reqs);
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc;
|
||||
memset(&mem_alloc, 0, sizeof(VkMemoryAllocateInfo));
|
||||
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc.pNext = NULL;
|
||||
mem_alloc.allocationSize = 0;
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc.memoryTypeIndex);
|
||||
vkAllocateMemory(vk_ctx.device, &mem_alloc, NULL, &render_target->impl.readbackMemory);
|
||||
vkBindBufferMemory(vk_ctx.device, render_target->impl.readbackBuffer, render_target->impl.readbackMemory, 0);
|
||||
|
||||
render_target->impl.readbackBufferCreated = true;
|
||||
}
|
||||
|
||||
vkCmdEndRenderPass(list->impl._buffer);
|
||||
setImageLayout(list->impl._buffer, render_target->impl.sourceImage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
VkBufferImageCopy region;
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = render_target->width;
|
||||
region.bufferImageHeight = render_target->height;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageOffset.x = 0;
|
||||
region.imageOffset.y = 0;
|
||||
region.imageOffset.z = 0;
|
||||
region.imageExtent.width = (uint32_t)render_target->width;
|
||||
region.imageExtent.height = (uint32_t)render_target->height;
|
||||
region.imageExtent.depth = 1;
|
||||
vkCmdCopyImageToBuffer(list->impl._buffer, render_target->impl.sourceImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, render_target->impl.readbackBuffer, 1,
|
||||
®ion);
|
||||
|
||||
setImageLayout(list->impl._buffer, render_target->impl.sourceImage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
vkCmdBeginRenderPass(list->impl._buffer, ¤tRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
in_render_pass = true;
|
||||
|
||||
kinc_g5_command_list_end(list);
|
||||
kinc_g5_command_list_execute(list);
|
||||
kinc_g5_command_list_wait_for_execution_to_finish(list);
|
||||
kinc_g5_command_list_begin(list);
|
||||
|
||||
// Read buffer
|
||||
void *p;
|
||||
vkMapMemory(vk_ctx.device, render_target->impl.readbackMemory, 0, VK_WHOLE_SIZE, 0, (void **)&p);
|
||||
memcpy(data, p, render_target->texWidth * render_target->texHeight * formatByteSize);
|
||||
vkUnmapMemory(vk_ctx.device, render_target->impl.readbackMemory);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_texture_to_render_target_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {
|
||||
// render-passes are used to transition render-targets
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_render_target_to_texture_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget) {
|
||||
// render-passes are used to transition render-targets
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_vertex_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size) {
|
||||
lastVertexConstantBufferOffset = offset;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_fragment_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size) {
|
||||
lastFragmentConstantBufferOffset = offset;
|
||||
|
||||
VkDescriptorSet descriptor_set = getDescriptorSet();
|
||||
uint32_t offsets[2] = {lastVertexConstantBufferOffset, lastFragmentConstantBufferOffset};
|
||||
vkCmdBindDescriptorSets(list->impl._buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, currentPipeline->impl.pipeline_layout, 0, 1, &descriptor_set, 2, offsets);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_compute_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size) {
|
||||
lastComputeConstantBufferOffset = offset;
|
||||
|
||||
VkDescriptorSet descriptor_set = get_compute_descriptor_set();
|
||||
uint32_t offsets[2] = {lastComputeConstantBufferOffset, lastComputeConstantBufferOffset};
|
||||
vkCmdBindDescriptorSets(list->impl._buffer, VK_PIPELINE_BIND_POINT_COMPUTE, current_compute_shader->impl.pipeline_layout, 0, 1, &descriptor_set, 2,
|
||||
offsets);
|
||||
}
|
||||
|
||||
static bool wait_for_framebuffer = false;
|
||||
|
||||
static void command_list_should_wait_for_framebuffer(void) {
|
||||
wait_for_framebuffer = true;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_execute(kinc_g5_command_list_t *list) {
|
||||
// Make sure the previous execution is done, so we can reuse the fence
|
||||
// Not optimal of course
|
||||
VkResult err = vkWaitForFences(vk_ctx.device, 1, &list->impl.fence, VK_TRUE, UINT64_MAX);
|
||||
assert(!err);
|
||||
vkResetFences(vk_ctx.device, 1, &list->impl.fence);
|
||||
|
||||
VkPipelineStageFlags pipe_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
VkSubmitInfo submit_info = {0};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.pNext = NULL;
|
||||
|
||||
VkSemaphore semaphores[2] = {framebuffer_available, relay_semaphore};
|
||||
VkPipelineStageFlags dst_stage_flags[2] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
|
||||
if (wait_for_framebuffer) {
|
||||
submit_info.pWaitSemaphores = semaphores;
|
||||
submit_info.pWaitDstStageMask = dst_stage_flags;
|
||||
submit_info.waitSemaphoreCount = wait_for_relay ? 2 : 1;
|
||||
wait_for_framebuffer = false;
|
||||
}
|
||||
else if (wait_for_relay) {
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = &semaphores[1];
|
||||
submit_info.pWaitDstStageMask = &dst_stage_flags[1];
|
||||
}
|
||||
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &list->impl._buffer;
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &relay_semaphore;
|
||||
wait_for_relay = true;
|
||||
|
||||
err = vkQueueSubmit(vk_ctx.queue, 1, &submit_info, list->impl.fence);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_wait_for_execution_to_finish(kinc_g5_command_list_t *list) {
|
||||
VkResult err = vkWaitForFences(vk_ctx.device, 1, &list->impl.fence, VK_TRUE, UINT64_MAX);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture) {
|
||||
vulkanTextures[unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]] = texture;
|
||||
vulkanRenderTargets[unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]] = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_sampler(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_sampler_t *sampler) {
|
||||
if (unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT] >= 0) {
|
||||
vulkanSamplers[unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]] = sampler->impl.sampler;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_image_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture) {
|
||||
vulkanTextures[unit.stages[KINC_G5_SHADER_TYPE_COMPUTE]] = texture;
|
||||
vulkanRenderTargets[unit.stages[KINC_G5_SHADER_TYPE_COMPUTE]] = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_render_target_face(kinc_g5_command_list_t *list, kinc_g5_render_target_t *texture, int face) {}
|
||||
|
||||
bool kinc_g5_command_list_init_occlusion_query(kinc_g5_command_list_t *list, unsigned *occlusionQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_delete_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery) {}
|
||||
|
||||
void kinc_g5_command_list_render_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery, int triangles) {}
|
||||
|
||||
bool kinc_g5_command_list_are_query_results_available(kinc_g5_command_list_t *list, unsigned occlusionQuery) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_get_query_result(kinc_g5_command_list_t *list, unsigned occlusionQuery, unsigned *pixelCount) {}
|
||||
|
||||
void kinc_g5_command_list_set_texture_from_render_target(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_render_target_t *target) {
|
||||
target->impl.stage = unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT];
|
||||
vulkanRenderTargets[unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]] = target;
|
||||
vulkanTextures[unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]] = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_texture_from_render_target_depth(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_render_target_t *target) {
|
||||
target->impl.stage_depth = unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT];
|
||||
vulkanRenderTargets[unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]] = target;
|
||||
vulkanTextures[unit.stages[KINC_G5_SHADER_TYPE_FRAGMENT]] = NULL;
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_set_compute_shader(kinc_g5_command_list_t *list, kinc_g5_compute_shader *shader) {
|
||||
current_compute_shader = shader;
|
||||
vkCmdBindPipeline(list->impl._buffer, VK_PIPELINE_BIND_POINT_COMPUTE, shader->impl.pipeline);
|
||||
//**vkCmdBindDescriptorSets(list->impl._buffer, VK_PIPELINE_BIND_POINT_COMPUTE, shader->impl.pipeline_layout, 0, 1, &shader->impl.descriptor_set, 0, 0);
|
||||
}
|
||||
|
||||
void kinc_g5_command_list_compute(kinc_g5_command_list_t *list, int x, int y, int z) {
|
||||
if (in_render_pass) {
|
||||
vkCmdEndRenderPass(list->impl._buffer);
|
||||
in_render_pass = false;
|
||||
}
|
||||
|
||||
vkCmdDispatch(list->impl._buffer, x, y, z);
|
||||
|
||||
int render_target_count = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (currentRenderTargets[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
++render_target_count;
|
||||
}
|
||||
if (render_target_count > 0) {
|
||||
kinc_g5_command_list_set_render_targets(list, currentRenderTargets, render_target_count);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "MiniVulkan.h"
|
||||
|
||||
typedef struct {
|
||||
int _indexCount;
|
||||
VkCommandBuffer _buffer;
|
||||
VkFence fence;
|
||||
} CommandList5Impl;
|
@ -0,0 +1,237 @@
|
||||
#include <kinc/graphics5/compute.h>
|
||||
|
||||
#include <kinc/graphics4/texture.h>
|
||||
#include <kinc/log.h>
|
||||
#include <kinc/math/core.h>
|
||||
|
||||
static void parse_shader(uint32_t *shader_source, int shader_length, kinc_internal_named_number *locations, kinc_internal_named_number *textureBindings,
|
||||
kinc_internal_named_number *uniformOffsets);
|
||||
|
||||
static VkShaderModule create_shader_module(const void *code, size_t size);
|
||||
|
||||
static VkDescriptorPool compute_descriptor_pool;
|
||||
|
||||
static void create_compute_descriptor_layout(void) {
|
||||
VkDescriptorSetLayoutBinding layoutBindings[18];
|
||||
memset(layoutBindings, 0, sizeof(layoutBindings));
|
||||
|
||||
layoutBindings[0].binding = 0;
|
||||
layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
|
||||
layoutBindings[0].descriptorCount = 1;
|
||||
layoutBindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
layoutBindings[0].pImmutableSamplers = NULL;
|
||||
|
||||
layoutBindings[1].binding = 1;
|
||||
layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
|
||||
layoutBindings[1].descriptorCount = 1;
|
||||
layoutBindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
layoutBindings[1].pImmutableSamplers = NULL;
|
||||
|
||||
for (int i = 2; i < 18; ++i) {
|
||||
layoutBindings[i].binding = i;
|
||||
layoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
layoutBindings[i].descriptorCount = 1;
|
||||
layoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
layoutBindings[i].pImmutableSamplers = NULL;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo descriptor_layout = {0};
|
||||
descriptor_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
descriptor_layout.pNext = NULL;
|
||||
descriptor_layout.bindingCount = 18;
|
||||
descriptor_layout.pBindings = layoutBindings;
|
||||
|
||||
VkResult err = vkCreateDescriptorSetLayout(vk_ctx.device, &descriptor_layout, NULL, &compute_descriptor_layout);
|
||||
assert(!err);
|
||||
|
||||
VkDescriptorPoolSize typeCounts[2];
|
||||
memset(typeCounts, 0, sizeof(typeCounts));
|
||||
|
||||
typeCounts[0].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
|
||||
typeCounts[0].descriptorCount = 2 * 1024;
|
||||
|
||||
typeCounts[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
typeCounts[1].descriptorCount = 16 * 1024;
|
||||
|
||||
VkDescriptorPoolCreateInfo pool_info = {0};
|
||||
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
pool_info.pNext = NULL;
|
||||
pool_info.maxSets = 1024;
|
||||
pool_info.poolSizeCount = 2;
|
||||
pool_info.pPoolSizes = typeCounts;
|
||||
|
||||
err = vkCreateDescriptorPool(vk_ctx.device, &pool_info, NULL, &compute_descriptor_pool);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
void kinc_g5_compute_shader_init(kinc_g5_compute_shader *shader, void *_data, int length) {
|
||||
memset(shader->impl.locations, 0, sizeof(kinc_internal_named_number) * KINC_INTERNAL_NAMED_NUMBER_COUNT);
|
||||
memset(shader->impl.offsets, 0, sizeof(kinc_internal_named_number) * KINC_INTERNAL_NAMED_NUMBER_COUNT);
|
||||
memset(shader->impl.texture_bindings, 0, sizeof(kinc_internal_named_number) * KINC_INTERNAL_NAMED_NUMBER_COUNT);
|
||||
parse_shader((uint32_t *)_data, length, shader->impl.locations, shader->impl.texture_bindings, shader->impl.offsets);
|
||||
|
||||
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {0};
|
||||
pPipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pPipelineLayoutCreateInfo.pNext = NULL;
|
||||
pPipelineLayoutCreateInfo.setLayoutCount = 1;
|
||||
pPipelineLayoutCreateInfo.pSetLayouts = &compute_descriptor_layout;
|
||||
|
||||
VkResult err = vkCreatePipelineLayout(vk_ctx.device, &pPipelineLayoutCreateInfo, NULL, &shader->impl.pipeline_layout);
|
||||
assert(!err);
|
||||
|
||||
VkComputePipelineCreateInfo pipeline_info = {0};
|
||||
|
||||
memset(&pipeline_info, 0, sizeof(pipeline_info));
|
||||
pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||
pipeline_info.layout = shader->impl.pipeline_layout;
|
||||
|
||||
VkPipelineShaderStageCreateInfo shader_stage;
|
||||
memset(&shader_stage, 0, sizeof(VkPipelineShaderStageCreateInfo));
|
||||
|
||||
shader_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shader_stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
shader->impl.shader_module = create_shader_module(_data, (size_t)length);
|
||||
shader_stage.module = shader->impl.shader_module;
|
||||
shader_stage.pName = "main";
|
||||
|
||||
pipeline_info.stage = shader_stage;
|
||||
|
||||
err = vkCreateComputePipelines(vk_ctx.device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &shader->impl.pipeline);
|
||||
assert(!err);
|
||||
|
||||
vkDestroyShaderModule(vk_ctx.device, shader->impl.shader_module, NULL);
|
||||
|
||||
/*shader->impl.length = (int)(length - index);
|
||||
shader->impl.data = (uint8_t *)malloc(shader->impl.length);
|
||||
assert(shader->impl.data != NULL);
|
||||
memcpy(shader->impl.data, &data[index], shader->impl.length);
|
||||
|
||||
VkShaderModuleCreateInfo module_create_info;
|
||||
module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
module_create_info.pNext = NULL;
|
||||
module_create_info.codeSize = shader->impl.length;
|
||||
module_create_info.pCode = (const uint32_t *)shader->impl.data;
|
||||
module_create_info.flags = 0;
|
||||
|
||||
VkShaderModule module;
|
||||
VkResult err = vkCreateShaderModule(vk_ctx.device, &module_create_info, NULL, &module);
|
||||
assert(!err);
|
||||
|
||||
VkPipelineShaderStageCreateInfo compute_shader_stage_info = {0};
|
||||
compute_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
compute_shader_stage_info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
compute_shader_stage_info.module = module;
|
||||
compute_shader_stage_info.pName = "main";
|
||||
|
||||
VkDescriptorSetLayoutBinding layout_bindings[1] = {0};
|
||||
layout_bindings[0].binding = 0;
|
||||
layout_bindings[0].descriptorCount = 1;
|
||||
layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
layout_bindings[0].pImmutableSamplers = NULL;
|
||||
layout_bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
|
||||
/*layout_bindings[1].binding = 1;
|
||||
layout_bindings[1].descriptorCount = 1;
|
||||
layout_bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
layout_bindings[1].pImmutableSamplers = NULL;
|
||||
layout_bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
|
||||
layout_bindings[2].binding = 2;
|
||||
layout_bindings[2].descriptorCount = 1;
|
||||
layout_bindings[2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
layout_bindings[2].pImmutableSamplers = NULL;
|
||||
layout_bindings[2].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;*/
|
||||
|
||||
/*VkDescriptorSetLayoutCreateInfo layoutInfo = {0};
|
||||
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
layoutInfo.bindingCount = 1;
|
||||
layoutInfo.pBindings = layout_bindings;
|
||||
|
||||
VkDescriptorSetLayout descriptor_set_layout;
|
||||
if (vkCreateDescriptorSetLayout(vk_ctx.device, &layoutInfo, NULL, &descriptor_set_layout) != VK_SUCCESS) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not initialize compute shader.");
|
||||
return;
|
||||
}
|
||||
|
||||
VkPipelineLayoutCreateInfo pipeline_layout_info = {0};
|
||||
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipeline_layout_info.setLayoutCount = 1;
|
||||
pipeline_layout_info.pSetLayouts = &descriptor_set_layout;
|
||||
|
||||
if (vkCreatePipelineLayout(vk_ctx.device, &pipeline_layout_info, NULL, &shader->impl.pipeline_layout) != VK_SUCCESS) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not initialize compute shader.");
|
||||
return;
|
||||
}
|
||||
|
||||
VkComputePipelineCreateInfo pipeline_info = {0};
|
||||
memset(&pipeline_info, 0, sizeof(pipeline_info));
|
||||
pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||
pipeline_info.layout = shader->impl.pipeline_layout;
|
||||
pipeline_info.stage = compute_shader_stage_info;
|
||||
|
||||
if (vkCreateComputePipelines(vk_ctx.device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &shader->impl.pipeline) != VK_SUCCESS) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not initialize compute shader.");
|
||||
return;
|
||||
}*/
|
||||
}
|
||||
|
||||
void kinc_g5_compute_shader_destroy(kinc_g5_compute_shader *shader) {}
|
||||
|
||||
kinc_g5_constant_location_t kinc_g5_compute_shader_get_constant_location(kinc_g5_compute_shader *shader, const char *name) {
|
||||
kinc_g5_constant_location_t location = {0};
|
||||
|
||||
uint32_t hash = kinc_internal_hash_name((unsigned char *)name);
|
||||
|
||||
/*kinc_compute_internal_shader_constant_t *constant = findComputeConstant(shader->impl.constants, hash);
|
||||
if (constant == NULL) {
|
||||
location.impl.computeOffset = 0;
|
||||
}
|
||||
else {
|
||||
location.impl.computeOffset = constant->offset;
|
||||
}
|
||||
|
||||
if (location.impl.computeOffset == 0) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Uniform %s not found.", name);
|
||||
}*/
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
kinc_g5_texture_unit_t kinc_g5_compute_shader_get_texture_unit(kinc_g5_compute_shader *shader, const char *name) {
|
||||
char unitName[64];
|
||||
int unitOffset = 0;
|
||||
size_t len = strlen(name);
|
||||
if (len > 63)
|
||||
len = 63;
|
||||
strncpy(unitName, name, len + 1);
|
||||
if (unitName[len - 1] == ']') { // Check for array - mySampler[2]
|
||||
unitOffset = (int)(unitName[len - 2] - '0'); // Array index is unit offset
|
||||
unitName[len - 3] = 0; // Strip array from name
|
||||
}
|
||||
|
||||
uint32_t hash = kinc_internal_hash_name((unsigned char *)unitName);
|
||||
|
||||
kinc_g5_texture_unit_t unit;
|
||||
for (int i = 0; i < KINC_G5_SHADER_TYPE_COUNT; ++i) {
|
||||
unit.stages[i] = -1;
|
||||
}
|
||||
unit.stages[KINC_G5_SHADER_TYPE_COMPUTE] = 0;
|
||||
/*kinc_internal_hash_index_t *compute_unit = findComputeTextureUnit(shader->impl.textures, hash);
|
||||
if (compute_unit == NULL) {
|
||||
#ifndef NDEBUG
|
||||
static int notFoundCount = 0;
|
||||
if (notFoundCount < 10) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Sampler %s not found.", unitName);
|
||||
++notFoundCount;
|
||||
}
|
||||
else if (notFoundCount == 10) {
|
||||
kinc_log(KINC_LOG_LEVEL_WARNING, "Giving up on sampler not found messages.", unitName);
|
||||
++notFoundCount;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
unit.stages[KINC_G5_SHADER_TYPE_COMPUTE] = compute_unit->index + unitOffset;
|
||||
}*/
|
||||
return unit;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/backend/graphics5/ShaderHash.h>
|
||||
|
||||
#include "MiniVulkan.h"
|
||||
|
||||
#include "named_number.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct kinc_g5_compute_shader_impl {
|
||||
kinc_internal_named_number locations[KINC_INTERNAL_NAMED_NUMBER_COUNT];
|
||||
kinc_internal_named_number texture_bindings[KINC_INTERNAL_NAMED_NUMBER_COUNT];
|
||||
kinc_internal_named_number offsets[KINC_INTERNAL_NAMED_NUMBER_COUNT];
|
||||
|
||||
VkPipelineLayout pipeline_layout;
|
||||
VkPipeline pipeline;
|
||||
VkShaderModule shader_module;
|
||||
} kinc_g5_compute_shader_impl;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,89 @@
|
||||
#include "vulkan.h"
|
||||
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
|
||||
bool memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
|
||||
|
||||
// VkBuffer *vk_ctx.vertex_uniform_buffer = NULL;
|
||||
// VkBuffer *vk_ctx.fragment_uniform_buffer = NULL;
|
||||
|
||||
bool kinc_g5_transposeMat3 = true;
|
||||
bool kinc_g5_transposeMat4 = true;
|
||||
|
||||
static void createUniformBuffer(VkBuffer *buf, VkMemoryAllocateInfo *mem_alloc, VkDeviceMemory *mem, VkDescriptorBufferInfo *buffer_info, int size) {
|
||||
VkBufferCreateInfo buf_info;
|
||||
memset(&buf_info, 0, sizeof(buf_info));
|
||||
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buf_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
buf_info.size = size;
|
||||
VkResult err = vkCreateBuffer(vk_ctx.device, &buf_info, NULL, buf);
|
||||
assert(!err);
|
||||
|
||||
VkMemoryRequirements mem_reqs;
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, *buf, &mem_reqs);
|
||||
|
||||
mem_alloc->sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc->pNext = NULL;
|
||||
mem_alloc->allocationSize = mem_reqs.size;
|
||||
mem_alloc->memoryTypeIndex = 0;
|
||||
|
||||
bool pass = memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc->memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
err = vkAllocateMemory(vk_ctx.device, mem_alloc, NULL, mem);
|
||||
assert(!err);
|
||||
|
||||
err = vkBindBufferMemory(vk_ctx.device, *buf, *mem, 0);
|
||||
assert(!err);
|
||||
|
||||
buffer_info->buffer = *buf;
|
||||
buffer_info->offset = 0;
|
||||
buffer_info->range = size;
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_init(kinc_g5_constant_buffer_t *buffer, int size) {
|
||||
buffer->impl.mySize = size;
|
||||
buffer->data = NULL;
|
||||
|
||||
createUniformBuffer(&buffer->impl.buf, &buffer->impl.mem_alloc, &buffer->impl.mem, &buffer->impl.buffer_info, size);
|
||||
|
||||
// buffer hack
|
||||
if (vk_ctx.vertex_uniform_buffer == NULL) {
|
||||
vk_ctx.vertex_uniform_buffer = &buffer->impl.buf;
|
||||
}
|
||||
else if (vk_ctx.fragment_uniform_buffer == NULL) {
|
||||
vk_ctx.fragment_uniform_buffer = &buffer->impl.buf;
|
||||
}
|
||||
else if (vk_ctx.compute_uniform_buffer == NULL) {
|
||||
vk_ctx.compute_uniform_buffer = &buffer->impl.buf;
|
||||
}
|
||||
|
||||
void *p;
|
||||
VkResult err = vkMapMemory(vk_ctx.device, buffer->impl.mem, 0, buffer->impl.mem_alloc.allocationSize, 0, (void **)&p);
|
||||
assert(!err);
|
||||
memset(p, 0, buffer->impl.mem_alloc.allocationSize);
|
||||
vkUnmapMemory(vk_ctx.device, buffer->impl.mem);
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_destroy(kinc_g5_constant_buffer_t *buffer) {
|
||||
vkFreeMemory(vk_ctx.device, buffer->impl.mem, NULL);
|
||||
vkDestroyBuffer(vk_ctx.device, buffer->impl.buf, NULL);
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_lock_all(kinc_g5_constant_buffer_t *buffer) {
|
||||
kinc_g5_constant_buffer_lock(buffer, 0, kinc_g5_constant_buffer_size(buffer));
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_lock(kinc_g5_constant_buffer_t *buffer, int start, int count) {
|
||||
VkResult err = vkMapMemory(vk_ctx.device, buffer->impl.mem, start, count, 0, (void **)&buffer->data);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
void kinc_g5_constant_buffer_unlock(kinc_g5_constant_buffer_t *buffer) {
|
||||
vkUnmapMemory(vk_ctx.device, buffer->impl.mem);
|
||||
buffer->data = NULL;
|
||||
}
|
||||
|
||||
int kinc_g5_constant_buffer_size(kinc_g5_constant_buffer_t *buffer) {
|
||||
return buffer->impl.mySize;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "MiniVulkan.h"
|
||||
|
||||
typedef struct {
|
||||
VkBuffer buf;
|
||||
VkDescriptorBufferInfo buffer_info;
|
||||
VkMemoryAllocateInfo mem_alloc;
|
||||
VkDeviceMemory mem;
|
||||
int lastStart;
|
||||
int lastCount;
|
||||
int mySize;
|
||||
} ConstantBuffer5Impl;
|
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <kinc/backend/graphics5/indexbuffer.h>
|
||||
#include <kinc/backend/graphics5/rendertarget.h>
|
||||
#include <kinc/backend/graphics5/texture.h>
|
||||
#include <kinc/backend/graphics5/vertexbuffer.h>
|
@ -0,0 +1,93 @@
|
||||
#include "vulkan.h"
|
||||
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
|
||||
bool memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
|
||||
|
||||
kinc_g5_index_buffer_t *currentIndexBuffer = NULL;
|
||||
|
||||
static void unset(kinc_g5_index_buffer_t *buffer) {
|
||||
if (currentIndexBuffer == buffer) {
|
||||
currentIndexBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_init(kinc_g5_index_buffer_t *buffer, int indexCount, kinc_g5_index_buffer_format_t format, bool gpuMemory) {
|
||||
buffer->impl.count = indexCount;
|
||||
buffer->impl.format = format;
|
||||
|
||||
VkBufferCreateInfo buf_info = {0};
|
||||
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buf_info.pNext = NULL;
|
||||
buf_info.size = format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? indexCount * sizeof(uint16_t) : indexCount * sizeof(uint32_t);
|
||||
buf_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||
#ifdef KINC_VKRT
|
||||
buf_info.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
#endif
|
||||
buf_info.flags = 0;
|
||||
|
||||
memset(&buffer->impl.mem_alloc, 0, sizeof(VkMemoryAllocateInfo));
|
||||
buffer->impl.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
buffer->impl.mem_alloc.pNext = NULL;
|
||||
buffer->impl.mem_alloc.allocationSize = 0;
|
||||
buffer->impl.mem_alloc.memoryTypeIndex = 0;
|
||||
|
||||
buffer->impl.buf = NULL;
|
||||
buffer->impl.mem = NULL;
|
||||
|
||||
VkResult err = vkCreateBuffer(vk_ctx.device, &buf_info, NULL, &buffer->impl.buf);
|
||||
assert(!err);
|
||||
|
||||
VkMemoryRequirements mem_reqs = {0};
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, buffer->impl.buf, &mem_reqs);
|
||||
|
||||
buffer->impl.mem_alloc.allocationSize = mem_reqs.size;
|
||||
bool pass = memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &buffer->impl.mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
#ifdef KINC_VKRT
|
||||
VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {0};
|
||||
memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
|
||||
memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
|
||||
buffer->impl.mem_alloc.pNext = &memory_allocate_flags_info;
|
||||
#endif
|
||||
|
||||
err = vkAllocateMemory(vk_ctx.device, &buffer->impl.mem_alloc, NULL, &buffer->impl.mem);
|
||||
assert(!err);
|
||||
|
||||
err = vkBindBufferMemory(vk_ctx.device, buffer->impl.buf, buffer->impl.mem, 0);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_destroy(kinc_g5_index_buffer_t *buffer) {
|
||||
unset(buffer);
|
||||
vkFreeMemory(vk_ctx.device, buffer->impl.mem, NULL);
|
||||
vkDestroyBuffer(vk_ctx.device, buffer->impl.buf, NULL);
|
||||
}
|
||||
|
||||
static int kinc_g5_internal_index_buffer_stride(kinc_g5_index_buffer_t *buffer) {
|
||||
return buffer->impl.format == KINC_G5_INDEX_BUFFER_FORMAT_16BIT ? 2 : 4;
|
||||
}
|
||||
|
||||
void *kinc_g5_index_buffer_lock_all(kinc_g5_index_buffer_t *buffer) {
|
||||
return kinc_g5_index_buffer_lock(buffer, 0, kinc_g5_index_buffer_count(buffer));
|
||||
}
|
||||
|
||||
void *kinc_g5_index_buffer_lock(kinc_g5_index_buffer_t *buffer, int start, int count) {
|
||||
uint8_t *data;
|
||||
VkResult err = vkMapMemory(vk_ctx.device, buffer->impl.mem, 0, buffer->impl.mem_alloc.allocationSize, 0, (void **)&data);
|
||||
assert(!err);
|
||||
return &data[start * kinc_g5_internal_index_buffer_stride(buffer)];
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_unlock_all(kinc_g5_index_buffer_t *buffer) {
|
||||
vkUnmapMemory(vk_ctx.device, buffer->impl.mem);
|
||||
}
|
||||
|
||||
void kinc_g5_index_buffer_unlock(kinc_g5_index_buffer_t *buffer, int count) {
|
||||
kinc_g5_index_buffer_unlock_all(buffer);
|
||||
}
|
||||
|
||||
int kinc_g5_index_buffer_count(kinc_g5_index_buffer_t *buffer) {
|
||||
return buffer->impl.count;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "MiniVulkan.h"
|
||||
|
||||
typedef struct {
|
||||
int count;
|
||||
int format;
|
||||
|
||||
VkBuffer buf;
|
||||
VkDeviceMemory mem;
|
||||
VkMemoryAllocateInfo mem_alloc;
|
||||
} IndexBuffer5Impl;
|
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#define KINC_INTERNAL_NAMED_NUMBER_COUNT 32
|
||||
|
||||
typedef struct {
|
||||
char name[256];
|
||||
uint32_t number;
|
||||
} kinc_internal_named_number;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "MiniVulkan.h"
|
||||
|
||||
#include "named_number.h"
|
||||
|
||||
struct kinc_g5_shader;
|
||||
|
||||
typedef struct PipelineState5Impl_s {
|
||||
const char **textures;
|
||||
int *textureValues;
|
||||
int textureCount;
|
||||
|
||||
VkPipeline framebuffer_pipeline;
|
||||
VkPipeline rendertarget_pipeline;
|
||||
VkShaderModule vert_shader_module;
|
||||
VkShaderModule frag_shader_module;
|
||||
|
||||
kinc_internal_named_number vertexLocations[KINC_INTERNAL_NAMED_NUMBER_COUNT];
|
||||
kinc_internal_named_number fragmentLocations[KINC_INTERNAL_NAMED_NUMBER_COUNT];
|
||||
kinc_internal_named_number textureBindings[KINC_INTERNAL_NAMED_NUMBER_COUNT];
|
||||
kinc_internal_named_number vertexOffsets[KINC_INTERNAL_NAMED_NUMBER_COUNT];
|
||||
kinc_internal_named_number fragmentOffsets[KINC_INTERNAL_NAMED_NUMBER_COUNT];
|
||||
|
||||
VkPipelineLayout pipeline_layout;
|
||||
} PipelineState5Impl;
|
||||
|
||||
typedef struct ComputePipelineState5Impl_t {
|
||||
int a;
|
||||
} ComputePipelineState5Impl;
|
||||
|
||||
typedef struct {
|
||||
int vertexOffset;
|
||||
int fragmentOffset;
|
||||
int computeOffset;
|
||||
} ConstantLocation5Impl;
|
||||
|
||||
typedef struct {
|
||||
int nothing;
|
||||
} AttributeLocation5Impl;
|
@ -0,0 +1,769 @@
|
||||
#include "vulkan.h"
|
||||
|
||||
#include "raytrace.h"
|
||||
|
||||
#ifndef KINC_ANDROID
|
||||
|
||||
#include <kinc/graphics5/commandlist.h>
|
||||
#include <kinc/graphics5/constantbuffer.h>
|
||||
#include <kinc/graphics5/graphics.h>
|
||||
#include <kinc/graphics5/indexbuffer.h>
|
||||
#include <kinc/graphics5/pipeline.h>
|
||||
#include <kinc/graphics5/raytrace.h>
|
||||
#include <kinc/graphics5/vertexbuffer.h>
|
||||
|
||||
extern VkRenderPassBeginInfo currentRenderPassBeginInfo;
|
||||
extern VkFramebuffer *framebuffers;
|
||||
extern uint32_t current_buffer;
|
||||
bool memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
|
||||
|
||||
static const int INDEX_RAYGEN = 0;
|
||||
static const int INDEX_MISS = 1;
|
||||
static const int INDEX_CLOSEST_HIT = 2;
|
||||
static const char *raygen_shader_name = "raygeneration";
|
||||
static const char *closesthit_shader_name = "closesthit";
|
||||
static const char *miss_shader_name = "miss";
|
||||
|
||||
static VkDescriptorPool raytrace_descriptor_pool;
|
||||
static kinc_raytrace_acceleration_structure_t *accel;
|
||||
static kinc_raytrace_pipeline_t *pipeline;
|
||||
static kinc_g5_texture_t *output = NULL;
|
||||
|
||||
static PFN_vkCreateRayTracingPipelinesKHR _vkCreateRayTracingPipelinesKHR = NULL;
|
||||
static PFN_vkGetRayTracingShaderGroupHandlesKHR _vkGetRayTracingShaderGroupHandlesKHR = NULL;
|
||||
static PFN_vkGetBufferDeviceAddressKHR _vkGetBufferDeviceAddressKHR = NULL;
|
||||
static PFN_vkCreateAccelerationStructureKHR _vkCreateAccelerationStructureKHR = NULL;
|
||||
static PFN_vkGetAccelerationStructureDeviceAddressKHR _vkGetAccelerationStructureDeviceAddressKHR = NULL;
|
||||
static PFN_vkGetAccelerationStructureBuildSizesKHR _vkGetAccelerationStructureBuildSizesKHR = NULL;
|
||||
static PFN_vkCmdBuildAccelerationStructuresKHR _vkCmdBuildAccelerationStructuresKHR = NULL;
|
||||
static PFN_vkDestroyAccelerationStructureKHR _vkDestroyAccelerationStructureKHR = NULL;
|
||||
static PFN_vkCmdTraceRaysKHR _vkCmdTraceRaysKHR = NULL;
|
||||
|
||||
void kinc_raytrace_pipeline_init(kinc_raytrace_pipeline_t *pipeline, kinc_g5_command_list_t *command_list, void *ray_shader, int ray_shader_size,
|
||||
kinc_g5_constant_buffer_t *constant_buffer) {
|
||||
pipeline->_constant_buffer = constant_buffer;
|
||||
|
||||
{
|
||||
VkDescriptorSetLayoutBinding acceleration_structure_layout_binding = {0};
|
||||
acceleration_structure_layout_binding.binding = 0;
|
||||
acceleration_structure_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
|
||||
acceleration_structure_layout_binding.descriptorCount = 1;
|
||||
acceleration_structure_layout_binding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
||||
|
||||
VkDescriptorSetLayoutBinding result_image_layout_binding = {0};
|
||||
result_image_layout_binding.binding = 1;
|
||||
result_image_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
result_image_layout_binding.descriptorCount = 1;
|
||||
result_image_layout_binding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
||||
|
||||
VkDescriptorSetLayoutBinding uniform_buffer_binding = {0};
|
||||
uniform_buffer_binding.binding = 2;
|
||||
uniform_buffer_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
uniform_buffer_binding.descriptorCount = 1;
|
||||
uniform_buffer_binding.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
||||
|
||||
VkDescriptorSetLayoutBinding bindings[3] = {acceleration_structure_layout_binding, result_image_layout_binding, uniform_buffer_binding};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo layout_info = {0};
|
||||
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
layout_info.pNext = NULL;
|
||||
layout_info.bindingCount = 3;
|
||||
layout_info.pBindings = &bindings[0];
|
||||
vkCreateDescriptorSetLayout(vk_ctx.device, &layout_info, NULL, &pipeline->impl.descriptor_set_layout);
|
||||
|
||||
VkPipelineLayoutCreateInfo pipeline_layout_create_info = {0};
|
||||
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipeline_layout_create_info.pNext = NULL;
|
||||
pipeline_layout_create_info.setLayoutCount = 1;
|
||||
pipeline_layout_create_info.pSetLayouts = &pipeline->impl.descriptor_set_layout;
|
||||
|
||||
vkCreatePipelineLayout(vk_ctx.device, &pipeline_layout_create_info, NULL, &pipeline->impl.pipeline_layout);
|
||||
|
||||
VkShaderModuleCreateInfo module_create_info = {0};
|
||||
memset(&module_create_info, 0, sizeof(VkShaderModuleCreateInfo));
|
||||
module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
module_create_info.codeSize = ray_shader_size;
|
||||
module_create_info.pCode = (const uint32_t *)ray_shader;
|
||||
module_create_info.pNext = NULL;
|
||||
module_create_info.flags = 0;
|
||||
VkShaderModule shader_module;
|
||||
vkCreateShaderModule(vk_ctx.device, &module_create_info, NULL, &shader_module);
|
||||
|
||||
VkPipelineShaderStageCreateInfo shader_stages[3];
|
||||
shader_stages[INDEX_RAYGEN].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shader_stages[INDEX_RAYGEN].pNext = NULL;
|
||||
shader_stages[INDEX_RAYGEN].stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
||||
shader_stages[INDEX_RAYGEN].module = shader_module;
|
||||
shader_stages[INDEX_RAYGEN].pName = raygen_shader_name;
|
||||
shader_stages[INDEX_RAYGEN].flags = 0;
|
||||
shader_stages[INDEX_RAYGEN].pSpecializationInfo = NULL;
|
||||
|
||||
shader_stages[INDEX_MISS].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shader_stages[INDEX_MISS].pNext = NULL;
|
||||
shader_stages[INDEX_MISS].stage = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||
shader_stages[INDEX_MISS].module = shader_module;
|
||||
shader_stages[INDEX_MISS].pName = miss_shader_name;
|
||||
shader_stages[INDEX_MISS].flags = 0;
|
||||
shader_stages[INDEX_MISS].pSpecializationInfo = NULL;
|
||||
|
||||
shader_stages[INDEX_CLOSEST_HIT].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shader_stages[INDEX_CLOSEST_HIT].pNext = NULL;
|
||||
shader_stages[INDEX_CLOSEST_HIT].stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||
shader_stages[INDEX_CLOSEST_HIT].module = shader_module;
|
||||
shader_stages[INDEX_CLOSEST_HIT].pName = closesthit_shader_name;
|
||||
shader_stages[INDEX_CLOSEST_HIT].flags = 0;
|
||||
shader_stages[INDEX_CLOSEST_HIT].pSpecializationInfo = NULL;
|
||||
|
||||
VkRayTracingShaderGroupCreateInfoKHR groups[3];
|
||||
groups[INDEX_RAYGEN].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
|
||||
groups[INDEX_RAYGEN].pNext = NULL;
|
||||
groups[INDEX_RAYGEN].generalShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_RAYGEN].closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_RAYGEN].anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_RAYGEN].intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_RAYGEN].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
groups[INDEX_RAYGEN].generalShader = INDEX_RAYGEN;
|
||||
|
||||
groups[INDEX_MISS].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
|
||||
groups[INDEX_MISS].pNext = NULL;
|
||||
groups[INDEX_MISS].generalShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_MISS].closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_MISS].anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_MISS].intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_MISS].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
|
||||
groups[INDEX_MISS].generalShader = INDEX_MISS;
|
||||
|
||||
groups[INDEX_CLOSEST_HIT].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
|
||||
groups[INDEX_CLOSEST_HIT].pNext = NULL;
|
||||
groups[INDEX_CLOSEST_HIT].generalShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_CLOSEST_HIT].closestHitShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_CLOSEST_HIT].anyHitShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_CLOSEST_HIT].intersectionShader = VK_SHADER_UNUSED_KHR;
|
||||
groups[INDEX_CLOSEST_HIT].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||
groups[INDEX_CLOSEST_HIT].closestHitShader = INDEX_CLOSEST_HIT;
|
||||
|
||||
VkRayTracingPipelineCreateInfoKHR raytracing_pipeline_create_info = {0};
|
||||
raytracing_pipeline_create_info.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR;
|
||||
raytracing_pipeline_create_info.pNext = NULL;
|
||||
raytracing_pipeline_create_info.flags = 0;
|
||||
raytracing_pipeline_create_info.stageCount = 3;
|
||||
raytracing_pipeline_create_info.pStages = &shader_stages[0];
|
||||
raytracing_pipeline_create_info.groupCount = 3;
|
||||
raytracing_pipeline_create_info.pGroups = &groups[0];
|
||||
raytracing_pipeline_create_info.maxPipelineRayRecursionDepth = 1;
|
||||
raytracing_pipeline_create_info.layout = pipeline->impl.pipeline_layout;
|
||||
_vkCreateRayTracingPipelinesKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkCreateRayTracingPipelinesKHR");
|
||||
_vkCreateRayTracingPipelinesKHR(vk_ctx.device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &raytracing_pipeline_create_info, NULL, &pipeline->impl.pipeline);
|
||||
}
|
||||
|
||||
{
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR ray_tracing_pipeline_properties;
|
||||
ray_tracing_pipeline_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
|
||||
ray_tracing_pipeline_properties.pNext = NULL;
|
||||
VkPhysicalDeviceProperties2 device_properties = {0};
|
||||
device_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
device_properties.pNext = &ray_tracing_pipeline_properties;
|
||||
vkGetPhysicalDeviceProperties2(vk_ctx.gpu, &device_properties);
|
||||
|
||||
_vkGetRayTracingShaderGroupHandlesKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkGetRayTracingShaderGroupHandlesKHR");
|
||||
uint32_t handle_size = ray_tracing_pipeline_properties.shaderGroupHandleSize;
|
||||
uint32_t handle_size_aligned =
|
||||
(ray_tracing_pipeline_properties.shaderGroupHandleSize + ray_tracing_pipeline_properties.shaderGroupHandleAlignment - 1) &
|
||||
~(ray_tracing_pipeline_properties.shaderGroupHandleAlignment - 1);
|
||||
|
||||
VkBufferCreateInfo buf_info = {0};
|
||||
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buf_info.pNext = NULL;
|
||||
buf_info.size = handle_size;
|
||||
buf_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
buf_info.flags = 0;
|
||||
|
||||
vkCreateBuffer(vk_ctx.device, &buf_info, NULL, &pipeline->impl.raygen_shader_binding_table);
|
||||
vkCreateBuffer(vk_ctx.device, &buf_info, NULL, &pipeline->impl.hit_shader_binding_table);
|
||||
vkCreateBuffer(vk_ctx.device, &buf_info, NULL, &pipeline->impl.miss_shader_binding_table);
|
||||
|
||||
uint8_t shader_handle_storage[1024];
|
||||
_vkGetRayTracingShaderGroupHandlesKHR(vk_ctx.device, pipeline->impl.pipeline, 0, 3, handle_size_aligned * 3, shader_handle_storage);
|
||||
|
||||
VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {0};
|
||||
memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
|
||||
memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
|
||||
|
||||
VkMemoryAllocateInfo memory_allocate_info = {0};
|
||||
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memory_allocate_info.pNext = &memory_allocate_flags_info;
|
||||
|
||||
VkMemoryRequirements mem_reqs = {0};
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, pipeline->impl.raygen_shader_binding_table, &mem_reqs);
|
||||
memory_allocate_info.allocationSize = mem_reqs.size;
|
||||
memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
|
||||
&memory_allocate_info.memoryTypeIndex);
|
||||
|
||||
VkDeviceMemory mem;
|
||||
void *data;
|
||||
vkAllocateMemory(vk_ctx.device, &memory_allocate_info, NULL, &mem);
|
||||
vkBindBufferMemory(vk_ctx.device, pipeline->impl.raygen_shader_binding_table, mem, 0);
|
||||
vkMapMemory(vk_ctx.device, mem, 0, handle_size, 0, (void **)&data);
|
||||
memcpy(data, shader_handle_storage, handle_size);
|
||||
vkUnmapMemory(vk_ctx.device, mem);
|
||||
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, pipeline->impl.miss_shader_binding_table, &mem_reqs);
|
||||
memory_allocate_info.allocationSize = mem_reqs.size;
|
||||
memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memory_allocate_info.memoryTypeIndex);
|
||||
|
||||
vkAllocateMemory(vk_ctx.device, &memory_allocate_info, NULL, &mem);
|
||||
vkBindBufferMemory(vk_ctx.device, pipeline->impl.miss_shader_binding_table, mem, 0);
|
||||
vkMapMemory(vk_ctx.device, mem, 0, handle_size, 0, (void **)&data);
|
||||
memcpy(data, shader_handle_storage + handle_size_aligned, handle_size);
|
||||
vkUnmapMemory(vk_ctx.device, mem);
|
||||
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, pipeline->impl.hit_shader_binding_table, &mem_reqs);
|
||||
memory_allocate_info.allocationSize = mem_reqs.size;
|
||||
memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memory_allocate_info.memoryTypeIndex);
|
||||
|
||||
vkAllocateMemory(vk_ctx.device, &memory_allocate_info, NULL, &mem);
|
||||
vkBindBufferMemory(vk_ctx.device, pipeline->impl.hit_shader_binding_table, mem, 0);
|
||||
vkMapMemory(vk_ctx.device, mem, 0, handle_size, 0, (void **)&data);
|
||||
memcpy(data, shader_handle_storage + handle_size_aligned * 2, handle_size);
|
||||
vkUnmapMemory(vk_ctx.device, mem);
|
||||
}
|
||||
|
||||
{
|
||||
VkDescriptorPoolSize type_counts[3];
|
||||
memset(type_counts, 0, sizeof(type_counts));
|
||||
|
||||
type_counts[0].type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
|
||||
type_counts[0].descriptorCount = 1;
|
||||
|
||||
type_counts[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
type_counts[1].descriptorCount = 1;
|
||||
|
||||
type_counts[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
type_counts[2].descriptorCount = 1;
|
||||
|
||||
VkDescriptorPoolCreateInfo descriptor_pool_create_info = {0};
|
||||
descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
descriptor_pool_create_info.pNext = NULL;
|
||||
descriptor_pool_create_info.maxSets = 1024;
|
||||
descriptor_pool_create_info.poolSizeCount = 3;
|
||||
descriptor_pool_create_info.pPoolSizes = type_counts;
|
||||
|
||||
vkCreateDescriptorPool(vk_ctx.device, &descriptor_pool_create_info, NULL, &raytrace_descriptor_pool);
|
||||
|
||||
VkDescriptorSetAllocateInfo alloc_info = {0};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
alloc_info.pNext = NULL;
|
||||
alloc_info.descriptorPool = raytrace_descriptor_pool;
|
||||
alloc_info.descriptorSetCount = 1;
|
||||
alloc_info.pSetLayouts = &pipeline->impl.descriptor_set_layout;
|
||||
vkAllocateDescriptorSets(vk_ctx.device, &alloc_info, &pipeline->impl.descriptor_set);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_raytrace_pipeline_destroy(kinc_raytrace_pipeline_t *pipeline) {
|
||||
vkDestroyPipeline(vk_ctx.device, pipeline->impl.pipeline, NULL);
|
||||
vkDestroyPipelineLayout(vk_ctx.device, pipeline->impl.pipeline_layout, NULL);
|
||||
vkDestroyDescriptorSetLayout(vk_ctx.device, pipeline->impl.descriptor_set_layout, NULL);
|
||||
}
|
||||
|
||||
uint64_t get_buffer_device_address(VkBuffer buffer) {
|
||||
VkBufferDeviceAddressInfoKHR buffer_device_address_info = {0};
|
||||
buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
|
||||
buffer_device_address_info.buffer = buffer;
|
||||
_vkGetBufferDeviceAddressKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkGetBufferDeviceAddressKHR");
|
||||
return _vkGetBufferDeviceAddressKHR(vk_ctx.device, &buffer_device_address_info);
|
||||
}
|
||||
|
||||
void kinc_raytrace_acceleration_structure_init(kinc_raytrace_acceleration_structure_t *accel, kinc_g5_command_list_t *command_list, kinc_g5_vertex_buffer_t *vb,
|
||||
kinc_g5_index_buffer_t *ib) {
|
||||
_vkGetBufferDeviceAddressKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkGetBufferDeviceAddressKHR");
|
||||
_vkCreateAccelerationStructureKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkCreateAccelerationStructureKHR");
|
||||
_vkGetAccelerationStructureDeviceAddressKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkGetAccelerationStructureDeviceAddressKHR");
|
||||
_vkGetAccelerationStructureBuildSizesKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkGetAccelerationStructureBuildSizesKHR");
|
||||
|
||||
{
|
||||
VkDeviceOrHostAddressConstKHR vertex_data_device_address = {0};
|
||||
VkDeviceOrHostAddressConstKHR index_data_device_address = {0};
|
||||
|
||||
vertex_data_device_address.deviceAddress = get_buffer_device_address(vb->impl.vertices.buf);
|
||||
index_data_device_address.deviceAddress = get_buffer_device_address(ib->impl.buf);
|
||||
|
||||
VkAccelerationStructureGeometryKHR acceleration_geometry = {0};
|
||||
acceleration_geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
|
||||
acceleration_geometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||
acceleration_geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||
acceleration_geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
|
||||
acceleration_geometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
acceleration_geometry.geometry.triangles.vertexData.deviceAddress = vertex_data_device_address.deviceAddress;
|
||||
acceleration_geometry.geometry.triangles.vertexStride = vb->impl.myStride;
|
||||
acceleration_geometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
|
||||
acceleration_geometry.geometry.triangles.indexData.deviceAddress = index_data_device_address.deviceAddress;
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR acceleration_structure_build_geometry_info = {0};
|
||||
acceleration_structure_build_geometry_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
||||
acceleration_structure_build_geometry_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||
acceleration_structure_build_geometry_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
acceleration_structure_build_geometry_info.geometryCount = 1;
|
||||
acceleration_structure_build_geometry_info.pGeometries = &acceleration_geometry;
|
||||
|
||||
VkAccelerationStructureBuildSizesInfoKHR acceleration_build_sizes_info = {0};
|
||||
acceleration_build_sizes_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
|
||||
const uint32_t primitive_count = 1;
|
||||
_vkGetAccelerationStructureBuildSizesKHR(vk_ctx.device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &acceleration_structure_build_geometry_info,
|
||||
&primitive_count, &acceleration_build_sizes_info);
|
||||
|
||||
VkBufferCreateInfo buffer_create_info = {0};
|
||||
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_create_info.size = acceleration_build_sizes_info.accelerationStructureSize;
|
||||
buffer_create_info.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
|
||||
buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VkBuffer bottom_level_buffer = VK_NULL_HANDLE;
|
||||
vkCreateBuffer(vk_ctx.device, &buffer_create_info, NULL, &bottom_level_buffer);
|
||||
|
||||
VkMemoryRequirements memory_requirements2;
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, bottom_level_buffer, &memory_requirements2);
|
||||
|
||||
VkMemoryAllocateFlagsInfo memory_allocate_flags_info2 = {0};
|
||||
memory_allocate_flags_info2.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
|
||||
memory_allocate_flags_info2.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
|
||||
|
||||
VkMemoryAllocateInfo memory_allocate_info = {0};
|
||||
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memory_allocate_info.pNext = &memory_allocate_flags_info2;
|
||||
memory_allocate_info.allocationSize = memory_requirements2.size;
|
||||
memory_type_from_properties(memory_requirements2.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memory_allocate_info.memoryTypeIndex);
|
||||
VkDeviceMemory mem;
|
||||
vkAllocateMemory(vk_ctx.device, &memory_allocate_info, NULL, &mem);
|
||||
vkBindBufferMemory(vk_ctx.device, bottom_level_buffer, mem, 0);
|
||||
|
||||
VkAccelerationStructureCreateInfoKHR acceleration_create_info = {0};
|
||||
acceleration_create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
|
||||
acceleration_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||
acceleration_create_info.buffer = bottom_level_buffer;
|
||||
acceleration_create_info.size = acceleration_build_sizes_info.accelerationStructureSize;
|
||||
_vkCreateAccelerationStructureKHR(vk_ctx.device, &acceleration_create_info, NULL, &accel->impl.bottom_level_acceleration_structure);
|
||||
|
||||
VkBuffer scratch_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory scratch_memory = VK_NULL_HANDLE;
|
||||
|
||||
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_create_info.size = acceleration_build_sizes_info.buildScratchSize;
|
||||
buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
vkCreateBuffer(vk_ctx.device, &buffer_create_info, NULL, &scratch_buffer);
|
||||
|
||||
VkMemoryRequirements memory_requirements;
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, scratch_buffer, &memory_requirements);
|
||||
|
||||
VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {0};
|
||||
memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
|
||||
memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
|
||||
|
||||
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memory_allocate_info.pNext = &memory_allocate_flags_info;
|
||||
memory_allocate_info.allocationSize = memory_requirements.size;
|
||||
memory_type_from_properties(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memory_allocate_info.memoryTypeIndex);
|
||||
vkAllocateMemory(vk_ctx.device, &memory_allocate_info, NULL, &scratch_memory);
|
||||
vkBindBufferMemory(vk_ctx.device, scratch_buffer, scratch_memory, 0);
|
||||
|
||||
VkBufferDeviceAddressInfoKHR buffer_device_address_info = {0};
|
||||
buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
|
||||
buffer_device_address_info.buffer = scratch_buffer;
|
||||
uint64_t scratch_buffer_device_address = _vkGetBufferDeviceAddressKHR(vk_ctx.device, &buffer_device_address_info);
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR acceleration_build_geometry_info = {0};
|
||||
acceleration_build_geometry_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
||||
acceleration_build_geometry_info.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||
acceleration_build_geometry_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
acceleration_build_geometry_info.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
||||
acceleration_build_geometry_info.dstAccelerationStructure = accel->impl.bottom_level_acceleration_structure;
|
||||
acceleration_build_geometry_info.geometryCount = 1;
|
||||
acceleration_build_geometry_info.pGeometries = &acceleration_geometry;
|
||||
acceleration_build_geometry_info.scratchData.deviceAddress = scratch_buffer_device_address;
|
||||
|
||||
VkAccelerationStructureBuildRangeInfoKHR acceleration_build_range_info = {0};
|
||||
acceleration_build_range_info.primitiveCount = 1;
|
||||
acceleration_build_range_info.primitiveOffset = 0x0;
|
||||
acceleration_build_range_info.firstVertex = 0;
|
||||
acceleration_build_range_info.transformOffset = 0x0;
|
||||
|
||||
const VkAccelerationStructureBuildRangeInfoKHR *acceleration_build_infos[1] = {&acceleration_build_range_info};
|
||||
|
||||
{
|
||||
VkCommandBufferAllocateInfo cmd_buf_allocate_info = {0};
|
||||
cmd_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
cmd_buf_allocate_info.commandPool = vk_ctx.cmd_pool;
|
||||
cmd_buf_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
cmd_buf_allocate_info.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer command_buffer;
|
||||
vkAllocateCommandBuffers(vk_ctx.device, &cmd_buf_allocate_info, &command_buffer);
|
||||
|
||||
VkCommandBufferBeginInfo command_buffer_info = {0};
|
||||
command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
vkBeginCommandBuffer(command_buffer, &command_buffer_info);
|
||||
|
||||
_vkCmdBuildAccelerationStructuresKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkCmdBuildAccelerationStructuresKHR");
|
||||
_vkCmdBuildAccelerationStructuresKHR(command_buffer, 1, &acceleration_build_geometry_info, &acceleration_build_infos[0]);
|
||||
|
||||
vkEndCommandBuffer(command_buffer);
|
||||
|
||||
VkSubmitInfo submit_info = {0};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &command_buffer;
|
||||
|
||||
VkFenceCreateInfo fence_info = {0};
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.flags = 0;
|
||||
|
||||
VkFence fence;
|
||||
vkCreateFence(vk_ctx.device, &fence_info, NULL, &fence);
|
||||
|
||||
VkResult result = vkQueueSubmit(vk_ctx.queue, 1, &submit_info, fence);
|
||||
assert(!result);
|
||||
vkWaitForFences(vk_ctx.device, 1, &fence, VK_TRUE, 100000000000);
|
||||
vkDestroyFence(vk_ctx.device, fence, NULL);
|
||||
vkFreeCommandBuffers(vk_ctx.device, vk_ctx.cmd_pool, 1, &command_buffer);
|
||||
}
|
||||
|
||||
VkAccelerationStructureDeviceAddressInfoKHR acceleration_device_address_info = {0};
|
||||
acceleration_device_address_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
|
||||
acceleration_device_address_info.accelerationStructure = accel->impl.bottom_level_acceleration_structure;
|
||||
|
||||
accel->impl.bottom_level_acceleration_structure_handle = _vkGetAccelerationStructureDeviceAddressKHR(vk_ctx.device, &acceleration_device_address_info);
|
||||
|
||||
vkFreeMemory(vk_ctx.device, scratch_memory, NULL);
|
||||
vkDestroyBuffer(vk_ctx.device, scratch_buffer, NULL);
|
||||
}
|
||||
|
||||
{
|
||||
VkTransformMatrixKHR transform_matrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f};
|
||||
|
||||
VkAccelerationStructureInstanceKHR instance = {0};
|
||||
instance.transform = transform_matrix;
|
||||
instance.instanceCustomIndex = 0;
|
||||
instance.mask = 0xFF;
|
||||
instance.instanceShaderBindingTableRecordOffset = 0;
|
||||
instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
instance.accelerationStructureReference = accel->impl.bottom_level_acceleration_structure_handle;
|
||||
|
||||
VkBufferCreateInfo buf_info = {0};
|
||||
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buf_info.pNext = NULL;
|
||||
buf_info.size = sizeof(instance);
|
||||
buf_info.usage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
buf_info.flags = 0;
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc;
|
||||
memset(&mem_alloc, 0, sizeof(VkMemoryAllocateInfo));
|
||||
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc.pNext = NULL;
|
||||
mem_alloc.allocationSize = 0;
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
|
||||
VkBuffer instances_buffer;
|
||||
vkCreateBuffer(vk_ctx.device, &buf_info, NULL, &instances_buffer);
|
||||
|
||||
VkMemoryRequirements mem_reqs = {0};
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, instances_buffer, &mem_reqs);
|
||||
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
memory_type_from_properties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &mem_alloc.memoryTypeIndex);
|
||||
|
||||
VkMemoryAllocateFlagsInfo memory_allocate_flags_info = {0};
|
||||
memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
|
||||
memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
|
||||
mem_alloc.pNext = &memory_allocate_flags_info;
|
||||
|
||||
VkDeviceMemory mem;
|
||||
vkAllocateMemory(vk_ctx.device, &mem_alloc, NULL, &mem);
|
||||
|
||||
vkBindBufferMemory(vk_ctx.device, instances_buffer, mem, 0);
|
||||
void *data;
|
||||
vkMapMemory(vk_ctx.device, mem, 0, sizeof(VkAccelerationStructureInstanceKHR), 0, (void **)&data);
|
||||
memcpy(data, &instance, sizeof(VkAccelerationStructureInstanceKHR));
|
||||
vkUnmapMemory(vk_ctx.device, mem);
|
||||
|
||||
VkDeviceOrHostAddressConstKHR instance_data_device_address = {0};
|
||||
instance_data_device_address.deviceAddress = get_buffer_device_address(instances_buffer);
|
||||
|
||||
VkAccelerationStructureGeometryKHR acceleration_geometry = {0};
|
||||
acceleration_geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
|
||||
acceleration_geometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||
acceleration_geometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
|
||||
acceleration_geometry.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
|
||||
acceleration_geometry.geometry.instances.arrayOfPointers = VK_FALSE;
|
||||
acceleration_geometry.geometry.instances.data.deviceAddress = instance_data_device_address.deviceAddress;
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR acceleration_structure_build_geometry_info = {0};
|
||||
acceleration_structure_build_geometry_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
||||
acceleration_structure_build_geometry_info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
||||
acceleration_structure_build_geometry_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
acceleration_structure_build_geometry_info.geometryCount = 1;
|
||||
acceleration_structure_build_geometry_info.pGeometries = &acceleration_geometry;
|
||||
|
||||
VkAccelerationStructureBuildSizesInfoKHR acceleration_build_sizes_info = {0};
|
||||
acceleration_build_sizes_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
|
||||
const uint32_t primitive_count = 1;
|
||||
_vkGetAccelerationStructureBuildSizesKHR(vk_ctx.device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &acceleration_structure_build_geometry_info,
|
||||
&primitive_count, &acceleration_build_sizes_info);
|
||||
|
||||
VkBufferCreateInfo buffer_create_info = {0};
|
||||
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_create_info.size = acceleration_build_sizes_info.accelerationStructureSize;
|
||||
buffer_create_info.usage = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
|
||||
buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VkBuffer top_level_buffer = VK_NULL_HANDLE;
|
||||
vkCreateBuffer(vk_ctx.device, &buffer_create_info, NULL, &top_level_buffer);
|
||||
|
||||
VkMemoryRequirements memory_requirements2;
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, top_level_buffer, &memory_requirements2);
|
||||
|
||||
memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
|
||||
memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
|
||||
|
||||
VkMemoryAllocateInfo memory_allocate_info = {0};
|
||||
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memory_allocate_info.pNext = &memory_allocate_flags_info;
|
||||
memory_allocate_info.allocationSize = memory_requirements2.size;
|
||||
memory_type_from_properties(memory_requirements2.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memory_allocate_info.memoryTypeIndex);
|
||||
vkAllocateMemory(vk_ctx.device, &memory_allocate_info, NULL, &mem);
|
||||
vkBindBufferMemory(vk_ctx.device, top_level_buffer, mem, 0);
|
||||
|
||||
VkAccelerationStructureCreateInfoKHR acceleration_create_info = {0};
|
||||
acceleration_create_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
|
||||
acceleration_create_info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
||||
acceleration_create_info.buffer = top_level_buffer;
|
||||
acceleration_create_info.size = acceleration_build_sizes_info.accelerationStructureSize;
|
||||
_vkCreateAccelerationStructureKHR(vk_ctx.device, &acceleration_create_info, NULL, &accel->impl.top_level_acceleration_structure);
|
||||
|
||||
VkBuffer scratch_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory scratch_memory = VK_NULL_HANDLE;
|
||||
|
||||
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_create_info.size = acceleration_build_sizes_info.buildScratchSize;
|
||||
buffer_create_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
vkCreateBuffer(vk_ctx.device, &buffer_create_info, NULL, &scratch_buffer);
|
||||
|
||||
VkMemoryRequirements memory_requirements;
|
||||
vkGetBufferMemoryRequirements(vk_ctx.device, scratch_buffer, &memory_requirements);
|
||||
|
||||
memory_allocate_flags_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
|
||||
memory_allocate_flags_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR;
|
||||
|
||||
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memory_allocate_info.pNext = &memory_allocate_flags_info;
|
||||
memory_allocate_info.allocationSize = memory_requirements.size;
|
||||
memory_type_from_properties(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memory_allocate_info.memoryTypeIndex);
|
||||
vkAllocateMemory(vk_ctx.device, &memory_allocate_info, NULL, &scratch_memory);
|
||||
vkBindBufferMemory(vk_ctx.device, scratch_buffer, scratch_memory, 0);
|
||||
|
||||
VkBufferDeviceAddressInfoKHR buffer_device_address_info = {0};
|
||||
buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
|
||||
buffer_device_address_info.buffer = scratch_buffer;
|
||||
uint64_t scratch_buffer_device_address = _vkGetBufferDeviceAddressKHR(vk_ctx.device, &buffer_device_address_info);
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR acceleration_build_geometry_info = {0};
|
||||
acceleration_build_geometry_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
||||
acceleration_build_geometry_info.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
||||
acceleration_build_geometry_info.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
acceleration_build_geometry_info.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
||||
acceleration_build_geometry_info.srcAccelerationStructure = VK_NULL_HANDLE;
|
||||
acceleration_build_geometry_info.dstAccelerationStructure = accel->impl.top_level_acceleration_structure;
|
||||
acceleration_build_geometry_info.geometryCount = 1;
|
||||
acceleration_build_geometry_info.pGeometries = &acceleration_geometry;
|
||||
acceleration_build_geometry_info.scratchData.deviceAddress = scratch_buffer_device_address;
|
||||
|
||||
VkAccelerationStructureBuildRangeInfoKHR acceleration_build_range_info = {0};
|
||||
acceleration_build_range_info.primitiveCount = 1;
|
||||
acceleration_build_range_info.primitiveOffset = 0x0;
|
||||
acceleration_build_range_info.firstVertex = 0;
|
||||
acceleration_build_range_info.transformOffset = 0x0;
|
||||
|
||||
const VkAccelerationStructureBuildRangeInfoKHR *acceleration_build_infos[1] = {&acceleration_build_range_info};
|
||||
|
||||
{
|
||||
VkCommandBufferAllocateInfo cmd_buf_allocate_info = {0};
|
||||
cmd_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
cmd_buf_allocate_info.commandPool = vk_ctx.cmd_pool;
|
||||
cmd_buf_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
cmd_buf_allocate_info.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer command_buffer;
|
||||
vkAllocateCommandBuffers(vk_ctx.device, &cmd_buf_allocate_info, &command_buffer);
|
||||
|
||||
VkCommandBufferBeginInfo command_buffer_info = {0};
|
||||
command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
vkBeginCommandBuffer(command_buffer, &command_buffer_info);
|
||||
|
||||
_vkCmdBuildAccelerationStructuresKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkCmdBuildAccelerationStructuresKHR");
|
||||
_vkCmdBuildAccelerationStructuresKHR(command_buffer, 1, &acceleration_build_geometry_info, &acceleration_build_infos[0]);
|
||||
|
||||
vkEndCommandBuffer(command_buffer);
|
||||
|
||||
VkSubmitInfo submit_info = {0};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &command_buffer;
|
||||
|
||||
VkFenceCreateInfo fence_info = {0};
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.flags = 0;
|
||||
|
||||
VkFence fence;
|
||||
vkCreateFence(vk_ctx.device, &fence_info, NULL, &fence);
|
||||
|
||||
VkResult result = vkQueueSubmit(vk_ctx.queue, 1, &submit_info, fence);
|
||||
assert(!result);
|
||||
vkWaitForFences(vk_ctx.device, 1, &fence, VK_TRUE, 100000000000);
|
||||
vkDestroyFence(vk_ctx.device, fence, NULL);
|
||||
|
||||
vkFreeCommandBuffers(vk_ctx.device, vk_ctx.cmd_pool, 1, &command_buffer);
|
||||
}
|
||||
|
||||
VkAccelerationStructureDeviceAddressInfoKHR acceleration_device_address_info = {0};
|
||||
acceleration_device_address_info.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
|
||||
acceleration_device_address_info.accelerationStructure = accel->impl.top_level_acceleration_structure;
|
||||
|
||||
accel->impl.top_level_acceleration_structure_handle = _vkGetAccelerationStructureDeviceAddressKHR(vk_ctx.device, &acceleration_device_address_info);
|
||||
|
||||
vkFreeMemory(vk_ctx.device, scratch_memory, NULL);
|
||||
vkDestroyBuffer(vk_ctx.device, scratch_buffer, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_raytrace_acceleration_structure_destroy(kinc_raytrace_acceleration_structure_t *accel) {
|
||||
_vkDestroyAccelerationStructureKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkDestroyAccelerationStructureKHR");
|
||||
_vkDestroyAccelerationStructureKHR(vk_ctx.device, accel->impl.bottom_level_acceleration_structure, NULL);
|
||||
_vkDestroyAccelerationStructureKHR(vk_ctx.device, accel->impl.top_level_acceleration_structure, NULL);
|
||||
}
|
||||
|
||||
void kinc_raytrace_set_acceleration_structure(kinc_raytrace_acceleration_structure_t *_accel) {
|
||||
accel = _accel;
|
||||
}
|
||||
|
||||
void kinc_raytrace_set_pipeline(kinc_raytrace_pipeline_t *_pipeline) {
|
||||
pipeline = _pipeline;
|
||||
}
|
||||
|
||||
void kinc_raytrace_set_target(kinc_g5_texture_t *_output) {
|
||||
output = _output;
|
||||
}
|
||||
|
||||
void kinc_raytrace_dispatch_rays(kinc_g5_command_list_t *command_list) {
|
||||
VkWriteDescriptorSetAccelerationStructureKHR descriptor_acceleration_structure_info = {0};
|
||||
descriptor_acceleration_structure_info.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
|
||||
descriptor_acceleration_structure_info.accelerationStructureCount = 1;
|
||||
descriptor_acceleration_structure_info.pAccelerationStructures = &accel->impl.top_level_acceleration_structure;
|
||||
|
||||
VkWriteDescriptorSet acceleration_structure_write = {0};
|
||||
acceleration_structure_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
acceleration_structure_write.pNext = &descriptor_acceleration_structure_info;
|
||||
acceleration_structure_write.dstSet = pipeline->impl.descriptor_set;
|
||||
acceleration_structure_write.dstBinding = 0;
|
||||
acceleration_structure_write.descriptorCount = 1;
|
||||
acceleration_structure_write.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
|
||||
|
||||
VkDescriptorImageInfo image_descriptor = {0};
|
||||
image_descriptor.imageView = output->impl.texture.view;
|
||||
image_descriptor.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
VkDescriptorBufferInfo buffer_descriptor = {0};
|
||||
buffer_descriptor.buffer = pipeline->_constant_buffer->impl.buf;
|
||||
buffer_descriptor.range = VK_WHOLE_SIZE;
|
||||
buffer_descriptor.offset = 0;
|
||||
|
||||
VkWriteDescriptorSet result_image_write = {0};
|
||||
result_image_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
result_image_write.pNext = NULL;
|
||||
result_image_write.dstSet = pipeline->impl.descriptor_set;
|
||||
result_image_write.dstBinding = 1;
|
||||
result_image_write.descriptorCount = 1;
|
||||
result_image_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
result_image_write.pImageInfo = &image_descriptor;
|
||||
|
||||
VkWriteDescriptorSet uniform_buffer_write = {0};
|
||||
uniform_buffer_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
uniform_buffer_write.pNext = NULL;
|
||||
uniform_buffer_write.dstSet = pipeline->impl.descriptor_set;
|
||||
uniform_buffer_write.dstBinding = 2;
|
||||
uniform_buffer_write.descriptorCount = 1;
|
||||
uniform_buffer_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
uniform_buffer_write.pBufferInfo = &buffer_descriptor;
|
||||
|
||||
VkWriteDescriptorSet write_descriptor_sets[3] = {acceleration_structure_write, result_image_write, uniform_buffer_write};
|
||||
vkUpdateDescriptorSets(vk_ctx.device, 3, write_descriptor_sets, 0, VK_NULL_HANDLE);
|
||||
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR ray_tracing_pipeline_properties;
|
||||
ray_tracing_pipeline_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
|
||||
ray_tracing_pipeline_properties.pNext = NULL;
|
||||
VkPhysicalDeviceProperties2 device_properties = {0};
|
||||
device_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
device_properties.pNext = &ray_tracing_pipeline_properties;
|
||||
vkGetPhysicalDeviceProperties2(vk_ctx.gpu, &device_properties);
|
||||
|
||||
// Setup the strided buffer regions pointing to the shaders in our shader binding table
|
||||
const uint32_t handle_size_aligned =
|
||||
(ray_tracing_pipeline_properties.shaderGroupHandleSize + ray_tracing_pipeline_properties.shaderGroupHandleAlignment - 1) &
|
||||
~(ray_tracing_pipeline_properties.shaderGroupHandleAlignment - 1);
|
||||
|
||||
VkStridedDeviceAddressRegionKHR raygen_shader_sbt_entry = {0};
|
||||
raygen_shader_sbt_entry.deviceAddress = get_buffer_device_address(pipeline->impl.raygen_shader_binding_table);
|
||||
raygen_shader_sbt_entry.stride = handle_size_aligned;
|
||||
raygen_shader_sbt_entry.size = handle_size_aligned;
|
||||
|
||||
VkStridedDeviceAddressRegionKHR miss_shader_sbt_entry = {0};
|
||||
miss_shader_sbt_entry.deviceAddress = get_buffer_device_address(pipeline->impl.miss_shader_binding_table);
|
||||
miss_shader_sbt_entry.stride = handle_size_aligned;
|
||||
miss_shader_sbt_entry.size = handle_size_aligned;
|
||||
|
||||
VkStridedDeviceAddressRegionKHR hit_shader_sbt_entry = {0};
|
||||
hit_shader_sbt_entry.deviceAddress = get_buffer_device_address(pipeline->impl.hit_shader_binding_table);
|
||||
hit_shader_sbt_entry.stride = handle_size_aligned;
|
||||
hit_shader_sbt_entry.size = handle_size_aligned;
|
||||
|
||||
VkStridedDeviceAddressRegionKHR callable_shader_sbt_entry = {0};
|
||||
|
||||
vkCmdEndRenderPass(command_list->impl._buffer);
|
||||
|
||||
// Dispatch the ray tracing commands
|
||||
vkCmdBindPipeline(command_list->impl._buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline->impl.pipeline);
|
||||
vkCmdBindDescriptorSets(command_list->impl._buffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline->impl.pipeline_layout, 0, 1,
|
||||
&pipeline->impl.descriptor_set, 0, 0);
|
||||
|
||||
_vkCmdTraceRaysKHR = (void *)vkGetDeviceProcAddr(vk_ctx.device, "vkCmdTraceRaysKHR");
|
||||
_vkCmdTraceRaysKHR(command_list->impl._buffer, &raygen_shader_sbt_entry, &miss_shader_sbt_entry, &hit_shader_sbt_entry, &callable_shader_sbt_entry,
|
||||
output->texWidth, output->texHeight, 1);
|
||||
|
||||
vkCmdBeginRenderPass(command_list->impl._buffer, ¤tRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
void kinc_raytrace_copy(kinc_g5_command_list_t *command_list, kinc_g5_render_target_t *target, kinc_g5_texture_t *source) {
|
||||
|
||||
vkCmdEndRenderPass(command_list->impl._buffer);
|
||||
|
||||
VkImageCopy copy_region = {0};
|
||||
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.srcSubresource.layerCount = 1;
|
||||
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
copy_region.dstSubresource.layerCount = 1;
|
||||
copy_region.extent.width = (uint32_t)output->texWidth;
|
||||
copy_region.extent.height = (uint32_t)output->texHeight;
|
||||
copy_region.extent.depth = 1;
|
||||
|
||||
if (target->framebuffer_index >= 0) {
|
||||
vkCmdCopyImage(command_list->impl._buffer, output->impl.texture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
vk_ctx.windows[vk_ctx.current_window].images[vk_ctx.windows[vk_ctx.current_window].current_image], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, ©_region);
|
||||
}
|
||||
else {
|
||||
vkCmdCopyImage(command_list->impl._buffer, output->impl.texture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, target->impl.sourceImage,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
||||
}
|
||||
|
||||
vkCmdBeginRenderPass(command_list->impl._buffer, ¤tRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef KINC_ANDROID
|
||||
|
||||
#include "MiniVulkan.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout pipeline_layout;
|
||||
VkDescriptorSet descriptor_set;
|
||||
VkDescriptorSetLayout descriptor_set_layout;
|
||||
VkBuffer raygen_shader_binding_table;
|
||||
VkBuffer miss_shader_binding_table;
|
||||
VkBuffer hit_shader_binding_table;
|
||||
} kinc_raytrace_pipeline_impl_t;
|
||||
|
||||
typedef struct {
|
||||
VkAccelerationStructureKHR top_level_acceleration_structure;
|
||||
VkAccelerationStructureKHR bottom_level_acceleration_structure;
|
||||
uint64_t top_level_acceleration_structure_handle;
|
||||
uint64_t bottom_level_acceleration_structure_handle;
|
||||
} kinc_raytrace_acceleration_structure_impl_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,331 @@
|
||||
#include "vulkan.h"
|
||||
|
||||
#include "rendertarget.h"
|
||||
|
||||
#include <kinc/graphics5/rendertarget.h>
|
||||
#include <kinc/graphics5/texture.h>
|
||||
#include <kinc/log.h>
|
||||
|
||||
extern uint32_t swapchainImageCount;
|
||||
extern kinc_g5_texture_t *vulkanTextures[16];
|
||||
extern kinc_g5_render_target_t *vulkanRenderTargets[16];
|
||||
|
||||
bool memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
|
||||
void setup_init_cmd();
|
||||
|
||||
/*static VkFormat convert_format(kinc_g5_render_target_format_t format) {
|
||||
switch (format) {
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_128BIT_FLOAT:
|
||||
return VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_64BIT_FLOAT:
|
||||
return VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT:
|
||||
return VK_FORMAT_R32_SFLOAT;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT:
|
||||
return VK_FORMAT_R16_SFLOAT;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_8BIT_RED:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
case KINC_G5_RENDER_TARGET_FORMAT_32BIT:
|
||||
default:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
}
|
||||
}*/
|
||||
|
||||
void setImageLayout(VkCommandBuffer _buffer, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout) {
|
||||
VkImageMemoryBarrier imageMemoryBarrier = {0};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.pNext = NULL;
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
imageMemoryBarrier.oldLayout = oldImageLayout;
|
||||
imageMemoryBarrier.newLayout = newImageLayout;
|
||||
imageMemoryBarrier.image = image;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = aspectMask;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
|
||||
if (oldImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
if (oldImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
if (oldImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
}
|
||||
if (oldImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
}
|
||||
if (newImageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
}
|
||||
if (newImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
|
||||
if (oldImageLayout != VK_IMAGE_LAYOUT_UNDEFINED)
|
||||
imageMemoryBarrier.srcAccessMask = imageMemoryBarrier.srcAccessMask | VK_ACCESS_TRANSFER_READ_BIT;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
}
|
||||
if (newImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
if (oldImageLayout != VK_IMAGE_LAYOUT_UNDEFINED)
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
}
|
||||
if (newImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
if (newImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
if (oldImageLayout != VK_IMAGE_LAYOUT_UNDEFINED)
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags srcStageFlags = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||
VkPipelineStageFlags dstStageFlags = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(_buffer, srcStageFlags, dstStageFlags, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier);
|
||||
}
|
||||
|
||||
static void render_target_init(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, int framebuffer_index) {
|
||||
target->width = width;
|
||||
target->height = height;
|
||||
target->framebuffer_index = framebuffer_index;
|
||||
target->texWidth = width;
|
||||
target->texHeight = height;
|
||||
target->impl.format = convert_format(format);
|
||||
target->impl.depthBufferBits = depthBufferBits;
|
||||
target->impl.stage = 0;
|
||||
target->impl.stage_depth = -1;
|
||||
target->impl.readbackBufferCreated = false;
|
||||
|
||||
if (framebuffer_index < 0) {
|
||||
{
|
||||
VkFormatProperties formatProperties;
|
||||
VkResult err;
|
||||
|
||||
vkGetPhysicalDeviceFormatProperties(vk_ctx.gpu, target->impl.format, &formatProperties);
|
||||
assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
|
||||
|
||||
VkImageCreateInfo image = {0};
|
||||
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image.pNext = NULL;
|
||||
image.imageType = VK_IMAGE_TYPE_2D;
|
||||
image.format = target->impl.format;
|
||||
image.extent.width = width;
|
||||
image.extent.height = height;
|
||||
image.extent.depth = 1;
|
||||
image.mipLevels = 1;
|
||||
image.arrayLayers = 1;
|
||||
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
image.flags = 0;
|
||||
|
||||
VkImageViewCreateInfo colorImageView = {0};
|
||||
colorImageView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
colorImageView.pNext = NULL;
|
||||
colorImageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
colorImageView.format = target->impl.format;
|
||||
colorImageView.flags = 0;
|
||||
colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
colorImageView.subresourceRange.baseMipLevel = 0;
|
||||
colorImageView.subresourceRange.levelCount = 1;
|
||||
colorImageView.subresourceRange.baseArrayLayer = 0;
|
||||
colorImageView.subresourceRange.layerCount = 1;
|
||||
|
||||
err = vkCreateImage(vk_ctx.device, &image, NULL, &target->impl.sourceImage);
|
||||
assert(!err);
|
||||
|
||||
VkMemoryRequirements memoryRequirements;
|
||||
vkGetImageMemoryRequirements(vk_ctx.device, target->impl.sourceImage, &memoryRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocationInfo = {0};
|
||||
allocationInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocationInfo.pNext = NULL;
|
||||
allocationInfo.memoryTypeIndex = 0;
|
||||
allocationInfo.allocationSize = memoryRequirements.size;
|
||||
bool pass = memory_type_from_properties(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocationInfo.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
err = vkAllocateMemory(vk_ctx.device, &allocationInfo, NULL, &target->impl.sourceMemory);
|
||||
assert(!err);
|
||||
|
||||
err = vkBindImageMemory(vk_ctx.device, target->impl.sourceImage, target->impl.sourceMemory, 0);
|
||||
assert(!err);
|
||||
|
||||
setup_init_cmd();
|
||||
setImageLayout(vk_ctx.setup_cmd, target->impl.sourceImage, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
flush_init_cmd();
|
||||
|
||||
colorImageView.image = target->impl.sourceImage;
|
||||
err = vkCreateImageView(vk_ctx.device, &colorImageView, NULL, &target->impl.sourceView);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
if (depthBufferBits > 0) {
|
||||
const VkFormat depth_format = VK_FORMAT_D16_UNORM;
|
||||
VkImageCreateInfo image = {0};
|
||||
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image.pNext = NULL;
|
||||
image.imageType = VK_IMAGE_TYPE_2D;
|
||||
image.format = depth_format;
|
||||
image.extent.width = width;
|
||||
image.extent.height = height;
|
||||
image.extent.depth = 1;
|
||||
image.mipLevels = 1;
|
||||
image.arrayLayers = 1;
|
||||
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image.flags = 0;
|
||||
|
||||
VkResult err = vkCreateImage(vk_ctx.device, &image, NULL, &target->impl.depthImage);
|
||||
assert(!err);
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc = {0};
|
||||
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
mem_alloc.pNext = NULL;
|
||||
mem_alloc.allocationSize = 0;
|
||||
mem_alloc.memoryTypeIndex = 0;
|
||||
|
||||
VkImageViewCreateInfo view = {0};
|
||||
view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
view.pNext = NULL;
|
||||
view.image = target->impl.depthImage;
|
||||
view.format = depth_format;
|
||||
view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
view.subresourceRange.baseMipLevel = 0;
|
||||
view.subresourceRange.levelCount = 1;
|
||||
view.subresourceRange.baseArrayLayer = 0;
|
||||
view.subresourceRange.layerCount = 1;
|
||||
view.flags = 0;
|
||||
view.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
|
||||
VkMemoryRequirements mem_reqs = {0};
|
||||
bool pass;
|
||||
|
||||
/* get memory requirements for this object */
|
||||
vkGetImageMemoryRequirements(vk_ctx.device, target->impl.depthImage, &mem_reqs);
|
||||
|
||||
/* select memory size and type */
|
||||
mem_alloc.allocationSize = mem_reqs.size;
|
||||
pass = memory_type_from_properties(mem_reqs.memoryTypeBits, 0, /* No requirements */ &mem_alloc.memoryTypeIndex);
|
||||
assert(pass);
|
||||
|
||||
/* allocate memory */
|
||||
err = vkAllocateMemory(vk_ctx.device, &mem_alloc, NULL, &target->impl.depthMemory);
|
||||
assert(!err);
|
||||
|
||||
/* bind memory */
|
||||
err = vkBindImageMemory(vk_ctx.device, target->impl.depthImage, target->impl.depthMemory, 0);
|
||||
assert(!err);
|
||||
|
||||
setup_init_cmd();
|
||||
setImageLayout(vk_ctx.setup_cmd, target->impl.depthImage, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
flush_init_cmd();
|
||||
|
||||
/* create image view */
|
||||
err = vkCreateImageView(vk_ctx.device, &view, NULL, &target->impl.depthView);
|
||||
assert(!err);
|
||||
}
|
||||
|
||||
VkImageView attachments[2];
|
||||
attachments[0] = target->impl.sourceView;
|
||||
|
||||
if (depthBufferBits > 0) {
|
||||
attachments[1] = target->impl.depthView;
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo fbufCreateInfo = {0};
|
||||
fbufCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
fbufCreateInfo.pNext = NULL;
|
||||
if (framebuffer_index >= 0) {
|
||||
fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].framebuffer_render_pass;
|
||||
}
|
||||
else if (depthBufferBits > 0) {
|
||||
fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass_with_depth;
|
||||
}
|
||||
else {
|
||||
fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass;
|
||||
}
|
||||
fbufCreateInfo.attachmentCount = depthBufferBits > 0 ? 2 : 1;
|
||||
fbufCreateInfo.pAttachments = attachments;
|
||||
fbufCreateInfo.width = width;
|
||||
fbufCreateInfo.height = height;
|
||||
fbufCreateInfo.layers = 1;
|
||||
|
||||
VkResult err = vkCreateFramebuffer(vk_ctx.device, &fbufCreateInfo, NULL, &target->impl.framebuffer);
|
||||
assert(!err);
|
||||
}
|
||||
}
|
||||
|
||||
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 *target, int cubeMapSize, kinc_g5_render_target_format_t format,
|
||||
int depthBufferBits, int stencilBufferBits, int samples_per_pixel) {}
|
||||
|
||||
void kinc_g5_render_target_destroy(kinc_g5_render_target_t *target) {
|
||||
if (target->framebuffer_index >= 0) {
|
||||
framebuffer_count -= 1;
|
||||
}
|
||||
else {
|
||||
vkDestroyFramebuffer(vk_ctx.device, target->impl.framebuffer, NULL);
|
||||
if (target->impl.depthBufferBits > 0) {
|
||||
vkDestroyImageView(vk_ctx.device, target->impl.depthView, NULL);
|
||||
vkDestroyImage(vk_ctx.device, target->impl.depthImage, NULL);
|
||||
vkFreeMemory(vk_ctx.device, target->impl.depthMemory, NULL);
|
||||
}
|
||||
vkDestroyImageView(vk_ctx.device, target->impl.sourceView, NULL);
|
||||
vkDestroyImage(vk_ctx.device, target->impl.sourceImage, NULL);
|
||||
vkFreeMemory(vk_ctx.device, target->impl.sourceMemory, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_render_target_set_depth_stencil_from(kinc_g5_render_target_t *target, kinc_g5_render_target_t *source) {
|
||||
target->impl.depthImage = source->impl.depthImage;
|
||||
target->impl.depthMemory = source->impl.depthMemory;
|
||||
target->impl.depthView = source->impl.depthView;
|
||||
target->impl.depthBufferBits = source->impl.depthBufferBits;
|
||||
|
||||
// vkDestroyFramebuffer(vk_ctx.device, target->impl.framebuffer, nullptr);
|
||||
|
||||
{
|
||||
VkImageView attachments[2];
|
||||
attachments[0] = target->impl.sourceView;
|
||||
|
||||
if (target->impl.depthBufferBits > 0) {
|
||||
attachments[1] = target->impl.depthView;
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo fbufCreateInfo = {0};
|
||||
fbufCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
fbufCreateInfo.pNext = NULL;
|
||||
if (target->impl.depthBufferBits > 0) {
|
||||
fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass_with_depth;
|
||||
}
|
||||
else {
|
||||
fbufCreateInfo.renderPass = vk_ctx.windows[vk_ctx.current_window].rendertarget_render_pass;
|
||||
}
|
||||
fbufCreateInfo.attachmentCount = target->impl.depthBufferBits > 0 ? 2 : 1;
|
||||
fbufCreateInfo.pAttachments = attachments;
|
||||
fbufCreateInfo.width = target->width;
|
||||
fbufCreateInfo.height = target->height;
|
||||
fbufCreateInfo.layers = 1;
|
||||
|
||||
VkResult err = vkCreateFramebuffer(vk_ctx.device, &fbufCreateInfo, NULL, &target->impl.framebuffer);
|
||||
assert(!err);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "MiniVulkan.h"
|
||||
|
||||
typedef struct {
|
||||
VkImage sourceImage;
|
||||
VkDeviceMemory sourceMemory;
|
||||
VkImageView sourceView;
|
||||
|
||||
VkImage depthImage;
|
||||
VkDeviceMemory depthMemory;
|
||||
VkImageView depthView;
|
||||
int depthBufferBits;
|
||||
|
||||
VkFramebuffer framebuffer;
|
||||
|
||||
VkFormat format;
|
||||
|
||||
VkBuffer readbackBuffer;
|
||||
VkDeviceMemory readbackMemory;
|
||||
bool readbackBufferCreated;
|
||||
|
||||
int stage;
|
||||
int stage_depth;
|
||||
} RenderTarget5Impl;
|
@ -0,0 +1,78 @@
|
||||
#include <kinc/graphics5/sampler.h>
|
||||
|
||||
static VkCompareOp convert_compare_mode(kinc_g5_compare_mode_t compare);
|
||||
|
||||
static VkSamplerAddressMode convert_addressing(kinc_g5_texture_addressing_t mode) {
|
||||
switch (mode) {
|
||||
case KINC_G5_TEXTURE_ADDRESSING_REPEAT:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_BORDER:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_CLAMP:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case KINC_G5_TEXTURE_ADDRESSING_MIRROR:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
default:
|
||||
assert(false);
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
}
|
||||
}
|
||||
|
||||
static VkSamplerMipmapMode convert_mipmap_mode(kinc_g5_mipmap_filter_t filter) {
|
||||
switch (filter) {
|
||||
case KINC_G5_MIPMAP_FILTER_NONE:
|
||||
case KINC_G5_MIPMAP_FILTER_POINT:
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
case KINC_G5_MIPMAP_FILTER_LINEAR:
|
||||
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
default:
|
||||
assert(false);
|
||||
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
static VkFilter convert_texture_filter(kinc_g5_texture_filter_t filter) {
|
||||
switch (filter) {
|
||||
case KINC_G5_TEXTURE_FILTER_POINT:
|
||||
return VK_FILTER_NEAREST;
|
||||
case KINC_G5_TEXTURE_FILTER_LINEAR:
|
||||
return VK_FILTER_LINEAR;
|
||||
case KINC_G5_TEXTURE_FILTER_ANISOTROPIC:
|
||||
return VK_FILTER_LINEAR; // ?
|
||||
default:
|
||||
assert(false);
|
||||
return VK_FILTER_NEAREST;
|
||||
}
|
||||
}
|
||||
|
||||
void kinc_g5_sampler_init(kinc_g5_sampler_t *sampler, const kinc_g5_sampler_options_t *options) {
|
||||
VkSamplerCreateInfo info = {0};
|
||||
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
info.pNext = NULL;
|
||||
info.flags = 0;
|
||||
|
||||
info.addressModeU = convert_addressing(options->u_addressing);
|
||||
info.addressModeV = convert_addressing(options->v_addressing);
|
||||
info.addressModeW = convert_addressing(options->w_addressing);
|
||||
|
||||
info.mipmapMode = convert_mipmap_mode(options->mipmap_filter);
|
||||
|
||||
info.magFilter = convert_texture_filter(options->magnification_filter);
|
||||
info.minFilter = convert_texture_filter(options->minification_filter);
|
||||
|
||||
info.compareEnable = options->is_comparison;
|
||||
info.compareOp = convert_compare_mode(options->compare_mode);
|
||||
|
||||
info.anisotropyEnable =
|
||||
(options->magnification_filter == KINC_G5_TEXTURE_FILTER_ANISOTROPIC || options->minification_filter == KINC_G5_TEXTURE_FILTER_ANISOTROPIC);
|
||||
info.maxAnisotropy = options->max_anisotropy;
|
||||
|
||||
info.maxLod = options->lod_max_clamp;
|
||||
info.minLod = options->lod_min_clamp;
|
||||
|
||||
vkCreateSampler(vk_ctx.device, &info, NULL, &sampler->impl.sampler);
|
||||
}
|
||||
|
||||
void kinc_g5_sampler_destroy(kinc_g5_sampler_t *sampler) {
|
||||
vkDestroySampler(vk_ctx.device, sampler->impl.sampler, NULL);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user