Kinc to Kore

This commit is contained in:
Gorochu
2026-06-09 13:00:08 -07:00
parent 7558d03739
commit c24828f11d
895 changed files with 0 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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[KINC_INTERNAL_D3D12_SWAP_CHAIN_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[KINC_INTERNAL_D3D12_SWAP_CHAIN_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[KINC_INTERNAL_D3D12_SWAP_CHAIN_COUNT];
// static HANDLE window->frame_fence_events[KINC_INTERNAL_D3D12_SWAP_CHAIN_COUNT];
// static ID3D12Fence *window->frame_fences[KINC_INTERNAL_D3D12_SWAP_CHAIN_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, KINC_INTERNAL_D3D12_SWAP_CHAIN_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 < KINC_INTERNAL_D3D12_SWAP_CHAIN_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 = KINC_INTERNAL_D3D12_SWAP_CHAIN_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 = &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[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 = &range;
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 < KINC_INTERNAL_D3D12_SWAP_CHAIN_COUNT; ++i) {
// waitForFence(window->frame_fences[i], window->current_fence_value[i], window->frame_fence_events[i]);
}
for (int i = 0; i < KINC_INTERNAL_D3D12_SWAP_CHAIN_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 = KINC_INTERNAL_D3D12_SWAP_CHAIN_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) % KINC_INTERNAL_D3D12_SWAP_CHAIN_COUNT;
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]);
if (window->new_width != window->width || window->new_height != window->height) {
#ifndef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
kinc_microsoft_affirm(window->swapChain->ResizeBuffers(0, 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;
}
// 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;
}

View File

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

View File

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

View File

@ -0,0 +1,620 @@
#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;
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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,58 @@
#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 KINC_INTERNAL_D3D12_SWAP_CHAIN_COUNT 2
struct dx_window {
#ifndef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
struct IDXGISwapChain *swapChain;
#endif
UINT64 current_fence_value;
UINT64 fence_values[KINC_INTERNAL_D3D12_SWAP_CHAIN_COUNT];
HANDLE frame_fence_events[KINC_INTERNAL_D3D12_SWAP_CHAIN_COUNT];
struct ID3D12Fence *frame_fences[KINC_INTERNAL_D3D12_SWAP_CHAIN_COUNT];
int width;
int height;
int new_width;
int new_height;
int current_backbuffer;
bool vsync;
int window_index;
};
struct dx_window *kinc_dx_current_window();
#ifdef __cplusplus
}
#endif

View File

@ -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};
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"

View File

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

View File

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

View File

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

View File

@ -0,0 +1,559 @@
#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, &currentProgram->vertexConstantBuffer);
}
if (currentProgram->fragmentShader->constantsSize > 0) {
context->UpdateSubresource(currentProgram->fragmentConstantBuffer, 0, nullptr, fragmentConstants, 0, 0);
context->PSSetConstantBuffers(0, 1, &currentProgram->fragmentConstantBuffer);
}
if (currentProgram->geometryShader != nullptr && currentProgram->geometryShader->constantsSize > 0) {
context->UpdateSubresource(currentProgram->geometryConstantBuffer, 0, nullptr, geometryConstants, 0, 0);
context->GSSetConstantBuffers(0, 1, &currentProgram->geometryConstantBuffer);
}
if (currentProgram->tessControlShader != nullptr && currentProgram->tessControlShader->constantsSize > 0) {
context->UpdateSubresource(currentProgram->tessControlConstantBuffer, 0, nullptr, tessControlConstants, 0, 0);
context->HSSetConstantBuffers(0, 1, &currentProgram->tessControlConstantBuffer);
}
if (currentProgram->tessEvalShader != nullptr && currentProgram->tessEvalShader->constantsSize > 0) {
context->UpdateSubresource(currentProgram->tessEvalConstantBuffer, 0, nullptr, tessEvalConstants, 0, 0);
context->DSSetConstantBuffers(0, 1, &currentProgram->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, &currentProgram->vertexConstantBuffer);
}
if (currentProgram->fragmentShader->constantsSize > 0) {
context->UpdateSubresource(currentProgram->fragmentConstantBuffer, 0, nullptr, fragmentConstants, 0, 0);
context->PSSetConstantBuffers(0, 1, &currentProgram->fragmentConstantBuffer);
}
if (currentProgram->geometryShader != nullptr && currentProgram->geometryShader->constantsSize > 0) {
context->UpdateSubresource(currentProgram->geometryConstantBuffer, 0, nullptr, geometryConstants, 0, 0);
context->GSSetConstantBuffers(0, 1, &currentProgram->geometryConstantBuffer);
}
if (currentProgram->tessControlShader != nullptr && currentProgram->tessControlShader->constantsSize > 0) {
context->UpdateSubresource(currentProgram->tessControlConstantBuffer, 0, nullptr, tessControlConstants, 0, 0);
context->HSSetConstantBuffers(0, 1, &currentProgram->tessControlConstantBuffer);
}
if (currentProgram->tessEvalShader != nullptr && currentProgram->tessEvalShader->constantsSize > 0) {
context->UpdateSubresource(currentProgram->tessEvalConstantBuffer, 0, nullptr, tessEvalConstants, 0, 0);
context->DSSetConstantBuffers(0, 1, &currentProgram->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";
vertexDesc[curAttr].SemanticIndex = findAttribute(pipe->vertexShader, pipe->inputLayout[stream]->elements[i].name).attribute;
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.");
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,287 @@
#include "rendertarget.h"
#include <kinc/backend/SystemMicrosoft.h>
#include <kinc/graphics5/rendertarget.h>
#include <kinc/graphics5/texture.h>
#ifdef KINC_WINDOWS
#include <dxgi1_4.h>
#endif
#ifdef KINC_DIRECT3D_HAS_NO_SWAPCHAIN
extern ID3D12Resource *swapChainRenderTargets[KINC_INTERNAL_D3D12_SWAP_CHAIN_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;
}

View File

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

View File

@ -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) {}

View File

@ -0,0 +1,7 @@
#pragma once
struct ID3D12DescriptorHeap;
typedef struct kinc_g5_sampler_impl {
struct ID3D12DescriptorHeap *sampler_heap;
} kinc_g5_sampler_impl_t;

View File

@ -0,0 +1,87 @@
#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;
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;
}
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);
}

View File

@ -0,0 +1,37 @@
#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

View File

@ -0,0 +1,455 @@
#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);
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) {
int texture_count = 0;
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) {
texture_count += 1;
}
}
if (texture_count > 0) {
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) {
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 || list->impl.currentTextures[i] != NULL) && list->impl.current_samplers[i] != NULL) {
ID3D12DescriptorHeap *samplerDescriptorHeap = list->impl.current_samplers[i]->impl.sampler_heap;
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);
}
}
else {
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 = DXGI_FORMAT_R8G8B8A8_UNORM;
shaderResourceViewDesc.Texture2D.MipLevels = 1;
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
shaderResourceViewDesc.Texture2D.ResourceMinLODClamp = 0.0f;
device->CreateShaderResourceView(NULL, &shaderResourceViewDesc, srvCpu);
D3D12_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(D3D12_SAMPLER_DESC));
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
samplerDesc.MinLOD = 0.0f;
samplerDesc.MaxLOD = 1.0f;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
device->CreateSampler(&samplerDesc, samplerCpu);
}
}
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) {}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,610 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// Don't include this file directly - use pix3.h
#pragma once
#ifndef _PIXEventsCommon_H_
#define _PIXEventsCommon_H_
//
// The PIXBeginEvent and PIXSetMarker functions have an optimized path for
// copying strings that work by copying 128-bit or 64-bits at a time. In some
// circumstances this may result in PIX logging the remaining memory after the
// null terminator.
//
// By default this optimization is enabled unless Address Sanitizer is enabled,
// since this optimization can trigger a global-buffer-overflow when copying
// string literals.
//
// The PIX_ENABLE_BLOCK_ARGUMENT_COPY controls whether or not this optimization
// is enabled. Applications may also explicitly set this macro to 0 to disable
// the optimization if necessary.
//
// Check for Address Sanitizer on either Clang or MSVC
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define PIX_ASAN_ENABLED
#endif
#elif defined(__SANITIZE_ADDRESS__)
#define PIX_ASAN_ENABLED
#endif
#if defined(PIX_ENABLE_BLOCK_ARGUMENT_COPY)
// Previously set values override everything
# define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 0
#elif defined(PIX_ASAN_ENABLED)
// Disable block argument copy when address sanitizer is enabled
#define PIX_ENABLE_BLOCK_ARGUMENT_COPY 0
#define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 1
#endif
#if !defined(PIX_ENABLE_BLOCK_ARGUMENT_COPY)
// Default to enabled.
#define PIX_ENABLE_BLOCK_ARGUMENT_COPY 1
#define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 1
#endif
struct PIXEventsBlockInfo;
struct PIXEventsThreadInfo
{
PIXEventsBlockInfo* block;
UINT64* biasedLimit;
UINT64* destination;
};
extern "C" UINT64 WINAPI PIXEventsReplaceBlock(PIXEventsThreadInfo * threadInfo, bool getEarliestTime) noexcept;
#define PIX_EVENT_METADATA_NONE 0x0
#define PIX_EVENT_METADATA_ON_CONTEXT 0x1
#define PIX_EVENT_METADATA_STRING_IS_ANSI 0x2
#define PIX_EVENT_METADATA_HAS_COLOR 0xF0
#ifndef PIX_GAMING_XBOX
#include "PIXEventsLegacy.h"
#endif
enum PIXEventType : UINT8
{
PIXEvent_EndEvent = 0x00,
PIXEvent_BeginEvent = 0x01,
PIXEvent_SetMarker = 0x02,
};
static const UINT64 PIXEventsReservedRecordSpaceQwords = 64;
//this is used to make sure SSE string copy always will end 16-byte write in the current block
//this way only a check if destination < limit can be performed, instead of destination < limit - 1
//since both these are UINT64* and SSE writes in 16 byte chunks, 8 bytes are kept in reserve
//so even if SSE overwrites 8-15 extra bytes, those will still belong to the correct block
//on next iteration check destination will be greater than limit
//this is used as well for fixed size UMD events and PIXEndEvent since these require less space
//than other variable length user events and do not need big reserved space
static const UINT64 PIXEventsReservedTailSpaceQwords = 2;
static const UINT64 PIXEventsSafeFastCopySpaceQwords = PIXEventsReservedRecordSpaceQwords - PIXEventsReservedTailSpaceQwords;
static const UINT64 PIXEventsGraphicsRecordSpaceQwords = 64;
//Bits 7-19 (13 bits)
static const UINT64 PIXEventsBlockEndMarker = 0x00000000000FFF80;
// V2 events
// Bits 00..06 (7 bits) - Size in QWORDS
static const UINT64 PIXEventsSizeWriteMask = 0x000000000000007F;
static const UINT64 PIXEventsSizeBitShift = 0;
static const UINT64 PIXEventsSizeReadMask = PIXEventsSizeWriteMask << PIXEventsSizeBitShift;
static const UINT64 PIXEventsSizeMax = (1ull << 7) - 1ull;
// Bits 07..11 (5 bits) - Event Type
static const UINT64 PIXEventsTypeWriteMask = 0x000000000000001F;
static const UINT64 PIXEventsTypeBitShift = 7;
static const UINT64 PIXEventsTypeReadMask = PIXEventsTypeWriteMask << PIXEventsTypeBitShift;
// Bits 12..19 (8 bits) - Event Specific Metadata
static const UINT64 PIXEventsMetadataWriteMask = 0x00000000000000FF;
static const UINT64 PIXEventsMetadataBitShift = 12;
static const UINT64 PIXEventsMetadataReadMask = PIXEventsMetadataWriteMask << PIXEventsMetadataBitShift;
// Buts 20..63 (44 bits) - Timestamp
static const UINT64 PIXEventsTimestampWriteMask = 0x00000FFFFFFFFFFF;
static const UINT64 PIXEventsTimestampBitShift = 20;
static const UINT64 PIXEventsTimestampReadMask = PIXEventsTimestampWriteMask << PIXEventsTimestampBitShift;
inline UINT64 PIXEncodeEventInfo(UINT64 timestamp, PIXEventType eventType, UINT8 eventSize, UINT8 eventMetadata)
{
return
((timestamp & PIXEventsTimestampWriteMask) << PIXEventsTimestampBitShift) |
(((UINT64)eventType & PIXEventsTypeWriteMask) << PIXEventsTypeBitShift) |
(((UINT64)eventMetadata & PIXEventsMetadataWriteMask) << PIXEventsMetadataBitShift) |
(((UINT64)eventSize & PIXEventsSizeWriteMask) << PIXEventsSizeBitShift);
}
inline UINT8 PIXEncodeIndexColor(UINT8 color)
{
// There are 8 index colors, indexed 0 (default) to 7
return (color & 0x7) << 4;
}
//Bits 60-63 (4)
static const UINT64 PIXEventsStringAlignmentWriteMask = 0x000000000000000F;
static const UINT64 PIXEventsStringAlignmentReadMask = 0xF000000000000000;
static const UINT64 PIXEventsStringAlignmentBitShift = 60;
//Bits 55-59 (5)
static const UINT64 PIXEventsStringCopyChunkSizeWriteMask = 0x000000000000001F;
static const UINT64 PIXEventsStringCopyChunkSizeReadMask = 0x0F80000000000000;
static const UINT64 PIXEventsStringCopyChunkSizeBitShift = 55;
//Bit 54
static const UINT64 PIXEventsStringIsANSIWriteMask = 0x0000000000000001;
static const UINT64 PIXEventsStringIsANSIReadMask = 0x0040000000000000;
static const UINT64 PIXEventsStringIsANSIBitShift = 54;
//Bit 53
static const UINT64 PIXEventsStringIsShortcutWriteMask = 0x0000000000000001;
static const UINT64 PIXEventsStringIsShortcutReadMask = 0x0020000000000000;
static const UINT64 PIXEventsStringIsShortcutBitShift = 53;
inline void PIXEncodeStringInfo(UINT64*& destination, BOOL isANSI)
{
const UINT64 encodedStringInfo =
((sizeof(UINT64) & PIXEventsStringCopyChunkSizeWriteMask) << PIXEventsStringCopyChunkSizeBitShift) |
(((UINT64)isANSI & PIXEventsStringIsANSIWriteMask) << PIXEventsStringIsANSIBitShift);
*destination++ = encodedStringInfo;
}
template<UINT alignment, class T>
inline bool PIXIsPointerAligned(T* pointer)
{
return !(((UINT64)pointer) & (alignment - 1));
}
// Generic template version slower because of the additional clear write
template<class T>
inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, T argument)
{
if (destination < limit)
{
*destination = 0ull;
*((T*)destination) = argument;
++destination;
}
}
// int32 specialization to avoid slower double memory writes
template<>
inline void PIXCopyEventArgument<INT32>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT32 argument)
{
if (destination < limit)
{
*reinterpret_cast<INT64*>(destination) = static_cast<INT64>(argument);
++destination;
}
}
// unsigned int32 specialization to avoid slower double memory writes
template<>
inline void PIXCopyEventArgument<UINT32>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT32 argument)
{
if (destination < limit)
{
*destination = static_cast<UINT64>(argument);
++destination;
}
}
// int64 specialization to avoid slower double memory writes
template<>
inline void PIXCopyEventArgument<INT64>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT64 argument)
{
if (destination < limit)
{
*reinterpret_cast<INT64*>(destination) = argument;
++destination;
}
}
// unsigned int64 specialization to avoid slower double memory writes
template<>
inline void PIXCopyEventArgument<UINT64>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT64 argument)
{
if (destination < limit)
{
*destination = argument;
++destination;
}
}
//floats must be cast to double during writing the data to be properly printed later when reading the data
//this is needed because when float is passed to varargs function it's cast to double
template<>
inline void PIXCopyEventArgument<float>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, float argument)
{
if (destination < limit)
{
*reinterpret_cast<double*>(destination) = static_cast<double>(argument);
++destination;
}
}
//char has to be cast to a longer signed integer type
//this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier
template<>
inline void PIXCopyEventArgument<char>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, char argument)
{
if (destination < limit)
{
*reinterpret_cast<INT64*>(destination) = static_cast<INT64>(argument);
++destination;
}
}
//UINT8 has to be cast to a longer unsigned integer type
//this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier
template<>
inline void PIXCopyEventArgument<UINT8>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT8 argument)
{
if (destination < limit)
{
*destination = static_cast<UINT64>(argument);
++destination;
}
}
//bool has to be cast to an integer since it's not explicitly supported by string format routines
//there's no format specifier for bool type, but it should work with integer format specifiers
template<>
inline void PIXCopyEventArgument<bool>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, bool argument)
{
if (destination < limit)
{
*destination = static_cast<UINT64>(argument);
++destination;
}
}
inline void PIXCopyEventStringArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
while (destination < limit)
{
UINT64 c = static_cast<UINT8>(argument[0]);
if (!c)
{
*destination++ = 0;
return;
}
UINT64 x = c;
c = static_cast<UINT8>(argument[1]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 8;
c = static_cast<UINT8>(argument[2]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 16;
c = static_cast<UINT8>(argument[3]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 24;
c = static_cast<UINT8>(argument[4]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 32;
c = static_cast<UINT8>(argument[5]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 40;
c = static_cast<UINT8>(argument[6]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 48;
c = static_cast<UINT8>(argument[7]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 56;
*destination++ = x;
argument += 8;
}
}
template<bool>
inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
PIXEncodeStringInfo(destination, TRUE);
PIXCopyEventStringArgumentSlow(destination, limit, argument);
}
template<>
inline void PIXCopyEventArgumentSlow<false>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
PIXCopyEventStringArgumentSlow(destination, limit, argument);
}
#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
inline void PIXCopyEventStringArgumentFast(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
constexpr UINT64 mask1 = 0x0101010101010101ULL;
constexpr UINT64 mask2 = 0x8080808080808080ULL;
UINT64* source = (UINT64*)argument;
while (destination < limit)
{
UINT64 qword = *source++;
*destination++ = qword;
//check if any of the characters is a terminating zero
UINT64 isTerminated = (qword - mask1) & (~qword & mask2);
if (isTerminated)
{
break;
}
}
}
#endif
template<>
inline void PIXCopyEventArgument<PCSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
if (destination < limit)
{
if (argument != nullptr)
{
#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
if (PIXIsPointerAligned<8>(argument))
{
PIXEncodeStringInfo(destination, TRUE);
PIXCopyEventStringArgumentFast(destination, limit, argument);
}
else
#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
{
PIXCopyEventArgumentSlow<true>(destination, limit, argument);
}
}
else
{
*destination++ = 0ull;
}
}
}
inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
if (argument != nullptr)
{
#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
if (PIXIsPointerAligned<8>(argument))
{
PIXCopyEventStringArgumentFast(destination, limit, argument);
}
else
#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
{
PIXCopyEventArgumentSlow<false>(destination, limit, argument);
}
}
else
{
*destination++ = 0ull;
}
}
template<>
inline void PIXCopyEventArgument<PSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument)
{
PIXCopyEventArgument(destination, limit, (PCSTR)argument);
}
inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument)
{
PIXCopyStringArgument(destination, limit, (PCSTR)argument);
}
inline void PIXCopyEventStringArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
while (destination < limit)
{
UINT64 c = static_cast<UINT16>(argument[0]);
if (!c)
{
*destination++ = 0;
return;
}
UINT64 x = c;
c = static_cast<UINT16>(argument[1]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 16;
c = static_cast<UINT16>(argument[2]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 32;
c = static_cast<UINT16>(argument[3]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 48;
*destination++ = x;
argument += 4;
}
}
template<bool>
inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
PIXEncodeStringInfo(destination, FALSE);
PIXCopyEventStringArgumentSlow(destination, limit, argument);
}
template<>
inline void PIXCopyEventArgumentSlow<false>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
PIXCopyEventStringArgumentSlow(destination, limit, argument);
}
#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
inline void PIXCopyEventStringArgumentFast(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
UINT64* source = (UINT64*)argument;
while (destination < limit)
{
UINT64 qword = *source++;
*destination++ = qword;
//check if any of the characters is a terminating zero
//TODO: check if reversed condition is faster
if (!((qword & 0xFFFF000000000000) &&
(qword & 0xFFFF00000000) &&
(qword & 0xFFFF0000) &&
(qword & 0xFFFF)))
{
break;
}
}
}
#endif
template<>
inline void PIXCopyEventArgument<PCWSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
if (destination < limit)
{
if (argument != nullptr)
{
#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
if (PIXIsPointerAligned<8>(argument))
{
PIXEncodeStringInfo(destination, FALSE);
PIXCopyEventStringArgumentFast(destination, limit, argument);
}
else
#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
{
PIXCopyEventArgumentSlow<true>(destination, limit, argument);
}
}
else
{
*destination++ = 0ull;
}
}
}
inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
if (argument != nullptr)
{
#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
if (PIXIsPointerAligned<8>(argument))
{
PIXCopyEventStringArgumentFast(destination, limit, argument);
}
else
#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
{
PIXCopyEventArgumentSlow<false>(destination, limit, argument);
}
}
else
{
*destination++ = 0ull;
}
}
template<>
inline void PIXCopyEventArgument<PWSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PWSTR argument)
{
PIXCopyEventArgument(destination, limit, (PCWSTR)argument);
};
inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PWSTR argument)
{
PIXCopyStringArgument(destination, limit, (PCWSTR)argument);
};
#if defined(__d3d12_x_h__) || defined(__d3d12_xs_h__) || defined(__d3d12_h__)
inline void PIXSetGPUMarkerOnContext(_In_ ID3D12GraphicsCommandList* commandList, _In_reads_bytes_(size) void* data, UINT size)
{
commandList->SetMarker(D3D12_EVENT_METADATA, data, size);
}
inline void PIXSetGPUMarkerOnContext(_In_ ID3D12CommandQueue* commandQueue, _In_reads_bytes_(size) void* data, UINT size)
{
commandQueue->SetMarker(D3D12_EVENT_METADATA, data, size);
}
inline void PIXBeginGPUEventOnContext(_In_ ID3D12GraphicsCommandList* commandList, _In_reads_bytes_(size) void* data, UINT size)
{
commandList->BeginEvent(D3D12_EVENT_METADATA, data, size);
}
inline void PIXBeginGPUEventOnContext(_In_ ID3D12CommandQueue* commandQueue, _In_reads_bytes_(size) void* data, UINT size)
{
commandQueue->BeginEvent(D3D12_EVENT_METADATA, data, size);
}
inline void PIXEndGPUEventOnContext(_In_ ID3D12GraphicsCommandList* commandList)
{
commandList->EndEvent();
}
inline void PIXEndGPUEventOnContext(_In_ ID3D12CommandQueue* commandQueue)
{
commandQueue->EndEvent();
}
#endif //__d3d12_h__
template<class T> struct PIXInferScopedEventType { typedef T Type; };
template<class T> struct PIXInferScopedEventType<const T> { typedef T Type; };
template<class T> struct PIXInferScopedEventType<T*> { typedef T Type; };
template<class T> struct PIXInferScopedEventType<T* const> { typedef T Type; };
template<> struct PIXInferScopedEventType<UINT64> { typedef void Type; };
template<> struct PIXInferScopedEventType<const UINT64> { typedef void Type; };
template<> struct PIXInferScopedEventType<INT64> { typedef void Type; };
template<> struct PIXInferScopedEventType<const INT64> { typedef void Type; };
template<> struct PIXInferScopedEventType<UINT> { typedef void Type; };
template<> struct PIXInferScopedEventType<const UINT> { typedef void Type; };
template<> struct PIXInferScopedEventType<INT> { typedef void Type; };
template<> struct PIXInferScopedEventType<const INT> { typedef void Type; };
template<> struct PIXInferScopedEventType<UINT8> { typedef void Type; };
template<> struct PIXInferScopedEventType<const UINT8> { typedef void Type; };
template<> struct PIXInferScopedEventType<INT8> { typedef void Type; };
template<> struct PIXInferScopedEventType<const INT8> { typedef void Type; };
#endif //_PIXEventsCommon_H_

View File

@ -0,0 +1,565 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// Don't include this file directly - use pix3.h
// This file encodes PIX events in the legacy PIX event format.
#ifndef _PIXEventsLegacy_H_
#define _PIXEventsLegacy_H_
#include <cstdint>
#if defined(_M_X64) || defined(_M_IX86)
#include <emmintrin.h>
#endif
namespace PixEventsLegacy
{
enum PIXEventType
{
PIXEvent_EndEvent = 0x000,
PIXEvent_BeginEvent_VarArgs = 0x001,
PIXEvent_BeginEvent_NoArgs = 0x002,
PIXEvent_SetMarker_VarArgs = 0x007,
PIXEvent_SetMarker_NoArgs = 0x008,
PIXEvent_EndEvent_OnContext = 0x010,
PIXEvent_BeginEvent_OnContext_VarArgs = 0x011,
PIXEvent_BeginEvent_OnContext_NoArgs = 0x012,
PIXEvent_SetMarker_OnContext_VarArgs = 0x017,
PIXEvent_SetMarker_OnContext_NoArgs = 0x018,
};
static const UINT64 PIXEventsReservedRecordSpaceQwords = 64;
static const UINT64 PIXEventsReservedTailSpaceQwords = 2;
static const UINT64 PIXEventsSafeFastCopySpaceQwords = PIXEventsReservedRecordSpaceQwords - PIXEventsReservedTailSpaceQwords;
static const UINT64 PIXEventsGraphicsRecordSpaceQwords = 64;
//Bits 7-19 (13 bits)
static const UINT64 PIXEventsBlockEndMarker = 0x00000000000FFF80;
//Bits 10-19 (10 bits)
static const UINT64 PIXEventsTypeReadMask = 0x00000000000FFC00;
static const UINT64 PIXEventsTypeWriteMask = 0x00000000000003FF;
static const UINT64 PIXEventsTypeBitShift = 10;
//Bits 20-63 (44 bits)
static const UINT64 PIXEventsTimestampReadMask = 0xFFFFFFFFFFF00000;
static const UINT64 PIXEventsTimestampWriteMask = 0x00000FFFFFFFFFFF;
static const UINT64 PIXEventsTimestampBitShift = 20;
inline UINT64 PIXEncodeEventInfo(UINT64 timestamp, PIXEventType eventType)
{
return ((timestamp & PIXEventsTimestampWriteMask) << PIXEventsTimestampBitShift) |
(((UINT64)eventType & PIXEventsTypeWriteMask) << PIXEventsTypeBitShift);
}
//Bits 60-63 (4)
static const UINT64 PIXEventsStringAlignmentWriteMask = 0x000000000000000F;
static const UINT64 PIXEventsStringAlignmentReadMask = 0xF000000000000000;
static const UINT64 PIXEventsStringAlignmentBitShift = 60;
//Bits 55-59 (5)
static const UINT64 PIXEventsStringCopyChunkSizeWriteMask = 0x000000000000001F;
static const UINT64 PIXEventsStringCopyChunkSizeReadMask = 0x0F80000000000000;
static const UINT64 PIXEventsStringCopyChunkSizeBitShift = 55;
//Bit 54
static const UINT64 PIXEventsStringIsANSIWriteMask = 0x0000000000000001;
static const UINT64 PIXEventsStringIsANSIReadMask = 0x0040000000000000;
static const UINT64 PIXEventsStringIsANSIBitShift = 54;
//Bit 53
static const UINT64 PIXEventsStringIsShortcutWriteMask = 0x0000000000000001;
static const UINT64 PIXEventsStringIsShortcutReadMask = 0x0020000000000000;
static const UINT64 PIXEventsStringIsShortcutBitShift = 53;
inline UINT64 PIXEncodeStringInfo(UINT64 alignment, UINT64 copyChunkSize, BOOL isANSI, BOOL isShortcut)
{
return ((alignment & PIXEventsStringAlignmentWriteMask) << PIXEventsStringAlignmentBitShift) |
((copyChunkSize & PIXEventsStringCopyChunkSizeWriteMask) << PIXEventsStringCopyChunkSizeBitShift) |
(((UINT64)isANSI & PIXEventsStringIsANSIWriteMask) << PIXEventsStringIsANSIBitShift) |
(((UINT64)isShortcut & PIXEventsStringIsShortcutWriteMask) << PIXEventsStringIsShortcutBitShift);
}
template<UINT alignment, class T>
inline bool PIXIsPointerAligned(T* pointer)
{
return !(((UINT64)pointer) & (alignment - 1));
}
// Generic template version slower because of the additional clear write
template<class T>
inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, T argument)
{
if (destination < limit)
{
*destination = 0ull;
*((T*)destination) = argument;
++destination;
}
}
// int32 specialization to avoid slower double memory writes
template<>
inline void PIXCopyEventArgument<INT32>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT32 argument)
{
if (destination < limit)
{
*reinterpret_cast<INT64*>(destination) = static_cast<INT64>(argument);
++destination;
}
}
// unsigned int32 specialization to avoid slower double memory writes
template<>
inline void PIXCopyEventArgument<UINT32>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT32 argument)
{
if (destination < limit)
{
*destination = static_cast<UINT64>(argument);
++destination;
}
}
// int64 specialization to avoid slower double memory writes
template<>
inline void PIXCopyEventArgument<INT64>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT64 argument)
{
if (destination < limit)
{
*reinterpret_cast<INT64*>(destination) = argument;
++destination;
}
}
// unsigned int64 specialization to avoid slower double memory writes
template<>
inline void PIXCopyEventArgument<UINT64>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT64 argument)
{
if (destination < limit)
{
*destination = argument;
++destination;
}
}
//floats must be cast to double during writing the data to be properly printed later when reading the data
//this is needed because when float is passed to varargs function it's cast to double
template<>
inline void PIXCopyEventArgument<float>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, float argument)
{
if (destination < limit)
{
*reinterpret_cast<double*>(destination) = static_cast<double>(argument);
++destination;
}
}
//char has to be cast to a longer signed integer type
//this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier
template<>
inline void PIXCopyEventArgument<char>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, char argument)
{
if (destination < limit)
{
*reinterpret_cast<INT64*>(destination) = static_cast<INT64>(argument);
++destination;
}
}
//unsigned char has to be cast to a longer unsigned integer type
//this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier
template<>
inline void PIXCopyEventArgument<unsigned char>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, unsigned char argument)
{
if (destination < limit)
{
*destination = static_cast<UINT64>(argument);
++destination;
}
}
//bool has to be cast to an integer since it's not explicitly supported by string format routines
//there's no format specifier for bool type, but it should work with integer format specifiers
template<>
inline void PIXCopyEventArgument<bool>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, bool argument)
{
if (destination < limit)
{
*destination = static_cast<UINT64>(argument);
++destination;
}
}
inline void PIXCopyEventArgumentSlowest(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
*destination++ = PIXEncodeStringInfo(0, 8, TRUE, FALSE);
while (destination < limit)
{
UINT64 c = static_cast<uint8_t>(argument[0]);
if (!c)
{
*destination++ = 0;
return;
}
UINT64 x = c;
c = static_cast<uint8_t>(argument[1]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 8;
c = static_cast<uint8_t>(argument[2]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 16;
c = static_cast<uint8_t>(argument[3]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 24;
c = static_cast<uint8_t>(argument[4]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 32;
c = static_cast<uint8_t>(argument[5]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 40;
c = static_cast<uint8_t>(argument[6]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 48;
c = static_cast<uint8_t>(argument[7]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 56;
*destination++ = x;
argument += 8;
}
}
inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
#if PIX_ENABLE_BLOCK_ARGUMENT_COPY
if (PIXIsPointerAligned<8>(argument))
{
*destination++ = PIXEncodeStringInfo(0, 8, TRUE, FALSE);
UINT64* source = (UINT64*)argument;
while (destination < limit)
{
UINT64 qword = *source++;
*destination++ = qword;
//check if any of the characters is a terminating zero
if (!((qword & 0xFF00000000000000) &&
(qword & 0xFF000000000000) &&
(qword & 0xFF0000000000) &&
(qword & 0xFF00000000) &&
(qword & 0xFF000000) &&
(qword & 0xFF0000) &&
(qword & 0xFF00) &&
(qword & 0xFF)))
{
break;
}
}
}
else
#endif // PIX_ENABLE_BLOCK_ARGUMENT_COPY
{
PIXCopyEventArgumentSlowest(destination, limit, argument);
}
}
template<>
inline void PIXCopyEventArgument<PCSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument)
{
if (destination < limit)
{
if (argument != nullptr)
{
#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
if (PIXIsPointerAligned<16>(argument))
{
*destination++ = PIXEncodeStringInfo(0, 16, TRUE, FALSE);
__m128i zero = _mm_setzero_si128();
if (PIXIsPointerAligned<16>(destination))
{
while (destination < limit)
{
__m128i mem = _mm_load_si128((__m128i*)argument);
_mm_store_si128((__m128i*)destination, mem);
//check if any of the characters is a terminating zero
__m128i res = _mm_cmpeq_epi8(mem, zero);
destination += 2;
if (_mm_movemask_epi8(res))
break;
argument += 16;
}
}
else
{
while (destination < limit)
{
__m128i mem = _mm_load_si128((__m128i*)argument);
_mm_storeu_si128((__m128i*)destination, mem);
//check if any of the characters is a terminating zero
__m128i res = _mm_cmpeq_epi8(mem, zero);
destination += 2;
if (_mm_movemask_epi8(res))
break;
argument += 16;
}
}
}
else
#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
{
PIXCopyEventArgumentSlow(destination, limit, argument);
}
}
else
{
*destination++ = 0ull;
}
}
}
template<>
inline void PIXCopyEventArgument<PSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument)
{
PIXCopyEventArgument(destination, limit, (PCSTR)argument);
}
inline void PIXCopyEventArgumentSlowest(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
*destination++ = PIXEncodeStringInfo(0, 8, FALSE, FALSE);
while (destination < limit)
{
UINT64 c = static_cast<uint16_t>(argument[0]);
if (!c)
{
*destination++ = 0;
return;
}
UINT64 x = c;
c = static_cast<uint16_t>(argument[1]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 16;
c = static_cast<uint16_t>(argument[2]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 32;
c = static_cast<uint16_t>(argument[3]);
if (!c)
{
*destination++ = x;
return;
}
x |= c << 48;
*destination++ = x;
argument += 4;
}
}
inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
#if PIX_ENABLE_BLOCK_ARGUMENT_COPY
if (PIXIsPointerAligned<8>(argument))
{
*destination++ = PIXEncodeStringInfo(0, 8, FALSE, FALSE);
UINT64* source = (UINT64*)argument;
while (destination < limit)
{
UINT64 qword = *source++;
*destination++ = qword;
//check if any of the characters is a terminating zero
//TODO: check if reversed condition is faster
if (!((qword & 0xFFFF000000000000) &&
(qword & 0xFFFF00000000) &&
(qword & 0xFFFF0000) &&
(qword & 0xFFFF)))
{
break;
}
}
}
else
#endif // PIX_ENABLE_BLOCK_ARGUMENT_COPY
{
PIXCopyEventArgumentSlowest(destination, limit, argument);
}
}
template<>
inline void PIXCopyEventArgument<PCWSTR>(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument)
{
if (destination < limit)
{
if (argument != nullptr)
{
#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
if (PIXIsPointerAligned<16>(argument))
{
*destination++ = PIXEncodeStringInfo(0, 16, FALSE, FALSE);
__m128i zero = _mm_setzero_si128();
if (PIXIsPointerAligned<16>(destination))
{
while (destination < limit)
{
__m128i mem = _mm_load_si128((__m128i*)argument);
_mm_store_si128((__m128i*)destination, mem);
//check if any of the characters is a terminating zero
__m128i res = _mm_cmpeq_epi16(mem, zero);
destination += 2;
if (_mm_movemask_epi8(res))
break;
argument += 8;
}
}
else
{
while (destination < limit)
{
__m128i mem = _mm_load_si128((__m128i*)argument);
_mm_storeu_si128((__m128i*)destination, mem);
//check if any of the characters is a terminating zero
__m128i res = _mm_cmpeq_epi16(mem, zero);
destination += 2;
if (_mm_movemask_epi8(res))
break;
argument += 8;
}
}
}
else
#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY
{
PIXCopyEventArgumentSlow(destination, limit, argument);
}
}
else
{
*destination++ = 0ull;
}
}
}
inline void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit)
{
// nothing
UNREFERENCED_PARAMETER(destination);
UNREFERENCED_PARAMETER(limit);
}
template<typename ARG, typename... ARGS>
void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, ARG const& arg, ARGS const&... args)
{
PIXCopyEventArgument(destination, limit, arg);
PIXCopyEventArguments(destination, limit, args...);
}
template<typename... ARGS>
struct PIXEventTypeInferer
{
static constexpr PIXEventType Begin() { return PIXEvent_BeginEvent_VarArgs; }
static constexpr PIXEventType SetMarker() { return PIXEvent_SetMarker_VarArgs; }
static constexpr PIXEventType BeginOnContext() { return PIXEvent_BeginEvent_OnContext_VarArgs; }
static constexpr PIXEventType SetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_VarArgs; }
static constexpr PIXEventType End() { return PIXEvent_EndEvent; }
// Xbox and Windows store different types of events for context events.
// On Xbox these include a context argument, while on Windows they do
// not. It is important not to change the event types used on the
// Windows version as there are OS components (eg debug layer & DRED)
// that decode event structs.
#ifdef PIX_XBOX
static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_VarArgs; }
static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_VarArgs; }
static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent_OnContext; }
#else
static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_VarArgs; }
static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_VarArgs; }
static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent; }
#endif
};
template<>
struct PIXEventTypeInferer<>
{
static constexpr PIXEventType Begin() { return PIXEvent_BeginEvent_NoArgs; }
static constexpr PIXEventType SetMarker() { return PIXEvent_SetMarker_NoArgs; }
static constexpr PIXEventType BeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; }
static constexpr PIXEventType SetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; }
static constexpr PIXEventType End() { return PIXEvent_EndEvent; }
#ifdef PIX_XBOX
static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; }
static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; }
static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent_OnContext; }
#else
static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_NoArgs; }
static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_NoArgs; }
static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent; }
#endif
};
template<size_t size, typename STR, typename... ARGS>
UINT64* EncodeBeginEventForContext(UINT64 (&buffer)[size], UINT64 color, STR formatString, ARGS... args)
{
UINT64* destination = buffer;
UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords;
*destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer<ARGS...>::GpuBeginOnContext());
*destination++ = color;
PIXCopyEventArguments(destination, limit, formatString, args...);
*destination = 0ull;
return destination;
}
template<size_t size, typename STR, typename... ARGS>
UINT64* EncodeSetMarkerForContext(UINT64 (&buffer)[size], UINT64 color, STR formatString, ARGS... args)
{
UINT64* destination = buffer;
UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords;
*destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer<ARGS...>::GpuSetMarkerOnContext());
*destination++ = color;
PIXCopyEventArguments(destination, limit, formatString, args...);
*destination = 0ull;
return destination;
}
}
#endif //_PIXEventsLegacy_H_

View File

@ -0,0 +1,195 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#ifndef _PIX3_H_
#define _PIX3_H_
#include <sal.h>
#ifndef __cplusplus
#error "Only C++ files can include pix3.h. C is not supported."
#endif
#if !defined(USE_PIX_SUPPORTED_ARCHITECTURE)
#if defined(_M_X64) || defined(USE_PIX_ON_ALL_ARCHITECTURES) || defined(_M_ARM64)
#define USE_PIX_SUPPORTED_ARCHITECTURE
#endif
#endif
#if !defined(USE_PIX)
#if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && (defined(_DEBUG) || DBG || defined(PROFILE) || defined(PROFILE_BUILD)) && !defined(_PREFAST_)
#define USE_PIX
#endif
#endif
#if defined(USE_PIX) && !defined(USE_PIX_SUPPORTED_ARCHITECTURE)
#pragma message("Warning: Pix markers are only supported on AMD64 and ARM64")
#endif
// These flags are used by both PIXBeginCapture and PIXGetCaptureState
#define PIX_CAPTURE_TIMING (1 << 0)
#define PIX_CAPTURE_GPU (1 << 1)
#define PIX_CAPTURE_FUNCTION_SUMMARY (1 << 2)
#define PIX_CAPTURE_FUNCTION_DETAILS (1 << 3)
#define PIX_CAPTURE_CALLGRAPH (1 << 4)
#define PIX_CAPTURE_INSTRUCTION_TRACE (1 << 5)
#define PIX_CAPTURE_SYSTEM_MONITOR_COUNTERS (1 << 6)
#define PIX_CAPTURE_VIDEO (1 << 7)
#define PIX_CAPTURE_AUDIO (1 << 8)
#define PIX_CAPTURE_GPU_TRACE (1 << 9)
#define PIX_CAPTURE_RESERVED (1 << 15)
union PIXCaptureParameters
{
enum PIXCaptureStorage
{
Memory = 0,
MemoryCircular = 1, // Xbox only
FileCircular = 2, // PC only
};
struct GpuCaptureParameters
{
PCWSTR FileName;
} GpuCaptureParameters;
struct TimingCaptureParameters
{
PCWSTR FileName;
UINT32 MaximumToolingMemorySizeMb;
PIXCaptureStorage CaptureStorage;
BOOL CaptureGpuTiming;
BOOL CaptureCallstacks;
BOOL CaptureCpuSamples;
UINT32 CpuSamplesPerSecond;
BOOL CaptureFileIO;
BOOL CaptureVirtualAllocEvents;
BOOL CaptureHeapAllocEvents;
BOOL CaptureXMemEvents; // Xbox only
BOOL CapturePixMemEvents;
BOOL CapturePageFaultEvents;
BOOL CaptureVideoFrames; // Xbox only
} TimingCaptureParameters;
struct GpuTraceParameters // Xbox Series and newer only
{
PWSTR FileName;
UINT32 MaximumToolingMemorySizeMb;
BOOL CaptureGpuOccupancy;
} GpuTraceParameters;
};
typedef PIXCaptureParameters* PPIXCaptureParameters;
#if defined(XBOX) || defined(_XBOX_ONE) || defined(_DURANGO) || defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT)
#include "pix3_xbox.h"
#else
#include "pix3_win.h"
#endif
#if defined(XBOX) || defined(_XBOX_ONE) || defined(_DURANGO) || defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT)
#define PIX_XBOX
#if defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT)
#define PIX_GAMING_XBOX
#endif
#endif
#if !defined(PIX_USE_GPU_MARKERS_V2)
#ifdef PIX_GAMING_XBOX
#define PIX_USE_GPU_MARKERS_V2
#endif
#endif
#if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && (defined(USE_PIX) || defined(USE_PIX_RETAIL))
#define PIX_EVENTS_ARE_TURNED_ON
#include "PIXEventsCommon.h"
#include "PIXEvents.h"
#ifdef USE_PIX
// Starts a programmatically controlled capture.
// captureFlags uses the PIX_CAPTURE_* family of flags to specify the type of capture to take
extern "C" HRESULT WINAPI PIXBeginCapture2(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters);
inline HRESULT PIXBeginCapture(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters) { return PIXBeginCapture2(captureFlags, captureParameters); }
// Stops a programmatically controlled capture
// If discard == TRUE, the captured data is discarded
// If discard == FALSE, the captured data is saved
// discard parameter is not supported on Windows
extern "C" HRESULT WINAPI PIXEndCapture(BOOL discard);
extern "C" DWORD WINAPI PIXGetCaptureState();
extern "C" void WINAPI PIXReportCounter(_In_ PCWSTR name, float value);
#endif // USE_PIX
#endif // (USE_PIX_SUPPORTED_ARCHITECTURE) && (USE_PIX || USE_PIX_RETAIL)
#if !defined(USE_PIX_SUPPORTED_ARCHITECTURE) || !defined(USE_PIX)
// Eliminate these APIs when not using PIX
inline HRESULT PIXBeginCapture2(DWORD, _In_opt_ const PIXCaptureParameters*) { return S_OK; }
inline HRESULT PIXBeginCapture(DWORD, _In_opt_ const PIXCaptureParameters*) { return S_OK; }
inline HRESULT PIXEndCapture(BOOL) { return S_OK; }
inline HRESULT PIXGpuCaptureNextFrames(PCWSTR, UINT32) { return S_OK; }
inline HRESULT PIXSetTargetWindow(HWND) { return S_OK; }
inline HRESULT PIXForceD3D11On12() { return S_OK; }
inline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions) { return S_OK; }
inline bool WINAPI PIXIsAttachedForGpuCapture() { return false; }
inline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR) { return 0; }
inline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary() { return nullptr; }
inline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary() { return nullptr; }
inline DWORD PIXGetCaptureState() { return 0; }
inline void PIXReportCounter(_In_ PCWSTR, float) {}
inline void PIXNotifyWakeFromFenceSignal(_In_ HANDLE) {}
#if !defined(USE_PIX_RETAIL)
inline void PIXBeginEvent(UINT64, _In_ PCSTR, ...) {}
inline void PIXBeginEvent(UINT64, _In_ PCWSTR, ...) {}
inline void PIXBeginEvent(void*, UINT64, _In_ PCSTR, ...) {}
inline void PIXBeginEvent(void*, UINT64, _In_ PCWSTR, ...) {}
inline void PIXEndEvent() {}
inline void PIXEndEvent(void*) {}
inline void PIXSetMarker(UINT64, _In_ PCSTR, ...) {}
inline void PIXSetMarker(UINT64, _In_ PCWSTR, ...) {}
inline void PIXSetMarker(void*, UINT64, _In_ PCSTR, ...) {}
inline void PIXSetMarker(void*, UINT64, _In_ PCWSTR, ...) {}
inline void PIXBeginRetailEvent(void*, UINT64, _In_ PCSTR, ...) {}
inline void PIXBeginRetailEvent(void*, UINT64, _In_ PCWSTR, ...) {}
inline void PIXEndRetailEvent(void*) {}
inline void PIXSetRetailMarker(void*, UINT64, _In_ PCSTR, ...) {}
inline void PIXSetRetailMarker(void*, UINT64, _In_ PCWSTR, ...) {}
inline void PIXScopedEvent(UINT64, _In_ PCSTR, ...) {}
inline void PIXScopedEvent(UINT64, _In_ PCWSTR, ...) {}
inline void PIXScopedEvent(void*, UINT64, _In_ PCSTR, ...) {}
inline void PIXScopedEvent(void*, UINT64, _In_ PCWSTR, ...) {}
#endif // !USE_PIX_RETAIL
// don't show warnings about expressions with no effect
#pragma warning(disable:4548)
#pragma warning(disable:4555)
#endif // !USE_PIX_SUPPORTED_ARCHITECTURE || !USE_PIX
// Use these functions to specify colors to pass as metadata to a PIX event/marker API.
// Use PIX_COLOR() to specify a particular color for an event.
// Or, use PIX_COLOR_INDEX() to specify a set of unique event categories, and let PIX choose
// the colors to represent each category.
inline UINT32 PIX_COLOR(UINT8 r, UINT8 g, UINT8 b) { return 0xff000000u | ((UINT32)r << 16) | ((UINT32)g << 8) | (UINT32)b; }
inline UINT8 PIX_COLOR_INDEX(UINT8 i) { return i; }
const UINT8 PIX_COLOR_DEFAULT = PIX_COLOR_INDEX(0);
#endif // _PIX3_H_

View File

@ -0,0 +1,509 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// Don't include this file directly - use pix3.h
#pragma once
#ifndef _PIX3_H_
#error Don't include this file directly - use pix3.h
#endif
#ifndef _PIX3_WIN_H_
#define _PIX3_WIN_H_
// PIXEventsThreadInfo is defined in PIXEventsCommon.h
struct PIXEventsThreadInfo;
extern "C" PIXEventsThreadInfo* WINAPI PIXGetThreadInfo() noexcept;
#if defined(USE_PIX) && defined(USE_PIX_SUPPORTED_ARCHITECTURE)
// Notifies PIX that an event handle was set as a result of a D3D12 fence being signaled.
// The event specified must have the same handle value as the handle
// used in ID3D12Fence::SetEventOnCompletion.
extern "C" void WINAPI PIXNotifyWakeFromFenceSignal(_In_ HANDLE event);
// Notifies PIX that a block of memory was allocated
extern "C" void WINAPI PIXRecordMemoryAllocationEvent(USHORT allocatorId, void* baseAddress, size_t size, UINT64 metadata);
// Notifies PIX that a block of memory was freed
extern "C" void WINAPI PIXRecordMemoryFreeEvent(USHORT allocatorId, void* baseAddress, size_t size, UINT64 metadata);
#else
// Eliminate these APIs when not using PIX
inline void PIXRecordMemoryAllocationEvent(USHORT, void*, size_t, UINT64) {}
inline void PIXRecordMemoryFreeEvent(USHORT, void*, size_t, UINT64) {}
#endif
// The following WINPIX_EVENT_* defines denote the different metadata values that have
// been used by tools to denote how to parse pix marker event data. The first two values
// are legacy values used by pix.h in the Windows SDK.
#define WINPIX_EVENT_UNICODE_VERSION 0
#define WINPIX_EVENT_ANSI_VERSION 1
// These values denote PIX marker event data that was created by the WinPixEventRuntime.
// In early 2023 we revised the PIX marker format and defined a new version number.
#define WINPIX_EVENT_PIX3BLOB_VERSION 2
#define WINPIX_EVENT_PIX3BLOB_V2 6345127 // A number that other applications are unlikely to have used before
// For backcompat reasons, the WinPixEventRuntime uses the older PIX3BLOB format when it passes data
// into the D3D12 runtime. It will be updated to use the V2 format in the future.
#define D3D12_EVENT_METADATA WINPIX_EVENT_PIX3BLOB_VERSION
__forceinline UINT64 PIXGetTimestampCounter()
{
LARGE_INTEGER time = {};
QueryPerformanceCounter(&time);
return static_cast<UINT64>(time.QuadPart);
}
enum PIXHUDOptions
{
PIX_HUD_SHOW_ON_ALL_WINDOWS = 0x1,
PIX_HUD_SHOW_ON_TARGET_WINDOW_ONLY = 0x2,
PIX_HUD_SHOW_ON_NO_WINDOWS = 0x4
};
DEFINE_ENUM_FLAG_OPERATORS(PIXHUDOptions);
#if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && defined(USE_PIX)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
#include <shlobj.h>
#include <strsafe.h>
#include <knownfolders.h>
#include <shellapi.h>
#define PIXERRORCHECK(value) do { \
if (FAILED(value)) \
return nullptr; \
} while(0)
namespace PixImpl
{
#ifndef PIX3_WIN_UNIT_TEST
__forceinline BOOL GetModuleHandleExW(
DWORD dwFlags,
LPCWSTR lpModuleName,
HMODULE* phModule)
{
return ::GetModuleHandleExW(dwFlags, lpModuleName, phModule);
}
__forceinline HRESULT SHGetKnownFolderPath(
REFKNOWNFOLDERID rfid,
DWORD dwFlags,
HANDLE hToken,
PWSTR* ppszPath)
{
return ::SHGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath);
}
__forceinline void CoTaskMemFree(LPVOID pv)
{
return ::CoTaskMemFree(pv);
}
__forceinline HANDLE FindFirstFileW(
LPCWSTR lpFileName,
LPWIN32_FIND_DATAW lpFindFileData)
{
return ::FindFirstFileW(lpFileName, lpFindFileData);
}
__forceinline DWORD GetFileAttributesW(LPCWSTR lpFileName)
{
return ::GetFileAttributesW(lpFileName);
}
__forceinline BOOL FindNextFileW(
HANDLE hFindFile,
LPWIN32_FIND_DATAW lpFindFileData)
{
return ::FindNextFileW(hFindFile, lpFindFileData);
}
__forceinline BOOL FindClose(HANDLE hFindFile)
{
return ::FindClose(hFindFile);
}
__forceinline HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, DWORD flags)
{
return ::LoadLibraryExW(lpLibFileName, NULL, flags);
}
#endif // !PIX3_WIN_UNIT_TESTS
__forceinline void * GetGpuCaptureFunctionPtr(LPCSTR fnName) noexcept
{
HMODULE module = GetModuleHandleW(L"WinPixGpuCapturer.dll");
if (module == NULL)
{
return nullptr;
}
auto fn = (void*)GetProcAddress(module, fnName);
if (fn == nullptr)
{
return nullptr;
}
return fn;
}
__forceinline void* GetTimingCaptureFunctionPtr(LPCSTR fnName) noexcept
{
HMODULE module = GetModuleHandleW(L"WinPixTimingCapturer.dll");
if (module == NULL)
{
return nullptr;
}
auto fn = (void*)GetProcAddress(module, fnName);
if (fn == nullptr)
{
return nullptr;
}
return fn;
}
__forceinline HMODULE PIXLoadLatestCapturerLibrary(wchar_t const* capturerDllName, DWORD flags)
{
HMODULE libHandle{};
if (PixImpl::GetModuleHandleExW(0, capturerDllName, &libHandle))
{
return libHandle;
}
LPWSTR programFilesPath = nullptr;
if (FAILED(PixImpl::SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &programFilesPath)))
{
PixImpl::CoTaskMemFree(programFilesPath);
return nullptr;
}
wchar_t pixSearchPath[MAX_PATH];
if (FAILED(StringCchCopyW(pixSearchPath, MAX_PATH, programFilesPath)))
{
PixImpl::CoTaskMemFree(programFilesPath);
return nullptr;
}
PixImpl::CoTaskMemFree(programFilesPath);
PIXERRORCHECK(StringCchCatW(pixSearchPath, MAX_PATH, L"\\Microsoft PIX\\*"));
WIN32_FIND_DATAW findData;
bool foundPixInstallation = false;
wchar_t newestVersionFound[MAX_PATH];
wchar_t output[MAX_PATH];
wchar_t possibleOutput[MAX_PATH];
HANDLE hFind = PixImpl::FindFirstFileW(pixSearchPath, &findData);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if (((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) &&
(findData.cFileName[0] != '.'))
{
if (!foundPixInstallation || wcscmp(newestVersionFound, findData.cFileName) <= 0)
{
// length - 1 to get rid of the wildcard character in the search path
PIXERRORCHECK(StringCchCopyNW(possibleOutput, MAX_PATH, pixSearchPath, wcslen(pixSearchPath) - 1));
PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, findData.cFileName));
PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, L"\\"));
PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, capturerDllName));
DWORD result = PixImpl::GetFileAttributesW(possibleOutput);
if (result != INVALID_FILE_ATTRIBUTES && !(result & FILE_ATTRIBUTE_DIRECTORY))
{
foundPixInstallation = true;
PIXERRORCHECK(StringCchCopyW(newestVersionFound, _countof(newestVersionFound), findData.cFileName));
PIXERRORCHECK(StringCchCopyW(output, _countof(possibleOutput), possibleOutput));
}
}
}
} while (PixImpl::FindNextFileW(hFind, &findData) != 0);
}
PixImpl::FindClose(hFind);
if (!foundPixInstallation)
{
SetLastError(ERROR_FILE_NOT_FOUND);
return nullptr;
}
return PixImpl::LoadLibraryExW(output, flags);
}
}
#undef PIXERRORCHECK
__forceinline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary()
{
return PixImpl::PIXLoadLatestCapturerLibrary(
L"WinPixGpuCapturer.dll",
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
}
__forceinline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary()
{
return PixImpl::PIXLoadLatestCapturerLibrary(
L"WinPixTimingCapturer.dll",
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
}
__forceinline HRESULT WINAPI PIXSetTargetWindow(HWND hwnd)
{
typedef void(WINAPI* SetGlobalTargetWindowFn)(HWND);
auto fn = (SetGlobalTargetWindowFn)PixImpl::GetGpuCaptureFunctionPtr("SetGlobalTargetWindow");
if (fn == nullptr)
{
return HRESULT_FROM_WIN32(GetLastError());
}
fn(hwnd);
return S_OK;
}
__forceinline HRESULT WINAPI PIXGpuCaptureNextFrames(PCWSTR fileName, UINT32 numFrames)
{
typedef HRESULT(WINAPI* CaptureNextFrameFn)(PCWSTR, UINT32);
auto fn = (CaptureNextFrameFn)PixImpl::GetGpuCaptureFunctionPtr("CaptureNextFrame");
if (fn == nullptr)
{
return HRESULT_FROM_WIN32(GetLastError());
}
return fn(fileName, numFrames);
}
extern "C" __forceinline HRESULT WINAPI PIXBeginCapture2(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters)
{
if (captureFlags == PIX_CAPTURE_GPU)
{
typedef HRESULT(WINAPI* BeginProgrammaticGpuCaptureFn)(const PPIXCaptureParameters);
auto fn = (BeginProgrammaticGpuCaptureFn)PixImpl::GetGpuCaptureFunctionPtr("BeginProgrammaticGpuCapture");
if (fn == nullptr)
{
return HRESULT_FROM_WIN32(GetLastError());
}
return fn(captureParameters);
}
else if (captureFlags == PIX_CAPTURE_TIMING)
{
typedef HRESULT(WINAPI* BeginProgrammaticTimingCaptureFn)(void const*, UINT64);
auto fn = (BeginProgrammaticTimingCaptureFn)PixImpl::GetTimingCaptureFunctionPtr("BeginProgrammaticTimingCapture");
if (fn == nullptr)
{
return HRESULT_FROM_WIN32(GetLastError());
}
return fn(&captureParameters->TimingCaptureParameters, sizeof(captureParameters->TimingCaptureParameters));
}
else
{
return E_NOTIMPL;
}
}
extern "C" __forceinline HRESULT WINAPI PIXEndCapture(BOOL discard)
{
// We can't tell if the user wants to end a GPU Capture or a Timing Capture.
// The user shouldn't have both WinPixGpuCapturer and WinPixTimingCapturer loaded in the process though,
// so we can just look for one of them and call it.
typedef HRESULT(WINAPI* EndProgrammaticGpuCaptureFn)(void);
auto gpuFn = (EndProgrammaticGpuCaptureFn)PixImpl::GetGpuCaptureFunctionPtr("EndProgrammaticGpuCapture");
if (gpuFn != NULL)
{
return gpuFn();
}
typedef HRESULT(WINAPI* EndProgrammaticTimingCaptureFn)(BOOL);
auto timingFn = (EndProgrammaticTimingCaptureFn)PixImpl::GetTimingCaptureFunctionPtr("EndProgrammaticTimingCapture");
if (timingFn != NULL)
{
return timingFn(discard);
}
return HRESULT_FROM_WIN32(GetLastError());
}
__forceinline HRESULT WINAPI PIXForceD3D11On12()
{
typedef HRESULT (WINAPI* ForceD3D11On12Fn)(void);
auto fn = (ForceD3D11On12Fn)PixImpl::GetGpuCaptureFunctionPtr("ForceD3D11On12");
if (fn == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
return fn();
}
__forceinline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions hudOptions)
{
typedef HRESULT(WINAPI* SetHUDOptionsFn)(PIXHUDOptions);
auto fn = (SetHUDOptionsFn)PixImpl::GetGpuCaptureFunctionPtr("SetHUDOptions");
if (fn == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
return fn(hudOptions);
}
__forceinline bool WINAPI PIXIsAttachedForGpuCapture()
{
typedef bool(WINAPI* GetIsAttachedToPixFn)(void);
auto fn = (GetIsAttachedToPixFn)PixImpl::GetGpuCaptureFunctionPtr("GetIsAttachedToPix");
if (fn == NULL)
{
OutputDebugStringW(L"WinPixEventRuntime error: Mismatched header/dll. Please ensure that pix3.h and WinPixGpuCapturer.dll match");
return false;
}
return fn();
}
__forceinline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR fileName)
{
return ShellExecuteW(0, 0, fileName, 0, 0, SW_SHOW);
}
#else
__forceinline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary()
{
return nullptr;
}
__forceinline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary()
{
return nullptr;
}
__forceinline HRESULT WINAPI PIXSetTargetWindow(HWND)
{
return E_NOTIMPL;
}
__forceinline HRESULT WINAPI PIXGpuCaptureNextFrames(PCWSTR, UINT32)
{
return E_NOTIMPL;
}
extern "C" __forceinline HRESULT WINAPI PIXBeginCapture2(DWORD, _In_opt_ const PPIXCaptureParameters)
{
return E_NOTIMPL;
}
extern "C" __forceinline HRESULT WINAPI PIXEndCapture(BOOL)
{
return E_NOTIMPL;
}
__forceinline HRESULT WINAPI PIXForceD3D11On12()
{
return E_NOTIMPL;
}
__forceinline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions)
{
return E_NOTIMPL;
}
__forceinline bool WINAPI PIXIsAttachedForGpuCapture()
{
return false;
}
__forceinline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR)
{
return 0;
}
#endif // WINAPI_PARTITION
#endif // USE_PIX_SUPPORTED_ARCHITECTURE || USE_PIX
#if defined(__d3d12_h__)
inline void PIXInsertTimingMarkerOnContextForBeginEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
{
UNREFERENCED_PARAMETER(eventType);
commandList->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size);
}
inline void PIXInsertTimingMarkerOnContextForBeginEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
{
UNREFERENCED_PARAMETER(eventType);
commandQueue->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size);
}
inline void PIXInsertTimingMarkerOnContextForSetMarker(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
{
UNREFERENCED_PARAMETER(eventType);
commandList->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size);
}
inline void PIXInsertTimingMarkerOnContextForSetMarker(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
{
UNREFERENCED_PARAMETER(eventType);
commandQueue->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size);
}
inline void PIXInsertTimingMarkerOnContextForEndEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType)
{
UNREFERENCED_PARAMETER(eventType);
commandList->EndEvent();
}
inline void PIXInsertTimingMarkerOnContextForEndEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType)
{
UNREFERENCED_PARAMETER(eventType);
commandQueue->EndEvent();
}
inline void PIXInsertGPUMarkerOnContextForBeginEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
{
UNREFERENCED_PARAMETER(eventType);
commandList->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size);
}
inline void PIXInsertGPUMarkerOnContextForBeginEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
{
UNREFERENCED_PARAMETER(eventType);
commandQueue->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size);
}
inline void PIXInsertGPUMarkerOnContextForSetMarker(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
{
UNREFERENCED_PARAMETER(eventType);
commandList->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size);
}
inline void PIXInsertGPUMarkerOnContextForSetMarker(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size)
{
UNREFERENCED_PARAMETER(eventType);
commandQueue->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size);
}
inline void PIXInsertGPUMarkerOnContextForEndEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8, void*, UINT)
{
commandList->EndEvent();
}
inline void PIXInsertGPUMarkerOnContextForEndEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8, void*, UINT)
{
commandQueue->EndEvent();
}
#endif
#endif //_PIX3_WIN_H_

View File

@ -0,0 +1,579 @@
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
Note: While Microsoft is not the author of the files below, Microsoft is
offering you a license subject to the terms of the Microsoft Software License
Terms for Microsoft PIX Developer Tool (the "Microsoft Program"). Microsoft
reserves all other rights. The notices below are provided for informational
purposes only and are not the license terms under which Microsoft distributes
these files.
The Microsoft Program includes the following third-party software:
1. Boost v. 1.66.0 (https://sourceforge.net/projects/boost/files/boost/1.66.0)
2. fmt v4.1.0 (https://github.com/fmtlib/fmt/releases/tag/4.1.0)
3. SQLite 3 (http://www.sqlite.org/)
4. AMD PIX Plugin
5. nlohmann JSON (https://github.com/nlohmann/json)
6. PresentMon (https://github.com/GameTechDev/PresentMon)
7. DirectXTex (https://github.com/microsoft/directxtex)
8. DirectXTK12 (https://github.com/microsoft/DirectXTK12)
9. Guidelines Support Library (GSL) (https://github.com/microsoft/GSL)
10. Windows Implementation Library (WIL) (https://github.com/microsoft/wil)
11. GoogleTest (https://github.com/google/googletest/)
12. Newtonsoft.Json (https://www.newtonsoft.com/json)
13. WIX (https://wixtoolset.org/)
14. Moq (https://github.com/moq/moq)
15. FluentAssertions (https://github.com/fluentassertions/fluentassertions)
16. .NET Community Toolkit (https://github.com/CommunityToolkit/dotnet)
17. LiveCharts (https://lvcharts.com)
18. NVIDIA PIX Plugin
As the recipient of the above third-party software, Microsoft sets forth a copy
of the notices and other information below.
BOOST NOTICES AND INFORMATION BEGIN HERE
========================================
Boost v. 1.66.0
Copyright Beman Dawes, David Abrahams, 1998-2005
Copyright Rene Rivera 2006-2007
Provided for Informational Purposes Only
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by this
license (the "Software") to use, reproduce, display, distribute, execute, and
transmit the Software, and to prepare derivative works of the Software, and to
permit third-parties to whom the Software is furnished to do so, all subject to
the following:
The copyright notices in the Software and this entire statement, including the
above license grant, this restriction and the following disclaimer, must be
included in all copies of the Software, in whole or in part, and all derivative
works of the Software, unless such copies or derivative works are solely in the
form of machine-executable object code generated by a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY
DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE
END OF BOOST NOTICES AND INFORMATION
====================================
FMT NOTICES AND INFORMATION BEGIN HERE
======================================
fmt v4.1.0
Copyright (c) 2012 - 2016, Victor Zverovich
Provided for Informational Purposes Only
BSD 2-clause
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
END OF FMT NOTICES AND INFORMATION
==================================
SQLITE3 NOTICES AND INFORMATION BEGIN HERE
==========================================
https://www.sqlite.org/copyright.html
SQLite Is Public Domain
All of the code and documentation in SQLite has been dedicated to the public
domain by the authors. All code authors, and representatives of the companies
they work for, have signed affidavits dedicating their contributions to the
public domain and originals of those signed affidavits are stored in a firesafe
at the main offices of Hwaci. Anyone is free to copy, modify, publish, use,
compile, sell, or distribute the original SQLite code, either in source code
form or as a compiled binary, for any purpose, commercial or non-commercial, and
by any means.
The previous paragraph applies to the deliverable code and documentation in SQLite -
those parts of the SQLite library that you actually bundle and ship with a larger
application. Some scripts used as part of the build process (for example the "configure"
scripts generated by autoconf) might fall under other open-source licenses. Nothing
from these build scripts ever reaches the final deliverable SQLite library, however,
and so the licenses associated with those scripts should not be a factor in assessing
your rights to copy and use the SQLite library.
All of the deliverable code in SQLite has been written from scratch. No code has been
taken from other projects or from the open internet. Every line of code can be traced
back to its original author, and all of those authors have public domain dedications
on file. So the SQLite code base is clean and is uncontaminated with licensed code
from other projects.
END OF SQLITE3 NOTICES AND INFORMATION
======================================
AMD NOTICES AND INFORMATION BEGIN HERE
======================================
AMD copyrighted code (MIT)
Copyright (c) 2017-2023 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Microsoft copyrighted code (MIT)
Copyright (c) Microsoft. All rights reserved.
This code is licensed under the MIT License (MIT).
THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
END OF AMD NOTICES AND INFORMATION
==================================
NLOHMANN JSON NOTICES AND INFORMATION BEGIN HERE
======================================
MIT License
Copyright (c) 2013-2021 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
END OF NLOHMANN JSON NOTICES AND INFORMATION
==================================
PRESENTMON NOTICES AND INFORMATION BEGIN HERE
======================================
Copyright (C) 2017-2021 Intel Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
END OF PRESENTMON NOTICES AND INFORMATION
==================================
DIRECTXTEX NOTICES AND INFORMATION BEGIN HERE
======================================
Copyright (c) 2011-2021 Microsoft Corp
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
END OF DIRECTXTEX NOTICES AND INFORMATION
==================================
DIRECTXTK12 NOTICES AND INFORMATION BEGIN HERE
======================================
Copyright (c) 2016-2021 Microsoft Corp
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
END OF DIRECTXTK12 NOTICES AND INFORMATION
==================================
GSL NOTICES AND INFORMATION BEGIN HERE
======================================
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
This code is licensed under the MIT License (MIT).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
END OF GSL NOTICES AND INFORMATION
==================================
WIL NOTICES AND INFORMATION BEGIN HERE
======================================
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
END OF WIL NOTICES AND INFORMATION
==================================
GOOGLETEST NOTICES AND INFORMATION BEGIN HERE
======================================
Copyright 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
END OF GOOGLETEST NOTICES AND INFORMATION
==================================
NEWTONSOFT.JSON NOTICES AND INFORMATION BEGIN HERE
======================================
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
END OF NEWTONSOFT.JSON NOTICES AND INFORMATION
=================================
WIX NOTICES AND INFORMATION BEGIN HERE
======================================
Copyright (c) .NET Foundation and contributors. This software is released under
the Microsoft Reciprocal License (MS-RL) (the "License"); you may not use the
software except in compliance with the License.
The text of the Microsoft Reciprocal License (MS-RL) can be found online at:
http://opensource.org/licenses/ms-rl
Microsoft Reciprocal License (MS-RL)
This license governs use of the accompanying software. If you use the software,
you accept this license. If you do not accept the license, do not use the
software.
1. Definitions The terms "reproduce," "reproduction," "derivative works," and
"distribution" have the same meaning here as under U.S. copyright law. A
"contribution" is the original software, or any additions or changes to the
software. A "contributor" is any person that distributes its contribution under
this license. "Licensed patents" are a contributor's patent claims that read
directly on its contribution.
2. Grant of Rights (A) Copyright Grant- Subject to the terms of this license,
including the license conditions and limitations in section 3, each contributor
grants you a non-exclusive, worldwide, royalty-free copyright license to
reproduce its contribution, prepare derivative works of its contribution, and
distribute its contribution or any derivative works that you create. (B) Patent
Grant- Subject to the terms of this license, including the license conditions and
limitations in section 3, each contributor grants you a non-exclusive, worldwide,
royalty-free license under its licensed patents to make, have made, use, sell,
offer for sale, import, and/or otherwise dispose of its contribution in the
software or derivative works of the contribution in the software.
3. Conditions and Limitations (A) Reciprocal Grants- For any file you distribute
that contains code from the software (in source code or binary format), you must
provide recipients the source code to that file along with a copy of this
license, which license will govern that file. You may license other files that
are entirely your own work and do not contain code from the software under any
terms you choose. (B) No Trademark License- This license does not grant you
rights to use any contributors' name, logo, or trademarks. (C) If you bring a
patent claim against any contributor over patents that you claim are infringed by
the software, your patent license from such contributor to the software ends
automatically. (D) If you distribute any portion of the software, you must retain
all copyright, patent, trademark, and attribution notices that are present in the
software. (E) If you distribute any portion of the software in source code form,
you may do so only under this license by including a complete copy of this
license with your distribution. If you distribute any portion of the software in
compiled or object code form, you may only do so under a license that complies
with this license. (F) The software is licensed "as-is." You bear the risk of
using it. The contributors give no express warranties, guarantees or conditions.
You may have additional consumer rights under your local laws which this license
cannot change. To the extent permitted under your local laws, the contributors
exclude the implied warranties of merchantability, fitness for a particular
purpose and non-infringement.
END OF WIX NOTICES AND INFORMATION
=================================
MOQ NOTICES AND INFORMATION BEGIN HERE
======================================
MIT License
Copyright (c) Daniel Cazzulino and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
END OF MOQ NOTICES AND INFORMATION
==================================
FLUENTASSERTIONS NOTICES AND INFORMATION BEGIN HERE
===================================================
Copyright [2010-2021] [Dennis Doomen]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
END OF FLUENTASSERTIONS NOTICES AND INFORMATION
===============================================
.NET COMMUNITY TOOLKIT NOTICES AND INFORMATION BEGIN HERE
======================================
MIT License
Copyright © .NET Foundation and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
END OF .NET COMMUNITY TOOLKIT NOTICES AND INFORMATION
==================================
LIVE CHARTS NOTICES AND INFORMATION BEGIN HERE
======================================
MIT License
Copyright (c) 2021 Alberto Rodriguez Orozco
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
END OF LIVE CHARTS NOTICES AND INFORMATION
==================================
NVIDIA PIX PLUGIN NOTICES AND INFORMATION BEGIN HERE
======================================
Copyright (c) Microsoft Corporation.
Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
END OF NVIDIA PIX PLUGIN NOTICES AND INFORMATION
==================================

View File

@ -0,0 +1,21 @@
Copyright (c) Microsoft Corporation.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

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

View File

@ -0,0 +1,4 @@
#pragma once
#include <kinc/graphics5/graphics.h>
#include <kinc/math/matrix.h>

View File

@ -0,0 +1,398 @@
#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));
kinc_g4_set_texture(g4_unit, &texture->impl.texture);
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) {}

View File

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

View File

@ -0,0 +1,28 @@
#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);
}
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;
}

View File

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

View File

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

View File

@ -0,0 +1,15 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
int lastStart;
int lastCount;
int mySize;
} ConstantBuffer5Impl;
#ifdef __cplusplus
}
#endif

View File

@ -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"

View File

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

View File

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

View File

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

View File

@ -0,0 +1,63 @@
#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);
}
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;
}
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);
}

View File

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

View File

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

View File

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

View File

@ -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) {}

View File

@ -0,0 +1,5 @@
#pragma once
typedef struct kinc_g5_sampler_impl {
int a;
} kinc_g5_sampler_impl_t;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,5 @@
#pragma once
#include <kinc/graphics5/graphics.h>
#include <kinc/image.h>
#include <kinc/math/matrix.h>

View File

@ -0,0 +1,259 @@
#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) {}
#ifdef __cplusplus
extern "C" {
#endif
extern void kinc_g4_on_g5_internal_resize(int, int, int);
#ifdef __cplusplus
}
#endif
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;
}

View File

@ -0,0 +1,7 @@
#pragma once
struct kinc_g5_index_buffer;
typedef struct {
struct kinc_g5_index_buffer *current_index_buffer;
} CommandList5Impl;

View File

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

View File

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

View File

@ -0,0 +1,112 @@
#include <kinc/graphics4/texture.h>
#include <kinc/graphics5/compute.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 = {0};
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;
}

View File

@ -0,0 +1,8 @@
#pragma once
typedef struct {
void *_buffer;
int lastStart;
int lastCount;
int mySize;
} ConstantBuffer5Impl;

View File

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

View File

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

View File

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

View File

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

View File

@ -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"

View File

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

View File

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

View File

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

View File

@ -0,0 +1,180 @@
#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;
API_AVAILABLE(macos(11.0), ios(14.0))
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) {}
API_AVAILABLE(macos(11.0), ios(14.0))
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;
}
API_AVAILABLE(macos(11.0), ios(14.0))
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;
}
API_AVAILABLE(macos(11.0), ios(14.0))
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];
}
API_AVAILABLE(macos(11.0), ios(14.0))
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];
}

View File

@ -0,0 +1,7 @@
#pragma once
typedef struct {
void *_tex;
void *_texReadback;
void *_depthTex;
} RenderTarget5Impl;

View File

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

View File

@ -0,0 +1,5 @@
#pragma once
typedef struct kinc_g5_sampler_impl {
void *sampler;
} kinc_g5_sampler_impl_t;

View File

@ -0,0 +1,72 @@
#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:
if (@available(iOS 14.0, *)) {
return MTLSamplerAddressModeClampToBorderColor;
}
else {
return MTLSamplerAddressModeClampToEdge;
}
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;
}

View File

@ -0,0 +1,6 @@
#pragma once
typedef struct {
char name[1024];
void *mtlFunction;
} Shader5Impl;

View File

@ -0,0 +1,55 @@
#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) {
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]];
assert(shader->impl.mtlFunction);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,3 @@
#pragma once
#include <vulkan/vulkan_core.h>

View File

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

View File

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

View File

@ -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,
&region);
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, &currentRenderPassBeginInfo, 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);
}
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "MiniVulkan.h"
typedef struct {
int _indexCount;
VkCommandBuffer _buffer;
VkFence fence;
} CommandList5Impl;

View File

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

View File

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

View File

@ -0,0 +1,96 @@
#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.fragment_uniform_buffer != NULL && vk_ctx.compute_uniform_buffer != NULL) {
// allow writing the buffers again after G4onG5 wrote them
vk_ctx.vertex_uniform_buffer = NULL;
vk_ctx.fragment_uniform_buffer = NULL;
vk_ctx.compute_uniform_buffer = NULL;
}
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;
}

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More