#include #include #include 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); }