From 43fcf81381473a06afbb8aaa87b9eb35a93ce232 Mon Sep 17 00:00:00 2001 From: mid <> Date: Sat, 10 May 2025 18:15:39 +0300 Subject: [PATCH] Fix mipmapping and add texture compression --- src/k3.c | 110 ++++++++++++++++++++++++++++++++++++++++------ src/k3_internal.h | 9 ++++ 2 files changed, 106 insertions(+), 13 deletions(-) diff --git a/src/k3.c b/src/k3.c index f75f9a9..21dcd32 100644 --- a/src/k3.c +++ b/src/k3.c @@ -26,6 +26,13 @@ bool k3IsCore = 0; static struct k3GLSLP *basicBlitProgram; static struct k3GLSLP *basicCubemapProgram; +typedef void*(*TextureOfflineCompressorFunc)(const void *pixels, uint16_t width, uint16_t height, GLenum externalFmt, GLenum intype, size_t *compressedSize); + +static bool TextureCompressionEnabled; +static GLenum TextureCompressionRGBA; +static GLenum TextureCompressionSRGBA; +static TextureOfflineCompressorFunc TextureOfflineCompressor; + void k3StorageRef(struct k3Storage *s) { s->ref++; } @@ -438,6 +445,7 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid GLint internalFmt, externalFmt, intype; int linearFilter, mipmap; + int compressed = 0; switch(type) { case k3_RAWCOLOR: @@ -448,7 +456,8 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid mipmap = 1; break; case k3_NORMAL: - internalFmt = GL_RGBA; + compressed = TextureCompressionEnabled; + internalFmt = compressed ? TextureCompressionRGBA : GL_RGBA; externalFmt = GL_RGBA; intype = GL_UNSIGNED_BYTE; linearFilter = 1; @@ -456,8 +465,9 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid break; case k3_DIFFUSE: case k3_EMISSION: - internalFmt = GLAD_GL_EXT_texture_compression_s3tc - ? (GLAD_GL_EXT_texture_sRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) + compressed = TextureCompressionEnabled; + internalFmt = compressed + ? (GLAD_GL_EXT_texture_sRGB ? TextureCompressionSRGBA : TextureCompressionRGBA) : (GLAD_GL_EXT_texture_sRGB ? GL_SRGB8_ALPHA8_EXT : GL_RGBA8); externalFmt = GL_RGBA; intype = GL_UNSIGNED_BYTE; @@ -480,7 +490,7 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid mipmap = 1; break; case k3_DEPTH: - internalFmt = GL_DEPTH_COMPONENT24; + internalFmt = GL_DEPTH_COMPONENT32F; externalFmt = GL_DEPTH_COMPONENT; intype = GL_UNSIGNED_INT; if(!k3IsCore) glTexParameteri(target, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); @@ -502,12 +512,9 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { - if(!k3IsCore && !mipmap) { - glTexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); - } else { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if(!k3IsCore && mipmap) { + glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE); } - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } if(type == k3_DEPTH) { @@ -515,13 +522,18 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); } + + if(!tex->cubemap && mipmap) { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linearFilter ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST); + } else { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST); + } } else { glBindTexture(target, tex->tex); } - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, linearFilter ? GL_LINEAR : GL_NEAREST); - if(k3IsCore && type == k3_ALPHA) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE); @@ -535,7 +547,16 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid k3Log(k3_WARN, "Non-zero index passed for non-cubemap texture"); } - glTexImage2D(target, 0, internalFmt, width, height, 0, externalFmt, intype, data); + if(compressed && TextureOfflineCompressor) { + size_t len; + data = TextureOfflineCompressor(data, width, height, externalFmt, intype, &len); + + glCompressedTexImage2D(target, 0, internalFmt, width, height, 0, len, data); + + free(data); + } else { + glTexImage2D(target, 0, internalFmt, width, height, 0, externalFmt, intype, data); + } if(!tex->cubemap && k3IsCore && mipmap) { glGenerateMipmap(target); @@ -544,6 +565,8 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid tex->szX = width; tex->szY = height; tex->szZ = 0; + + tex->glInternalFormat = internalFmt; } uint32_t k3TexSzX(struct k3Tex *this) { return this->szX; @@ -2201,6 +2224,50 @@ void GlCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei } } +#include"compr/bc7enc.h" +static void *compress_rgba_bc7(const void *pixels, uint16_t width, uint16_t height, GLenum externalFmt, GLenum intype, size_t *compressedSize) { + static bool called = false; + if(!called) { + bc7enc_compress_block_init(); + called = true; + } + + assert(externalFmt == GL_RGBA); + assert(intype == GL_UNSIGNED_BYTE); + + uint16_t blockWidth = (width + 3) / 4; + uint16_t blockHeight = (height + 3) / 4; + + size_t blocks = blockWidth * blockHeight; + + *compressedSize = blocks * 16; + + uint8_t *output = calloc(blocks, 16); + + #pragma omp parallel + { + bc7enc_compress_block_params p; + bc7enc_compress_block_params_init(&p); + + #pragma omp for + for(size_t blk = 0; blk < blocks; blk++) { + uint8_t blockPixels[64]; + + uint16_t blkX = blk % blockWidth; + uint16_t blkY = blk / blockWidth; + + memcpy(blockPixels + 0, pixels + 4 * (((blkY * 4) + 0) * width + (blkX * 4)), 16); + memcpy(blockPixels +16, pixels + 4 * (((blkY * 4) + 1) * width + (blkX * 4)), 16); + memcpy(blockPixels +32, pixels + 4 * (((blkY * 4) + 2) * width + (blkX * 4)), 16); + memcpy(blockPixels +48, pixels + 4 * (((blkY * 4) + 3) * width + (blkX * 4)), 16); + + bc7enc_compress_block(output + blk * 16, blockPixels, &p); + } + } + + return output; +} + void k3Init() { if(GLAD_GL_ARB_debug_output) { glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); @@ -2259,6 +2326,23 @@ void k3Init() { "}\n" , NULL), NULL); } + + /*if(GLAD_GL_KHR_texture_compression_astc_ldr) { + TextureCompressionEnabled = true; + + + } else */ if(GLAD_GL_ARB_texture_compression_bptc || GLAD_GL_VERSION_4_2) { + TextureCompressionEnabled = true; + + TextureCompressionSRGBA = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; + TextureCompressionRGBA = GL_COMPRESSED_RGBA_BPTC_UNORM; + TextureOfflineCompressor = compress_rgba_bc7; + } else if(GL_EXT_texture_compression_s3tc) { + TextureCompressionEnabled = true; + + TextureCompressionSRGBA = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + TextureCompressionRGBA = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } } static size_t preprocess(char *src, const char*(*ldr)(const char *fn), const char ***strs, GLuint **sizes) { diff --git a/src/k3_internal.h b/src/k3_internal.h index 2ec7740..318d3d9 100644 --- a/src/k3_internal.h +++ b/src/k3_internal.h @@ -20,6 +20,15 @@ struct k3Tex { uint32_t szX; uint32_t szY; uint32_t szZ; + GLuint glInternalFormat; + GLuint glExternalFormat; + GLuint glInType; + bool mipmap; + + // Asynchronous decoding + uint8_t deferredRemaining; + uint8_t *deferredData[6]; + struct k3Tex *deferredNext; }; struct k3Storage {