diff options
Diffstat (limited to 'source/blender/gpu/metal/mtl_texture.mm')
-rw-r--r-- | source/blender/gpu/metal/mtl_texture.mm | 125 |
1 files changed, 106 insertions, 19 deletions
diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm index 2b7c2333bff..4af46c13751 100644 --- a/source/blender/gpu/metal/mtl_texture.mm +++ b/source/blender/gpu/metal/mtl_texture.mm @@ -20,6 +20,7 @@ #include "mtl_context.hh" #include "mtl_debug.hh" #include "mtl_texture.hh" +#include "mtl_vertex_buffer.hh" #include "GHOST_C-api.h" @@ -50,7 +51,6 @@ void gpu::MTLTexture::mtl_texture_init() /* VBO. */ vert_buffer_ = nullptr; vert_buffer_mtl_ = nil; - vert_buffer_offset_ = -1; /* Default Swizzle. */ tex_swizzle_mask_[0] = 'r'; @@ -169,26 +169,39 @@ void gpu::MTLTexture::bake_mip_swizzle_view() id<MTLTexture> gpu::MTLTexture::get_metal_handle() { - /* ensure up to date and baked. */ - this->ensure_baked(); - /* Verify VBO texture shares same buffer. */ if (resource_mode_ == MTL_TEXTURE_MODE_VBO) { - int r_offset = -1; + id<MTLBuffer> buf = vert_buffer_->get_metal_buffer(); + + /* Source vertex buffer has been re-generated, require re-initialisation. */ + if (buf != vert_buffer_mtl_) { + MTL_LOG_INFO( + "MTLTexture '%p' using MTL_TEXTURE_MODE_VBO requires re-generation due to updated " + "Vertex-Buffer.\n", + this); + /* Clear state. */ + this->reset(); + + /* Re-initialise. */ + this->init_internal(wrap(vert_buffer_)); + + /* Update for assertion check below. */ + buf = vert_buffer_->get_metal_buffer(); + } - /* TODO(Metal): Fetch buffer from MTLVertBuf when implemented. */ - id<MTLBuffer> buf = nil; /*vert_buffer_->get_metal_buffer(&r_offset);*/ + /* Ensure buffer is valid. + * Fetchvert buffer handle directly in-case it changed above. */ BLI_assert(vert_buffer_mtl_ != nil); - BLI_assert(buf == vert_buffer_mtl_ && r_offset == vert_buffer_offset_); - - UNUSED_VARS(buf); - UNUSED_VARS_NDEBUG(r_offset); + BLI_assert(vert_buffer_->get_metal_buffer() == vert_buffer_mtl_); } + /* ensure up to date and baked. */ + this->ensure_baked(); + if (is_baked_) { /* For explicit texture views, ensure we always return the texture view. */ if (resource_mode_ == MTL_TEXTURE_MODE_TEXTURE_VIEW) { - BLI_assert(mip_swizzle_view_ && "Texture view should always have a valid handle."); + BLI_assert_msg(mip_swizzle_view_, "Texture view should always have a valid handle."); } if (mip_swizzle_view_ != nil || texture_view_dirty_flags_) { @@ -208,7 +221,7 @@ id<MTLTexture> gpu::MTLTexture::get_metal_handle_base() /* For explicit texture views, always return the texture view. */ if (resource_mode_ == MTL_TEXTURE_MODE_TEXTURE_VIEW) { - BLI_assert(mip_swizzle_view_ && "Texture view should always have a valid handle."); + BLI_assert_msg(mip_swizzle_view_, "Texture view should always have a valid handle."); if (mip_swizzle_view_ != nil || texture_view_dirty_flags_) { bake_mip_swizzle_view(); } @@ -915,7 +928,7 @@ void gpu::MTLTexture::generate_mipmap() /* Ensure texture is baked. */ this->ensure_baked(); - BLI_assert(is_baked_ && texture_ && "MTLTexture is not valid"); + BLI_assert_msg(is_baked_ && texture_, "MTLTexture is not valid"); if (mipmaps_ == 1 || mtl_max_mips_ == 1) { MTL_LOG_WARNING("Call to generate mipmaps on texture with 'mipmaps_=1\n'"); @@ -1231,7 +1244,7 @@ void gpu::MTLTexture::read_internal(int mip, depth_format_mode = 4; break; default: - BLI_assert(false && "Unhandled depth read format case"); + BLI_assert_msg(false, "Unhandled depth read format case"); break; } } @@ -1445,11 +1458,85 @@ bool gpu::MTLTexture::init_internal() bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo) { - /* Zero initialize. */ - this->prepare_internal(); + /* Not a valid vertex buffer format, though verifying texture is not set as such + * as this is not supported on Apple Silicon. */ + BLI_assert_msg(this->format_ != GPU_DEPTH24_STENCIL8, + "Apple silicon does not support GPU_DEPTH24_S8"); - /* TODO(Metal): Add implementation for GPU Vert buf. */ - return false; + MTLPixelFormat mtl_format = gpu_texture_format_to_metal(this->format_); + mtl_max_mips_ = 1; + mipmaps_ = 0; + this->mip_range_set(0, 0); + + /* Create texture from GPUVertBuf's buffer. */ + MTLVertBuf *mtl_vbo = static_cast<MTLVertBuf *>(unwrap(vbo)); + mtl_vbo->bind(); + mtl_vbo->flag_used(); + + /* Get Metal Buffer. */ + id<MTLBuffer> source_buffer = mtl_vbo->get_metal_buffer(); + BLI_assert(source_buffer); + + /* Verify size. */ + if (w_ <= 0) { + MTL_LOG_WARNING("Allocating texture buffer of width 0!\n"); + w_ = 1; + } + + /* Verify Texture and vertex buffer alignment. */ + int bytes_per_pixel = get_mtl_format_bytesize(mtl_format); + int bytes_per_row = bytes_per_pixel * w_; + + MTLContext *mtl_ctx = MTLContext::get(); + uint align_requirement = static_cast<uint>( + [mtl_ctx->device minimumLinearTextureAlignmentForPixelFormat:mtl_format]); + + /* Verify per-vertex size aligns with texture size. */ + const GPUVertFormat *format = GPU_vertbuf_get_format(vbo); + BLI_assert(bytes_per_pixel == format->stride && + "Pixel format stride MUST match the texture format stride -- These being different " + "is likely caused by Metal's VBO padding to a minimum of 4-bytes per-vertex"); + UNUSED_VARS_NDEBUG(format); + + /* Create texture descriptor. */ + BLI_assert(type_ == GPU_TEXTURE_BUFFER); + texture_descriptor_ = [[MTLTextureDescriptor alloc] init]; + texture_descriptor_.pixelFormat = mtl_format; + texture_descriptor_.textureType = MTLTextureTypeTextureBuffer; + texture_descriptor_.width = w_; + texture_descriptor_.height = 1; + texture_descriptor_.depth = 1; + texture_descriptor_.arrayLength = 1; + texture_descriptor_.mipmapLevelCount = mtl_max_mips_; + texture_descriptor_.usage = + MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite | + MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */ + texture_descriptor_.storageMode = [source_buffer storageMode]; + texture_descriptor_.sampleCount = 1; + texture_descriptor_.cpuCacheMode = [source_buffer cpuCacheMode]; + texture_descriptor_.hazardTrackingMode = [source_buffer hazardTrackingMode]; + + texture_ = [source_buffer + newTextureWithDescriptor:texture_descriptor_ + offset:0 + bytesPerRow:ceil_to_multiple_u(bytes_per_row, align_requirement)]; + aligned_w_ = bytes_per_row / bytes_per_pixel; + + BLI_assert(texture_); + texture_.label = [NSString stringWithUTF8String:this->get_name()]; + is_baked_ = true; + is_dirty_ = false; + resource_mode_ = MTL_TEXTURE_MODE_VBO; + + /* Track Status. */ + vert_buffer_ = mtl_vbo; + vert_buffer_mtl_ = source_buffer; + + /* Cleanup. */ + [texture_descriptor_ release]; + texture_descriptor_ = nullptr; + + return true; } bool gpu::MTLTexture::init_internal(const GPUTexture *src, int mip_offset, int layer_offset) |