292 lines
10 KiB
Objective-C
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
|