Files
2025-01-29 10:55:49 +01:00

354 lines
14 KiB
C

#include <kinc/graphics4/texture.h>
#include <kinc/graphics4/textureunit.h>
#include <assert.h>
static kinc_g4_texture_t *setTextures[16] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static DXGI_FORMAT convertFormat(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:
assert(false);
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:
assert(false);
return 4;
}
}
static bool isHdr(kinc_image_format_t format) {
return format == KINC_IMAGE_FORMAT_RGBA128 || format == KINC_IMAGE_FORMAT_RGBA64 || format == KINC_IMAGE_FORMAT_A32 || format == KINC_IMAGE_FORMAT_A16;
}
void kinc_g4_texture_init_from_image(kinc_g4_texture_t *texture, kinc_image_t *image) {
memset(&texture->impl, 0, sizeof(texture->impl));
texture->impl.stage = 0;
texture->tex_width = image->width;
texture->tex_height = image->height;
texture->tex_depth = 1;
texture->format = image->format;
texture->impl.rowPitch = 0;
D3D11_TEXTURE2D_DESC desc;
desc.Width = image->width;
desc.Height = image->height;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = convertFormat(image->format);
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0; // D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = image->data;
data.SysMemPitch = image->width * formatByteSize(image->format);
data.SysMemSlicePitch = 0;
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateTexture2D(dx_ctx.device, &desc, &data, &texture->impl.texture));
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateShaderResourceView(dx_ctx.device, (ID3D11Resource *)texture->impl.texture, NULL, &texture->impl.view));
}
void kinc_g4_texture_init_from_image3d(kinc_g4_texture_t *texture, kinc_image_t *image) {
memset(&texture->impl, 0, sizeof(texture->impl));
texture->impl.stage = 0;
texture->tex_width = image->width;
texture->tex_height = image->height;
texture->tex_depth = image->depth;
texture->format = image->format;
texture->impl.rowPitch = 0;
D3D11_TEXTURE3D_DESC desc;
desc.Width = image->width;
desc.Height = image->height;
desc.Depth = image->depth;
desc.MipLevels = 1;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.MiscFlags = 0;
desc.Format = convertFormat(image->format);
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA data;
data.pSysMem = image->data;
data.SysMemPitch = image->width * formatByteSize(image->format);
data.SysMemSlicePitch = image->width * image->height * formatByteSize(image->format);
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateTexture3D(dx_ctx.device, &desc, &data, &texture->impl.texture3D));
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateShaderResourceView(dx_ctx.device, (ID3D11Resource *)texture->impl.texture3D, NULL, &texture->impl.view));
}
void kinc_g4_texture_init(kinc_g4_texture_t *texture, int width, int height, kinc_image_format_t format) {
memset(&texture->impl, 0, sizeof(texture->impl));
texture->impl.stage = 0;
texture->tex_width = width;
texture->tex_height = height;
texture->tex_depth = 1;
texture->format = format;
D3D11_TEXTURE2D_DESC desc;
desc.Width = width;
desc.Height = height;
desc.MipLevels = desc.ArraySize = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.MiscFlags = 0;
if (format == KINC_IMAGE_FORMAT_RGBA128) { // for compute
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
}
else {
desc.Format = convertFormat(format);
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
}
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateTexture2D(dx_ctx.device, &desc, NULL, &texture->impl.texture));
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateShaderResourceView(dx_ctx.device, (ID3D11Resource *)texture->impl.texture, NULL, &texture->impl.view));
if (format == KINC_IMAGE_FORMAT_RGBA128) {
D3D11_UNORDERED_ACCESS_VIEW_DESC du;
du.Format = desc.Format;
du.Texture2D.MipSlice = 0;
du.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
kinc_microsoft_affirm(
dx_ctx.device->lpVtbl->CreateUnorderedAccessView(dx_ctx.device, (ID3D11Resource *)texture->impl.texture, &du, &texture->impl.computeView));
}
}
void kinc_g4_texture_init3d(kinc_g4_texture_t *texture, int width, int height, int depth, kinc_image_format_t format) {
memset(&texture->impl, 0, sizeof(texture->impl));
texture->impl.stage = 0;
texture->tex_width = width;
texture->tex_height = height;
texture->tex_depth = depth;
texture->format = format;
texture->impl.hasMipmaps = true;
D3D11_TEXTURE3D_DESC desc;
desc.Width = width;
desc.Height = height;
desc.Depth = depth;
desc.MipLevels = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
desc.Format = format == KINC_IMAGE_FORMAT_RGBA32 ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R8_UNORM;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET | D3D11_BIND_UNORDERED_ACCESS;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.CPUAccessFlags = 0;
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateTexture3D(dx_ctx.device, &desc, NULL, &texture->impl.texture3D));
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateShaderResourceView(dx_ctx.device, (ID3D11Resource *)texture->impl.texture3D, NULL, &texture->impl.view));
}
// TextureImpl::TextureImpl() : hasMipmaps(false), renderView(nullptr), computeView(nullptr) {}
void kinc_internal_texture_unset(kinc_g4_texture_t *texture);
void kinc_g4_texture_destroy(kinc_g4_texture_t *texture) {
kinc_internal_texture_unset(texture);
if (texture->impl.view != NULL) {
texture->impl.view->lpVtbl->Release(texture->impl.view);
}
if (texture->impl.texture != NULL) {
texture->impl.texture->lpVtbl->Release(texture->impl.texture);
}
if (texture->impl.texture3D != NULL) {
texture->impl.texture3D->lpVtbl->Release(texture->impl.texture3D);
}
if (texture->impl.computeView != NULL) {
texture->impl.computeView->lpVtbl->Release(texture->impl.computeView);
}
}
void kinc_internal_texture_unmipmap(kinc_g4_texture_t *texture) {
texture->impl.hasMipmaps = false;
}
#ifdef KINC_KONG
void kinc_internal_texture_set(kinc_g4_texture_t *texture, uint32_t unit) {
dx_ctx.context->lpVtbl->PSSetShaderResources(dx_ctx.context, unit, 1, &texture->impl.view);
texture->impl.stage = unit;
setTextures[unit] = texture;
}
#else
void kinc_internal_texture_set(kinc_g4_texture_t *texture, kinc_g4_texture_unit_t unit) {
if (unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT] < 0 && unit.stages[KINC_G4_SHADER_TYPE_VERTEX] < 0)
return;
if (unit.stages[KINC_G4_SHADER_TYPE_VERTEX] >= 0) {
dx_ctx.context->lpVtbl->VSSetShaderResources(dx_ctx.context, unit.stages[KINC_G4_SHADER_TYPE_VERTEX], 1, &texture->impl.view);
}
if (unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT] >= 0) {
dx_ctx.context->lpVtbl->PSSetShaderResources(dx_ctx.context, unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT], 1, &texture->impl.view);
}
texture->impl.stage = unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT] >= 0 ? unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT] : unit.stages[KINC_G4_SHADER_TYPE_VERTEX];
setTextures[texture->impl.stage] = texture;
}
#endif
void kinc_internal_texture_set_image(kinc_g4_texture_t *texture, kinc_g4_texture_unit_t unit) {
if (unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT] < 0)
return;
if (texture->impl.computeView == NULL) {
D3D11_UNORDERED_ACCESS_VIEW_DESC du;
du.Format = texture->format == KINC_IMAGE_FORMAT_RGBA32 ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R8_UNORM;
du.Texture3D.MipSlice = 0;
du.Texture3D.FirstWSlice = 0;
du.Texture3D.WSize = -1;
du.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
kinc_microsoft_affirm(
dx_ctx.device->lpVtbl->CreateUnorderedAccessView(dx_ctx.device, (ID3D11Resource *)texture->impl.texture3D, &du, &texture->impl.computeView));
}
dx_ctx.context->lpVtbl->OMSetRenderTargetsAndUnorderedAccessViews(dx_ctx.context, 0, NULL, NULL, unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT], 1,
&texture->impl.computeView, NULL);
}
void kinc_internal_texture_unset(kinc_g4_texture_t *texture) {
if (setTextures[texture->impl.stage] == texture) {
setTextures[texture->impl.stage] = NULL;
}
}
uint8_t *kinc_g4_texture_lock(kinc_g4_texture_t *texture) {
D3D11_MAPPED_SUBRESOURCE mappedResource;
kinc_microsoft_affirm(dx_ctx.context->lpVtbl->Map(dx_ctx.context, (ID3D11Resource *)texture->impl.texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource));
texture->impl.rowPitch = mappedResource.RowPitch;
return (uint8_t *)mappedResource.pData;
}
void kinc_g4_texture_unlock(kinc_g4_texture_t *texture) {
dx_ctx.context->lpVtbl->Unmap(dx_ctx.context, (ID3D11Resource *)texture->impl.texture, 0);
}
void kinc_g4_texture_clear(kinc_g4_texture_t *texture, int x, int y, int z, int width, int height, int depth, unsigned color) {
if (texture->impl.renderView == NULL) {
texture->tex_depth > 1 ? kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateRenderTargetView(dx_ctx.device, (ID3D11Resource *)texture->impl.texture3D,
0, &texture->impl.renderView))
: kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateRenderTargetView(dx_ctx.device, (ID3D11Resource *)texture->impl.texture, 0,
&texture->impl.renderView));
}
static float clearColor[4];
clearColor[0] = ((color & 0x00ff0000) >> 16) / 255.0f;
clearColor[1] = ((color & 0x0000ff00) >> 8) / 255.0f;
clearColor[2] = (color & 0x000000ff) / 255.0f;
clearColor[3] = ((color & 0xff000000) >> 24) / 255.0f;
dx_ctx.context->lpVtbl->ClearRenderTargetView(dx_ctx.context, texture->impl.renderView, clearColor);
}
int kinc_g4_texture_stride(kinc_g4_texture_t *texture) {
assert(texture->impl.rowPitch != 0); // stride is not yet set, lock and unlock the texture first (or find a good fix for this and send a PR)
return texture->impl.rowPitch;
}
static void enableMipmaps(kinc_g4_texture_t *texture, int texWidth, int texHeight, int format) {
D3D11_TEXTURE2D_DESC desc;
desc.Width = texWidth;
desc.Height = texHeight;
desc.MipLevels = 0;
desc.ArraySize = 1;
desc.Format = convertFormat((kinc_image_format_t)format);
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
desc.CPUAccessFlags = 0;
desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
ID3D11Texture2D *mipMappedTexture;
ID3D11ShaderResourceView *mipMappedView;
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateTexture2D(dx_ctx.device, &desc, NULL, &mipMappedTexture));
kinc_microsoft_affirm(dx_ctx.device->lpVtbl->CreateShaderResourceView(dx_ctx.device, (ID3D11Resource *)mipMappedTexture, NULL, &mipMappedView));
D3D11_BOX sourceRegion;
sourceRegion.left = 0;
sourceRegion.right = texWidth;
sourceRegion.top = 0;
sourceRegion.bottom = texHeight;
sourceRegion.front = 0;
sourceRegion.back = 1;
dx_ctx.context->lpVtbl->CopySubresourceRegion(dx_ctx.context, (ID3D11Resource *)mipMappedTexture, 0, 0, 0, 0, (ID3D11Resource *)texture->impl.texture, 0,
&sourceRegion);
if (texture->impl.texture != NULL) {
texture->impl.texture->lpVtbl->Release(texture->impl.texture);
}
texture->impl.texture = mipMappedTexture;
if (texture->impl.view != NULL) {
texture->impl.view->lpVtbl->Release(texture->impl.view);
}
texture->impl.view = mipMappedView;
texture->impl.hasMipmaps = true;
}
void kinc_g4_texture_generate_mipmaps(kinc_g4_texture_t *texture, int levels) {
if (!texture->impl.hasMipmaps) {
enableMipmaps(texture, texture->tex_width, texture->tex_height, texture->format);
}
dx_ctx.context->lpVtbl->GenerateMips(dx_ctx.context, texture->impl.view);
}
void kinc_g4_texture_set_mipmap(kinc_g4_texture_t *texture, kinc_image_t *mipmap, int level) {
if (!texture->impl.hasMipmaps) {
enableMipmaps(texture, texture->tex_width, texture->tex_height, texture->format);
}
D3D11_BOX dstRegion;
dstRegion.left = 0;
dstRegion.right = mipmap->width;
dstRegion.top = 0;
dstRegion.bottom = mipmap->height;
dstRegion.front = 0;
dstRegion.back = 1;
dx_ctx.context->lpVtbl->UpdateSubresource(dx_ctx.context, (ID3D11Resource *)texture->impl.texture, level, &dstRegion, mipmap->data,
mipmap->width * formatByteSize(mipmap->format), 0);
}