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

292 lines
10 KiB
Objective-C

#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(KORE_IOS) || defined(KORE_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