diff --git a/src/airconv/air_signature.hpp b/src/airconv/air_signature.hpp index 3924e6ad9..112c680b5 100644 --- a/src/airconv/air_signature.hpp +++ b/src/airconv/air_signature.hpp @@ -693,4 +693,146 @@ to_air_scaler_type(dxmt::shader::common::ScalerDataType type) { } } +enum class MTLPixelFormat : uint32_t { + Invalid = 0, + A8Unorm = 1, + R8Unorm = 10, + R8Unorm_sRGB = 11, + R8Snorm = 12, + R8Uint = 13, + R8Sint = 14, + R16Unorm = 20, + R16Snorm = 22, + R16Uint = 23, + R16Sint = 24, + R16Float = 25, + RG8Unorm = 30, + RG8Unorm_sRGB = 31, + RG8Snorm = 32, + RG8Uint = 33, + RG8Sint = 34, + B5G6R5Unorm = 40, + A1BGR5Unorm = 41, + ABGR4Unorm = 42, + BGR5A1Unorm = 43, + R32Uint = 53, + R32Sint = 54, + R32Float = 55, + RG16Unorm = 60, + RG16Snorm = 62, + RG16Uint = 63, + RG16Sint = 64, + RG16Float = 65, + RGBA8Unorm = 70, + RGBA8Unorm_sRGB = 71, + RGBA8Snorm = 72, + RGBA8Uint = 73, + RGBA8Sint = 74, + BGRA8Unorm = 80, + BGRA8Unorm_sRGB = 81, + RGB10A2Unorm = 90, + RGB10A2Uint = 91, + RG11B10Float = 92, + RGB9E5Float = 93, + BGR10A2Unorm = 94, + BGR10_XR = 554, + BGR10_XR_sRGB = 555, + RG32Uint = 103, + RG32Sint = 104, + RG32Float = 105, + RGBA16Unorm = 110, + RGBA16Snorm = 112, + RGBA16Uint = 113, + RGBA16Sint = 114, + RGBA16Float = 115, + BGRA10_XR = 552, + BGRA10_XR_sRGB = 553, + RGBA32Uint = 123, + RGBA32Sint = 124, + RGBA32Float = 125, + BC1_RGBA = 130, + BC1_RGBA_sRGB = 131, + BC2_RGBA = 132, + BC2_RGBA_sRGB = 133, + BC3_RGBA = 134, + BC3_RGBA_sRGB = 135, + BC4_RUnorm = 140, + BC4_RSnorm = 141, + BC5_RGUnorm = 142, + BC5_RGSnorm = 143, + BC6H_RGBFloat = 150, + BC6H_RGBUfloat = 151, + BC7_RGBAUnorm = 152, + BC7_RGBAUnorm_sRGB = 153, + PVRTC_RGB_2BPP = 160, + PVRTC_RGB_2BPP_sRGB = 161, + PVRTC_RGB_4BPP = 162, + PVRTC_RGB_4BPP_sRGB = 163, + PVRTC_RGBA_2BPP = 164, + PVRTC_RGBA_2BPP_sRGB = 165, + PVRTC_RGBA_4BPP = 166, + PVRTC_RGBA_4BPP_sRGB = 167, + EAC_R11Unorm = 170, + EAC_R11Snorm = 172, + EAC_RG11Unorm = 174, + EAC_RG11Snorm = 176, + EAC_RGBA8 = 178, + EAC_RGBA8_sRGB = 179, + ETC2_RGB8 = 180, + ETC2_RGB8_sRGB = 181, + ETC2_RGB8A1 = 182, + ETC2_RGB8A1_sRGB = 183, + ASTC_4x4_sRGB = 186, + ASTC_5x4_sRGB = 187, + ASTC_5x5_sRGB = 188, + ASTC_6x5_sRGB = 189, + ASTC_6x6_sRGB = 190, + ASTC_8x5_sRGB = 192, + ASTC_8x6_sRGB = 193, + ASTC_8x8_sRGB = 194, + ASTC_10x5_sRGB = 195, + ASTC_10x6_sRGB = 196, + ASTC_10x8_sRGB = 197, + ASTC_10x10_sRGB = 198, + ASTC_12x10_sRGB = 199, + ASTC_12x12_sRGB = 200, + ASTC_4x4_LDR = 204, + ASTC_5x4_LDR = 205, + ASTC_5x5_LDR = 206, + ASTC_6x5_LDR = 207, + ASTC_6x6_LDR = 208, + ASTC_8x5_LDR = 210, + ASTC_8x6_LDR = 211, + ASTC_8x8_LDR = 212, + ASTC_10x5_LDR = 213, + ASTC_10x6_LDR = 214, + ASTC_10x8_LDR = 215, + ASTC_10x10_LDR = 216, + ASTC_12x10_LDR = 217, + ASTC_12x12_LDR = 218, + ASTC_4x4_HDR = 222, + ASTC_5x4_HDR = 223, + ASTC_5x5_HDR = 224, + ASTC_6x5_HDR = 225, + ASTC_6x6_HDR = 226, + ASTC_8x5_HDR = 228, + ASTC_8x6_HDR = 229, + ASTC_8x8_HDR = 230, + ASTC_10x5_HDR = 231, + ASTC_10x6_HDR = 232, + ASTC_10x8_HDR = 233, + ASTC_10x10_HDR = 234, + ASTC_12x10_HDR = 235, + ASTC_12x12_HDR = 236, + GBGR422 = 240, + BGRG422 = 241, + Depth16Unorm = 250, + Depth32Float = 252, + Stencil8 = 253, + Depth24Unorm_Stencil8 = 255, + Depth32Float_Stencil8 = 260, + X32_Stencil8 = 261, + X24_Stencil8 = 262, +}; + } // namespace dxmt::air \ No newline at end of file diff --git a/src/airconv/airconv_public.h b/src/airconv/airconv_public.h index 5bb84f8c1..15b51c1f1 100644 --- a/src/airconv/airconv_public.h +++ b/src/airconv/airconv_public.h @@ -243,6 +243,8 @@ struct SM50_SHADER_PSO_PIXEL_SHADER_DATA { bool dual_source_blending; bool disable_depth_output; uint32_t unorm_output_reg_mask; + /** MTLPixelFormat */ + uint32_t pixel_formats[8]; }; struct SM50_IA_INPUT_ELEMENT { diff --git a/src/airconv/dxbc_converter.cpp b/src/airconv/dxbc_converter.cpp index c1a0f7901..02b3a4cf1 100644 --- a/src/airconv/dxbc_converter.cpp +++ b/src/airconv/dxbc_converter.cpp @@ -234,6 +234,87 @@ void setup_metal_version(llvm::Module &module, SM50_SHADER_METAL_VERSION metal_v } } +RegisterComponentType +component_type_from_pixel_format(air::MTLPixelFormat format) { + switch (format) { + case air::MTLPixelFormat::R8Sint: + case air::MTLPixelFormat::R16Sint: + case air::MTLPixelFormat::RG8Sint: + case air::MTLPixelFormat::R32Sint: + case air::MTLPixelFormat::RG16Sint: + case air::MTLPixelFormat::RGBA8Sint: + case air::MTLPixelFormat::RG32Sint: + case air::MTLPixelFormat::RGBA16Sint: + case air::MTLPixelFormat::RGBA32Sint: + return RegisterComponentType::Int; + case air::MTLPixelFormat::R8Uint: + case air::MTLPixelFormat::R16Uint: + case air::MTLPixelFormat::RG8Uint: + case air::MTLPixelFormat::R32Uint: + case air::MTLPixelFormat::RG16Uint: + case air::MTLPixelFormat::RGBA8Uint: + case air::MTLPixelFormat::RGB10A2Uint: + case air::MTLPixelFormat::RG32Uint: + case air::MTLPixelFormat::RGBA16Uint: + case air::MTLPixelFormat::RGBA32Uint: + return RegisterComponentType::Uint; + case air::MTLPixelFormat::A8Unorm: + case air::MTLPixelFormat::R8Unorm: + case air::MTLPixelFormat::R8Unorm_sRGB: + case air::MTLPixelFormat::R8Snorm: + case air::MTLPixelFormat::R16Unorm: + case air::MTLPixelFormat::R16Snorm: + case air::MTLPixelFormat::R16Float: + case air::MTLPixelFormat::RG8Unorm: + case air::MTLPixelFormat::RG8Unorm_sRGB: + case air::MTLPixelFormat::RG8Snorm: + case air::MTLPixelFormat::B5G6R5Unorm: + case air::MTLPixelFormat::A1BGR5Unorm: + case air::MTLPixelFormat::ABGR4Unorm: + case air::MTLPixelFormat::BGR5A1Unorm: + case air::MTLPixelFormat::R32Float: + case air::MTLPixelFormat::RG16Unorm: + case air::MTLPixelFormat::RG16Snorm: + case air::MTLPixelFormat::RG16Float: + case air::MTLPixelFormat::RGBA8Unorm: + case air::MTLPixelFormat::RGBA8Unorm_sRGB: + case air::MTLPixelFormat::RGBA8Snorm: + case air::MTLPixelFormat::BGRA8Unorm: + case air::MTLPixelFormat::BGRA8Unorm_sRGB: + case air::MTLPixelFormat::RGB10A2Unorm: + case air::MTLPixelFormat::RG11B10Float: + case air::MTLPixelFormat::RGB9E5Float: + case air::MTLPixelFormat::BGR10A2Unorm: + case air::MTLPixelFormat::BGR10_XR: + case air::MTLPixelFormat::BGR10_XR_sRGB: + case air::MTLPixelFormat::RG32Float: + case air::MTLPixelFormat::RGBA16Unorm: + case air::MTLPixelFormat::RGBA16Snorm: + case air::MTLPixelFormat::RGBA16Float: + case air::MTLPixelFormat::BGRA10_XR: + case air::MTLPixelFormat::BGRA10_XR_sRGB: + case air::MTLPixelFormat::RGBA32Float: + case air::MTLPixelFormat::BC1_RGBA: + case air::MTLPixelFormat::BC1_RGBA_sRGB: + case air::MTLPixelFormat::BC2_RGBA: + case air::MTLPixelFormat::BC2_RGBA_sRGB: + case air::MTLPixelFormat::BC3_RGBA: + case air::MTLPixelFormat::BC3_RGBA_sRGB: + case air::MTLPixelFormat::BC4_RUnorm: + case air::MTLPixelFormat::BC4_RSnorm: + case air::MTLPixelFormat::BC5_RGUnorm: + case air::MTLPixelFormat::BC5_RGSnorm: + case air::MTLPixelFormat::BC6H_RGBFloat: + case air::MTLPixelFormat::BC6H_RGBUfloat: + case air::MTLPixelFormat::BC7_RGBAUnorm: + case air::MTLPixelFormat::BC7_RGBAUnorm_sRGB: + return RegisterComponentType::Float; + default: + break; + } + return RegisterComponentType::Unknown; +} + llvm::Error convert_dxbc_pixel_shader( SM50ShaderInternal *pShaderInternal, const char *name, llvm::LLVMContext &context, llvm::Module &module, @@ -250,12 +331,14 @@ llvm::Error convert_dxbc_pixel_shader( bool pso_dual_source_blending = false; bool pso_disable_depth_output = false; uint32_t pso_unorm_output_reg_mask = 0; + uint32_t *pso_pixel_formats = nullptr; SM50_SHADER_PSO_PIXEL_SHADER_DATA *pso_data = nullptr; if (args_get_data(pArgs, &pso_data)) { pso_dual_source_blending = pso_data->dual_source_blending; pso_disable_depth_output = pso_data->disable_depth_output; pso_unorm_output_reg_mask = pso_data->unorm_output_reg_mask; pso_sample_mask = pso_data->sample_mask; + pso_pixel_formats = pso_data->pixel_formats; } SM50_SHADER_METAL_VERSION metal_version = SM50_SHADER_METAL_310; SM50_SHADER_FLAG shader_flags = {}; @@ -285,6 +368,8 @@ llvm::Error convert_dxbc_pixel_shader( sig_ctx.disable_depth_output = pso_disable_depth_output; sig_ctx.pull_mode_reg_mask = shader_info->pull_mode_reg_mask; sig_ctx.unorm_output_reg_mask = pso_unorm_output_reg_mask; + if (pso_pixel_formats) + memcpy(sig_ctx.pixel_formats, pso_pixel_formats, sizeof(sig_ctx.pixel_formats)); for (auto &p : pShaderInternal->signature_handlers) { p(sig_ctx); } diff --git a/src/airconv/dxbc_converter.hpp b/src/airconv/dxbc_converter.hpp index 7dc026806..d9872b3e5 100644 --- a/src/airconv/dxbc_converter.hpp +++ b/src/airconv/dxbc_converter.hpp @@ -331,15 +331,28 @@ struct SignatureContext { bool skip_vertex_output; uint32_t pull_mode_reg_mask; uint32_t unorm_output_reg_mask; + // it is considered optional (as a hint) + air::MTLPixelFormat pixel_formats[8]; SignatureContext( - IREffect &prologue, IRValue &epilogue, air::FunctionSignatureBuilder &func_signature, io_binding_map &resource - ) - : prologue(prologue), epilogue(epilogue), func_signature(func_signature), resource(resource), ia_layout(nullptr), - dual_source_blending(false), disable_depth_output(false), skip_vertex_output(false), pull_mode_reg_mask(0), - unorm_output_reg_mask(0){}; + IREffect &prologue, IRValue &epilogue, air::FunctionSignatureBuilder &func_signature, io_binding_map &resource + ) : + prologue(prologue), + epilogue(epilogue), + func_signature(func_signature), + resource(resource), + ia_layout(nullptr), + dual_source_blending(false), + disable_depth_output(false), + skip_vertex_output(false), + pull_mode_reg_mask(0), + unorm_output_reg_mask(0) { + memset(pixel_formats, 0, sizeof(pixel_formats)); + }; }; +RegisterComponentType component_type_from_pixel_format(air::MTLPixelFormat format); + struct MeshOutputContext { llvm::Value *vertex_id; llvm::Value *primitive_id; diff --git a/src/airconv/dxbc_signature.cpp b/src/airconv/dxbc_signature.cpp index a568cbfaf..a64f84009 100644 --- a/src/airconv/dxbc_signature.cpp +++ b/src/airconv/dxbc_signature.cpp @@ -600,8 +600,11 @@ void handle_signature_ps( max_output_register = std::max(reg + 1, max_output_register); pso_valid_output_reg_mask |= (1 << reg); if (sig.mask() == 0) break; - auto type = sig.componentType(); + auto sig_type = sig.componentType(); signature_handlers.push_back([=](SignatureContext &ctx) { + auto type = component_type_from_pixel_format(ctx.pixel_formats[reg]); + if (ctx.dual_source_blending || type == RegisterComponentType::Unknown) + type = sig_type; uint32_t assigned_index; if (ctx.dual_source_blending) { if (reg > 1 || reg < 0) diff --git a/src/d3d11/d3d11_shader.cpp b/src/d3d11/d3d11_shader.cpp index 687b94a93..5b7b742e3 100644 --- a/src/d3d11/d3d11_shader.cpp +++ b/src/d3d11/d3d11_shader.cpp @@ -183,6 +183,7 @@ CreateVariantShader(MTLD3D11Device *pDevice, ManagedShader shader, data.dual_source_blending = variant.dual_source_blending; data.disable_depth_output = variant.disable_depth_output; data.unorm_output_reg_mask = variant.unorm_output_reg_mask; + memset(data.pixel_formats, 0, sizeof(data.pixel_formats)); sm50_bitcode_t compile_result = nullptr; sm50_error_t sm50_err = nullptr; diff --git a/src/d3d12/d3d12_buffer.cpp b/src/d3d12/d3d12_buffer.cpp index f31879376..11ea27dfd 100644 --- a/src/d3d12/d3d12_buffer.cpp +++ b/src/d3d12/d3d12_buffer.cpp @@ -34,7 +34,7 @@ class MTLD3D12Buffer : public MTLD3D12Pageable { HRESULT Initialize( const D3D12_HEAP_PROPERTIES *pHeapProps, D3D12_HEAP_FLAGS HeapFlags, const D3D12_RESOURCE_DESC *pDesc, - const D3D12_CLEAR_VALUE *OptimizedClearValue, MTLD3D12Heap *pHeap + const D3D12_CLEAR_VALUE *OptimizedClearValue, MTLD3D12Heap *pHeap, UINT64 Offset ) { if (OptimizedClearValue) return E_INVALIDARG; @@ -249,7 +249,7 @@ CreateCommittedBuffer( REFIID riid, void **ppResource ) { auto buffer = Com(new MTLD3D12Buffer(pDevice)); - HRESULT hr = buffer->Initialize(pHeapProps, HeapFlags, pDesc, OptimizedClearValue, nullptr); + HRESULT hr = buffer->Initialize(pHeapProps, HeapFlags, pDesc, OptimizedClearValue, nullptr, 0); if (FAILED(hr)) return hr; if (!ppResource) @@ -259,12 +259,12 @@ CreateCommittedBuffer( HRESULT CreatePlacedBuffer( - MTLD3D12Device *pDevice, MTLD3D12Heap *pHeap, const D3D12_RESOURCE_DESC *pDesc, D3D12_RESOURCE_STATES InitialState, - const D3D12_CLEAR_VALUE *OptimizedClearValue, REFIID riid, void **ppResource + MTLD3D12Device *pDevice, MTLD3D12Heap *pHeap, UINT64 Offset, const D3D12_RESOURCE_DESC *pDesc, + D3D12_RESOURCE_STATES InitialState, const D3D12_CLEAR_VALUE *OptimizedClearValue, REFIID riid, void **ppResource ) { auto buffer = Com(new MTLD3D12Buffer(pDevice)); D3D12_HEAP_DESC heap_desc = pHeap->GetDesc(); - HRESULT hr = buffer->Initialize(&heap_desc.Properties, heap_desc.Flags, pDesc, OptimizedClearValue, pHeap); + HRESULT hr = buffer->Initialize(&heap_desc.Properties, heap_desc.Flags, pDesc, OptimizedClearValue, pHeap, Offset); if (FAILED(hr)) return hr; if (!ppResource) diff --git a/src/d3d12/d3d12_command_allocator.cpp b/src/d3d12/d3d12_command_allocator.cpp index c7b47e1ee..0effda51b 100644 --- a/src/d3d12/d3d12_command_allocator.cpp +++ b/src/d3d12/d3d12_command_allocator.cpp @@ -24,7 +24,11 @@ namespace dxmt { MTLD3D12CommandAllocatorImpl::MTLD3D12CommandAllocatorImpl(MTLD3D12Device *pDevice, D3D12_COMMAND_LIST_TYPE Type) : MTLD3D12Pageable(pDevice), type_(Type), - clear_uav_(device_->GetMTLDevice(), *this) {} + clear_uav_(device_->GetMTLDevice(), *this), + copy_temp_allocator_( + {device_->GetMTLDevice(), WMTResourceHazardTrackingModeUntracked | WMTResourceStorageModePrivate} + ), + copy_temp_version_(0) {} HRESULT CreateCommandAllocator(MTLD3D12Device *pDevice, D3D12_COMMAND_LIST_TYPE Type, REFIID riid, void **ppCommandAllocator) { @@ -77,6 +81,8 @@ MTLD3D12CommandAllocatorImpl::Initialize() { icb_.clear(); + copy_temp_allocator_.free_blocks(copy_temp_version_++); + return S_OK; } diff --git a/src/d3d12/d3d12_command_allocator.hpp b/src/d3d12/d3d12_command_allocator.hpp index 0b0a8d065..acf5262c3 100644 --- a/src/d3d12/d3d12_command_allocator.hpp +++ b/src/d3d12/d3d12_command_allocator.hpp @@ -20,6 +20,7 @@ #include "d3d12_pageable.hpp" #include "dxmt_command_clear.hpp" +#include "dxmt_ring_bump_allocator.hpp" namespace dxmt { @@ -90,6 +91,9 @@ class MTLD3D12CommandAllocatorImpl : public MTLD3D12Pageable clear_uav_; + RingBumpState copy_temp_allocator_; + uint64_t copy_temp_version_; + public: MTLD3D12CommandAllocatorImpl(MTLD3D12Device *pDevice, D3D12_COMMAND_LIST_TYPE Type); @@ -216,6 +220,13 @@ class MTLD3D12CommandAllocatorImpl : public MTLD3D12Pageable + AllocateTempBuffer(size_t Size, size_t Alignment) { + assert(copy_temp_version_); + auto [block, offset] = copy_temp_allocator_.allocate(copy_temp_version_, copy_temp_version_ - 1, Size, Alignment); + return {block.buffer, offset}; + } + IndirectComputeCommandData *EncodeIndirectComputeCommand(MTLD3D12CommandSignature *pCmdSig, MTLD3D12ComputePipelineState *pPSO, size_t MaxCount); IndirectRenderCommandData *EncodeIndirectRenderCommand(MTLD3D12CommandSignature *pCmdSig, MTLD3D12GraphicsPipelineState *pPSO, size_t MaxCount); diff --git a/src/d3d12/d3d12_command_encoder.hpp b/src/d3d12/d3d12_command_encoder.hpp index a579dcdd8..1caf3bcdf 100644 --- a/src/d3d12/d3d12_command_encoder.hpp +++ b/src/d3d12/d3d12_command_encoder.hpp @@ -48,6 +48,7 @@ struct ClearEncoderData : EncoderData { unsigned array_length; unsigned width; unsigned height; + unsigned depth_plane; ClearEncoderData() {} }; diff --git a/src/d3d12/d3d12_command_list.cpp b/src/d3d12/d3d12_command_list.cpp index 1d3642a9f..99eb607cc 100644 --- a/src/d3d12/d3d12_command_list.cpp +++ b/src/d3d12/d3d12_command_list.cpp @@ -106,9 +106,6 @@ to_metal_primitive_type(D3D12_PRIMITIVE_TOPOLOGY topo, WMTPrimitiveType &primiti return true; } -/* FIXME: it's not *public* */ -unsigned getPlanarCount(WMTPixelFormat format); - // `Graphics`CommandList is a really confusing name class MTLD3D12GraphicsCommandListImpl : public MTLD3D12DeviceChild { @@ -217,7 +214,8 @@ class MTLD3D12GraphicsCommandListImpl : public MTLD3D12DeviceChilddepth; rt.attachment = AttachmentDesc.Texture->view(AttachmentDesc.View); - rt.depth_plane = 0; + rt.depth_plane = 0; // DSV cannot be 3D rt.load_action = WMTLoadActionLoad; rt.store_action = WMTStoreActionStore; } if (dsv_planar_flags & 2) { auto &rt = render->stencil; rt.attachment = AttachmentDesc.Texture->view(AttachmentDesc.View); - rt.depth_plane = AttachmentDesc.DepthPlane; + rt.depth_plane = 0; // DSV cannot be 3D rt.load_action = WMTLoadActionLoad; rt.store_action = WMTStoreActionStore; } @@ -620,101 +618,190 @@ class MTLD3D12GraphicsCommandListImpl : public MTLD3D12DeviceChildpResource->GetDesc(); + auto dst_desc = pDst->pResource->GetDesc(); + uint32_t src_level = 0, src_slice = 0, src_planar = 0; + uint32_t dst_level = 0, dst_slice = 0, dst_planar = 0; + D3D12_BOX src_box, full_src_box; + + if (pSrc->Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT) { + full_src_box = { + 0, 0, 0, + pSrc->PlacedFootprint.Footprint.Width, + pSrc->PlacedFootprint.Footprint.Height, + pSrc->PlacedFootprint.Footprint.Depth + }; + } else { + DecomposeSubresource(src_desc, pSrc->SubresourceIndex, &src_level, &src_slice, &src_planar); + full_src_box = GetResourceExtent(src_desc, src_level); + } + src_box = pSrcBox ? *pSrcBox : full_src_box; + + // discard invalid & empty box + if (src_box.left >= src_box.right || src_box.front >= src_box.back || src_box.top >= src_box.bottom) + return; + if (pDst->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX) { auto &dst = static_cast(pDst->pResource)->texture; if (!dst) return; - auto dst_planar_count = getPlanarCount(dst->pixelFormat()); - auto dst_subresource_index = pDst->SubresourceIndex / dst_planar_count; - auto dst_subresource_planar = pDst->SubresourceIndex % dst_planar_count; + DecomposeSubresource(dst_desc, pDst->SubresourceIndex, &dst_level, &dst_slice, &dst_planar); + + MTL_DXGI_FORMAT_DESC dst_format; + if (FAILED(MTLQueryDXGIFormat(device_->GetMTLDevice(), dst_desc.Format, dst_format))) { + WARN("CopyTextureRegion: unsupported format ", dst_desc.Format); + return; + } + auto dst_planar_count = dst_format.PlanarCount; if (pSrc->Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT) { auto &src = static_cast(pSrc->pResource)->buffer; if (!src) return; - if (pSrcBox) - IMPLEMENT_ME + + MTL_DXGI_FORMAT_DESC src_format; + if (FAILED(MTLQueryDXGIFormat(device_->GetMTLDevice(), pSrc->PlacedFootprint.Footprint.Format, src_format))) { + WARN("CopyTextureRegion: unsupported format ", pSrc->PlacedFootprint.Footprint.Format); + return; + } + + auto block_width = src_format.Flag & MTL_DXGI_FORMAT_BC ? 4 : 1; + auto src_depth_pitch = dst->textureType() == WMTTextureType3D + ? (pSrc->PlacedFootprint.Footprint.Height / block_width) * pSrc->PlacedFootprint.Footprint.RowPitch + : 0; auto &cmd_cp = allocator_->EncodeBlitCommand(); cmd_cp.type = WMTBlitCommandCopyFromBufferToTextureWithBlitOption; cmd_cp.src = src->current()->buffer(); - cmd_cp.src_offset = pSrc->PlacedFootprint.Offset; + cmd_cp.src_offset = pSrc->PlacedFootprint.Offset + (src_box.left / block_width) * src_format.BytesPerTexel + + (src_box.top / block_width) * pSrc->PlacedFootprint.Footprint.RowPitch + src_box.front * src_depth_pitch; cmd_cp.bytes_per_row = pSrc->PlacedFootprint.Footprint.RowPitch; - cmd_cp.bytes_per_image = dst->textureType() == WMTTextureType3D - ? pSrc->PlacedFootprint.Footprint.Height * pSrc->PlacedFootprint.Footprint.RowPitch - : 0; - cmd_cp.size = { - pSrc->PlacedFootprint.Footprint.Width, pSrc->PlacedFootprint.Footprint.Height, - pSrc->PlacedFootprint.Footprint.Depth - }; + cmd_cp.bytes_per_image = src_depth_pitch; + cmd_cp.size = {src_box.right - src_box.left, src_box.bottom - src_box.top, src_box.back - src_box.front}; cmd_cp.dst = dst->current()->texture(); - cmd_cp.level = dst_subresource_index % dst->miplevelCount(); - cmd_cp.slice = dst_subresource_index / dst->miplevelCount(); - cmd_cp.options = (dst_planar_count > 1) ? (dst_subresource_planar ? WMTBlitOptionStencilFromDepthStencil - : WMTBlitOptionDepthFromDepthStencil) - : WMTBlitOptionNone; + cmd_cp.level = dst_level; + cmd_cp.slice = dst_slice; + cmd_cp.options = (dst_planar_count > 1) + ? (dst_planar ? WMTBlitOptionStencilFromDepthStencil : WMTBlitOptionDepthFromDepthStencil) + : WMTBlitOptionNone; cmd_cp.origin = {DstX, DstY, DstZ}; } else { auto &src = static_cast(pSrc->pResource)->texture; if (!src) return; - auto src_planar_count = getPlanarCount(src->pixelFormat()); - if (!pSrcBox) - IMPLEMENT_ME + + MTL_DXGI_FORMAT_DESC src_format; + if (FAILED(MTLQueryDXGIFormat(device_->GetMTLDevice(), src_desc.Format, src_format))) { + WARN("CopyTextureRegion: unsupported format ", src_desc.Format); + return; + } + auto src_planar_count = src_format.PlanarCount; // copy between depth-stencil texture is tricky - if (dst_planar_count > 1 || src_planar_count > 1) - IMPLEMENT_ME + if (dst_planar_count > 1 || src_planar_count > 1) { + // in this path, one/both of dst/src would be depth-stencil texture + + if (dst_planar_count > 1 && src_planar_count > 1 && dst_planar != src_planar) { + WARN("CopyTextureRegion: unmatched planar"); // just in case + return; + } + + auto texel_size = (dst_planar == 1 || src_planar == 1) ? 1 : 4; + auto width = src_box.right - src_box.left; + auto height = src_box.bottom - src_box.top; + auto bytes_per_row = align(width * texel_size, 256); + auto bytes_per_image = bytes_per_row * height; + + auto [temp_buffer, temp_buffer_offset] = allocator_->AllocateTempBuffer(bytes_per_image, 256); + + auto &cmd_to_tmp = allocator_->EncodeBlitCommand(); + cmd_to_tmp.type = WMTBlitCommandCopyFromTextureToBufferWithBlitOption; + cmd_to_tmp.src = src->current()->texture(); + cmd_to_tmp.level = src_level; + cmd_to_tmp.slice = src_slice; + cmd_to_tmp.origin = {src_box.left, src_box.top, src_box.front}; + cmd_to_tmp.size = {width, height, src_box.back - src_box.front}; + cmd_to_tmp.dst = temp_buffer; + cmd_to_tmp.offset = temp_buffer_offset; + cmd_to_tmp.bytes_per_image = 0; // DSV cannot be 3D + cmd_to_tmp.bytes_per_row = bytes_per_row; + cmd_to_tmp.options = (src_planar_count > 1) ? (src_planar ? WMTBlitOptionStencilFromDepthStencil + : WMTBlitOptionDepthFromDepthStencil) + : WMTBlitOptionNone; + + auto &cmd_to_tex = allocator_->EncodeBlitCommand(); + cmd_to_tex.type = WMTBlitCommandCopyFromBufferToTextureWithBlitOption; + cmd_to_tex.src = temp_buffer; + cmd_to_tex.src_offset = temp_buffer_offset; + cmd_to_tex.bytes_per_image = 0; // DSV cannot be 3D + cmd_to_tex.bytes_per_row = bytes_per_row; + cmd_to_tex.dst = dst->current()->texture(); + cmd_to_tex.level = dst_level; + cmd_to_tex.slice = dst_slice; + cmd_to_tex.origin = {DstX, DstY, DstZ}; + cmd_to_tex.size = {src_box.right - src_box.left, src_box.bottom - src_box.top, src_box.back - src_box.front}; + cmd_to_tex.options = (dst_planar_count > 1) ? (dst_planar ? WMTBlitOptionStencilFromDepthStencil + : WMTBlitOptionDepthFromDepthStencil) + : WMTBlitOptionNone; + return; + } auto &cmd_cp = allocator_->EncodeBlitCommand(); cmd_cp.type = WMTBlitCommandCopyFromTextureToTexture; cmd_cp.src = src->current()->texture(); - cmd_cp.src_level = pSrc->SubresourceIndex % src->miplevelCount(); - cmd_cp.src_slice = pSrc->SubresourceIndex / src->miplevelCount(); - cmd_cp.src_origin = {pSrcBox->left, pSrcBox->top, pSrcBox->front}; - cmd_cp.src_size = { - pSrcBox->right - pSrcBox->left, pSrcBox->bottom - pSrcBox->top, pSrcBox->back - pSrcBox->front - }; + cmd_cp.src_level = src_level; + cmd_cp.src_slice = src_slice; + cmd_cp.src_origin = {src_box.left, src_box.top, src_box.front}; + cmd_cp.src_size = {src_box.right - src_box.left, src_box.bottom - src_box.top, src_box.back - src_box.front}; cmd_cp.dst = dst->current()->texture(); - cmd_cp.dst_level = pDst->SubresourceIndex % dst->miplevelCount(); - cmd_cp.dst_slice = pDst->SubresourceIndex / dst->miplevelCount(); + cmd_cp.dst_level = dst_level; + cmd_cp.dst_slice = dst_slice; cmd_cp.dst_origin = {DstX, DstY, DstZ}; } } else if (pDst->Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT) { auto &dst = static_cast(pDst->pResource)->buffer; if (!dst) return; - if (pSrcBox) - IMPLEMENT_ME + + MTL_DXGI_FORMAT_DESC dst_format; + if (FAILED(MTLQueryDXGIFormat(device_->GetMTLDevice(), pDst->PlacedFootprint.Footprint.Format, dst_format))) { + WARN("CopyTextureRegion: unsupported format ", pDst->PlacedFootprint.Footprint.Format); + return; + } + if (pSrc->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX) { auto &src = static_cast(pSrc->pResource)->texture; if (!src) return; - auto src_planar_count = getPlanarCount(src->pixelFormat()); - auto src_subresource_index = pSrc->SubresourceIndex / src_planar_count; - auto src_subresource_planar = pSrc->SubresourceIndex % src_planar_count; + MTL_DXGI_FORMAT_DESC src_format; + if (FAILED(MTLQueryDXGIFormat(device_->GetMTLDevice(), src_desc.Format, src_format))) { + WARN("CopyTextureRegion: unsupported format ", src_desc.Format); + return; + } + auto src_planar_count = src_format.PlanarCount; + + auto block_width = dst_format.Flag & MTL_DXGI_FORMAT_BC ? 4 : 1; + auto dst_depth_pitch = src->textureType() == WMTTextureType3D + ? (pDst->PlacedFootprint.Footprint.Height / block_width) * pDst->PlacedFootprint.Footprint.RowPitch + : 0; auto &cmd_cp = allocator_->EncodeBlitCommand(); cmd_cp.type = WMTBlitCommandCopyFromTextureToBufferWithBlitOption; cmd_cp.src = src->current()->texture(); - cmd_cp.level = src_subresource_index % src->miplevelCount(); - cmd_cp.slice = src_subresource_index / src->miplevelCount(); - cmd_cp.origin = {0, 0, 0}; - cmd_cp.size = { - pDst->PlacedFootprint.Footprint.Width, pDst->PlacedFootprint.Footprint.Height, - pDst->PlacedFootprint.Footprint.Depth - }; + cmd_cp.level = src_level; + cmd_cp.slice = src_slice; + cmd_cp.origin = {src_box.left, src_box.top, src_box.front}; + cmd_cp.size = {src_box.right - src_box.left, src_box.bottom - src_box.top, src_box.back - src_box.front}; cmd_cp.dst = dst->current()->buffer(); - cmd_cp.offset = pDst->PlacedFootprint.Offset; + cmd_cp.offset = pDst->PlacedFootprint.Offset + (DstX / block_width) * dst_format.BytesPerTexel + + (DstY / block_width) * pDst->PlacedFootprint.Footprint.RowPitch + DstZ * dst_depth_pitch; cmd_cp.bytes_per_row = pDst->PlacedFootprint.Footprint.RowPitch; - cmd_cp.bytes_per_image = src->textureType() == WMTTextureType3D - ? pDst->PlacedFootprint.Footprint.Height * pDst->PlacedFootprint.Footprint.RowPitch - : 0; - cmd_cp.options = (src_planar_count > 1) ? (src_subresource_planar ? WMTBlitOptionStencilFromDepthStencil - : WMTBlitOptionDepthFromDepthStencil) - : WMTBlitOptionNone; + cmd_cp.bytes_per_image = dst_depth_pitch; + cmd_cp.options = (src_planar_count > 1) + ? (src_planar ? WMTBlitOptionStencilFromDepthStencil : WMTBlitOptionDepthFromDepthStencil) + : WMTBlitOptionNone; } else { // so it is buffer to buffer copy? IMPLEMENT_ME @@ -748,7 +835,16 @@ class MTLD3D12GraphicsCommandListImpl : public MTLD3D12DeviceChildtexture->pixelFormat() != pSrc->texture->pixelFormat()) { + WARN("CopyResource: TODO: reinterpret copy"); + return; + } + + auto &cmd_cp = allocator_->EncodeBlitCommand(); + cmd_cp.type = WMTBlitCommandCopyTexture; + cmd_cp.src = pSrc->texture->current()->texture(); + cmd_cp.dst = pDst->texture->current()->texture(); }; void STDMETHODCALLTYPE CopyTiles( @@ -866,7 +962,7 @@ class MTLD3D12GraphicsCommandListImpl : public MTLD3D12DeviceChildEncodeRenderCommand(); cmd_setdsso.type = WMTRenderCommandSetDSSO; cmd_setdsso.dsso = pso_graphics->dsso; - cmd_setdsso.stencil_ref = 0; /* FIXME */ + cmd_setdsso.stencil_ref = stencil_ref_; auto &cmd_setrs = allocator_->EncodeRenderCommand(); cmd_setrs.type = WMTRenderCommandSetRasterizerState; @@ -1146,6 +1242,7 @@ class MTLD3D12GraphicsCommandListImpl : public MTLD3D12DeviceChildarray_length = AttachmentDesc.RenderTargetArrayLength; encoder_info->width = AttachmentDesc.Width; encoder_info->height = AttachmentDesc.Height; + encoder_info->depth_plane = 0; allocator_->InvalidateCurrentPass(); }; @@ -1172,6 +1269,7 @@ class MTLD3D12GraphicsCommandListImpl : public MTLD3D12DeviceChildarray_length = AttachmentDesc.RenderTargetArrayLength; encoder_info->width = AttachmentDesc.Width; encoder_info->height = AttachmentDesc.Height; + encoder_info->depth_plane = AttachmentDesc.DepthPlane; allocator_->InvalidateCurrentPass(); }; @@ -1378,6 +1476,52 @@ class MTLD3D12GraphicsCommandListImpl : public MTLD3D12DeviceChildvertex_buffer = allocator_->gpu_heap_buffer_address_ + VBOffset; cmd->vertex_argbuf_stride = VBStride; }; + + void STDMETHODCALLTYPE + AtomicCopyBufferUINT( + ID3D12Resource *pDstBuffer, UINT64 DstOffset, ID3D12Resource *pSrcBuffer, UINT64 SrcOffset, UINT Dependencies, + ID3D12Resource *const *ppDependentResources, const D3D12_SUBRESOURCE_RANGE_UINT64 *pDependentSubresourceRanges + ) { + IMPLEMENT_ME + } + + void STDMETHODCALLTYPE + AtomicCopyBufferUINT64( + ID3D12Resource *pDstBuffer, UINT64 DstOffset, ID3D12Resource *pSrcBuffer, UINT64 SrcOffset, UINT Dependencies, + ID3D12Resource *const *ppDependentResources, const D3D12_SUBRESOURCE_RANGE_UINT64 *pDependentSubresourceRanges + ) { + IMPLEMENT_ME + } + + void STDMETHODCALLTYPE + OMSetDepthBounds(FLOAT Min, FLOAT Max) { + WARN("OMSetDepthBounds: ignoring (", Min, ", ", Max, ")"); + } + + void STDMETHODCALLTYPE + SetSamplePositions(UINT NumSamplesPerPixel, UINT NumPixels, D3D12_SAMPLE_POSITION *pSamplePositions) { + IMPLEMENT_ME + } + + void STDMETHODCALLTYPE + ResolveSubresourceRegion( + ID3D12Resource *pDstResource, UINT DstSubresource, UINT DstX, UINT DstY, ID3D12Resource *pSrcResource, + UINT SrcSubresource, D3D12_RECT *pSrcRect, DXGI_FORMAT Format, D3D12_RESOLVE_MODE ResolveMode + ) { + IMPLEMENT_ME + } + + void STDMETHODCALLTYPE + SetViewInstanceMask(UINT Mask) { + IMPLEMENT_ME + } + + void STDMETHODCALLTYPE + WriteBufferImmediate( + UINT Count, const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *pParams, const D3D12_WRITEBUFFERIMMEDIATE_MODE *pModes + ) { + IMPLEMENT_ME + } }; HRESULT STDMETHODCALLTYPE diff --git a/src/d3d12/d3d12_command_queue.cpp b/src/d3d12/d3d12_command_queue.cpp index d4553eed1..5cea88676 100644 --- a/src/d3d12/d3d12_command_queue.cpp +++ b/src/d3d12/d3d12_command_queue.cpp @@ -121,12 +121,14 @@ class MTLD3D12CommandQueueImpl : public MTLD3D12Pageableattachment.texture(); info.depth.load_action = WMTLoadActionClear; info.depth.store_action = WMTStoreActionStore; + info.depth.depth_plane = data->depth_plane; } if (data->clear_dsv & 2) { info.stencil.clear_stencil = data->depth_stencil.second; info.stencil.texture = data->attachment.texture(); info.stencil.load_action = WMTLoadActionClear; info.stencil.store_action = WMTStoreActionStore; + info.stencil.depth_plane = data->depth_plane; } info.render_target_width = data->width; info.render_target_height = data->height; @@ -135,6 +137,7 @@ class MTLD3D12CommandQueueImpl : public MTLD3D12Pageableattachment.texture(); info.colors[0].load_action = WMTLoadActionClear; info.colors[0].store_action = WMTStoreActionStore; + info.colors[0].depth_plane = data->depth_plane; } info.render_target_array_length = data->array_length; auto encoder = cmdbuf.renderCommandEncoder(info); diff --git a/src/d3d12/d3d12_device.cpp b/src/d3d12/d3d12_device.cpp index 2f630f067..4ea882725 100644 --- a/src/d3d12/d3d12_device.cpp +++ b/src/d3d12/d3d12_device.cpp @@ -39,6 +39,7 @@ class MTLD3D12DeviceImpl : public MTLD3D12Object> { std::map interval_map_; InternalCommandLibrary command_library; + FormatCapabilityInspector format_inspector_; public: MTLD3D12DeviceImpl(IMTLDXGIAdapter *adapter) : adapter_(adapter), command_library(adapter_->GetMTLDevice()) {} @@ -53,6 +54,7 @@ class MTLD3D12DeviceImpl : public MTLD3D12Object> { ERR("Failed to create MTLResidencySet: ", err.description().getUTF8String()); return E_FAIL; } + format_inspector_.Inspect(GetMTLDevice()); return S_OK; }; @@ -85,7 +87,7 @@ class MTLD3D12DeviceImpl : public MTLD3D12Object> { *ppvObject = nullptr; if (riid == __uuidof(IUnknown) || riid == __uuidof(ID3D12Object) || riid == __uuidof(ID3D12Device) || - riid == __uuidof(ID3D12Device1)) { + riid == __uuidof(ID3D12Device1) || riid == __uuidof(ID3D12Device2) || riid == __uuidof(ID3D12Device3)) { *ppvObject = ref(this); return S_OK; } @@ -551,9 +553,9 @@ class MTLD3D12DeviceImpl : public MTLD3D12Object> { case D3D12_RESOURCE_DIMENSION_TEXTURE1D: case D3D12_RESOURCE_DIMENSION_TEXTURE2D: case D3D12_RESOURCE_DIMENSION_TEXTURE3D: - return CreatePlacedTexture(this, d3d12heap, pDesc, InitialState, OptimizedClearValue, riid, ppResource); + return CreatePlacedTexture(this, d3d12heap, Offset, pDesc, InitialState, OptimizedClearValue, riid, ppResource); case D3D12_RESOURCE_DIMENSION_BUFFER: - return CreatePlacedBuffer(this, d3d12heap, pDesc, InitialState, OptimizedClearValue, riid, ppResource); + return CreatePlacedBuffer(this, d3d12heap, Offset, pDesc, InitialState, OptimizedClearValue, riid, ppResource); default: break; } @@ -587,7 +589,7 @@ class MTLD3D12DeviceImpl : public MTLD3D12Object> { HRESULT STDMETHODCALLTYPE MakeResident(UINT ObjectCount, ID3D12Pageable *const *objects) { - return E_NOTIMPL; + return S_OK; }; HRESULT STDMETHODCALLTYPE @@ -602,7 +604,7 @@ class MTLD3D12DeviceImpl : public MTLD3D12Object> { HRESULT STDMETHODCALLTYPE GetDeviceRemovedReason() { - return E_NOTIMPL; + return S_OK; }; void STDMETHODCALLTYPE GetCopyableFootprints( @@ -750,6 +752,245 @@ class MTLD3D12DeviceImpl : public MTLD3D12Object> { return E_NOTIMPL; }; + HRESULT STDMETHODCALLTYPE + CreatePipelineState(const D3D12_PIPELINE_STATE_STREAM_DESC *pDesc, REFIID riid, void **ppPipelineState) { + const char *stream_start = reinterpret_cast(pDesc->pPipelineStateSubobjectStream); + const char *stream_end = stream_start + pDesc->SizeInBytes; + + D3D12_COMPUTE_PIPELINE_STATE_DESC desc_cs{}; + D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_graphics{}; + { + desc_graphics.DepthStencilState.DepthEnable = TRUE; + desc_graphics.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + desc_graphics.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS; + desc_graphics.DepthStencilState.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS; + desc_graphics.DepthStencilState.FrontFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP; + desc_graphics.DepthStencilState.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP; + desc_graphics.DepthStencilState.FrontFace.StencilFailOp = D3D12_STENCIL_OP_KEEP; + desc_graphics.DepthStencilState.BackFace = desc_graphics.DepthStencilState.FrontFace; + desc_graphics.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + desc_graphics.RasterizerState.CullMode = D3D12_CULL_MODE_BACK; + desc_graphics.RasterizerState.DepthClipEnable = TRUE; + desc_graphics.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; + desc_graphics.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + desc_graphics.SampleDesc.Count = 1; + desc_graphics.SampleDesc.Quality = 0; + desc_graphics.SampleMask = D3D12_DEFAULT_SAMPLE_MASK; + } + + uint32_t defined_type = 0; + + while (stream_start < stream_end) { + if (stream_start + sizeof(D3D12_PIPELINE_STATE_SUBOBJECT_TYPE) > stream_end) { + ERR("CreatePipelineState: invalid stream"); + return E_INVALIDARG; + } + auto type = *reinterpret_cast(stream_start); + + if (defined_type & (1 << type)) { + ERR("CreatePipelineState: duplicated subobejct type ", type); + return E_INVALIDARG; + } + defined_type |= (1 << type); + +#define GET_STREAM_DATA(data_type) \ + using subobject_t = struct { \ + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; \ + data_type data; \ + }; \ + auto subobject = reinterpret_cast(stream_start); \ + if (stream_start + sizeof(*subobject) > stream_end) { \ + ERR("CreatePipelineState: invalid stream"); \ + return E_INVALIDARG; \ + } \ + stream_start += align(sizeof(*subobject), sizeof(void *)); + + switch (type) { + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE: { + GET_STREAM_DATA(ID3D12RootSignature *); + desc_cs.pRootSignature = subobject->data; + desc_graphics.pRootSignature = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS: { + GET_STREAM_DATA(D3D12_SHADER_BYTECODE); + desc_graphics.VS = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS: { + GET_STREAM_DATA(D3D12_SHADER_BYTECODE); + desc_graphics.PS = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS: { + GET_STREAM_DATA(D3D12_SHADER_BYTECODE); + desc_graphics.DS = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS: { + GET_STREAM_DATA(D3D12_SHADER_BYTECODE); + desc_graphics.HS = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS: { + GET_STREAM_DATA(D3D12_SHADER_BYTECODE); + desc_graphics.GS = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS: { + GET_STREAM_DATA(D3D12_SHADER_BYTECODE); + desc_cs.CS = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT: { + GET_STREAM_DATA(D3D12_STREAM_OUTPUT_DESC); + desc_graphics.StreamOutput = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND: { + GET_STREAM_DATA(D3D12_BLEND_DESC); + desc_graphics.BlendState = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK: { + GET_STREAM_DATA(UINT); + desc_graphics.SampleMask = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER: { + GET_STREAM_DATA(D3D12_RASTERIZER_DESC); + desc_graphics.RasterizerState = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL: { + GET_STREAM_DATA(D3D12_DEPTH_STENCIL_DESC); + desc_graphics.DepthStencilState = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT: { + GET_STREAM_DATA(D3D12_INPUT_LAYOUT_DESC); + desc_graphics.InputLayout = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE: { + GET_STREAM_DATA(D3D12_INDEX_BUFFER_STRIP_CUT_VALUE); + desc_graphics.IBStripCutValue = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY: { + GET_STREAM_DATA(D3D12_PRIMITIVE_TOPOLOGY_TYPE); + desc_graphics.PrimitiveTopologyType = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS: { + GET_STREAM_DATA(D3D12_RT_FORMAT_ARRAY); + memcpy(desc_graphics.RTVFormats, subobject->data.RTFormats, sizeof(desc_graphics.RTVFormats)); + desc_graphics.NumRenderTargets = subobject->data.NumRenderTargets; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT: { + GET_STREAM_DATA(DXGI_FORMAT); + desc_graphics.DSVFormat = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC: { + GET_STREAM_DATA(DXGI_SAMPLE_DESC); + desc_graphics.SampleDesc = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK: { + GET_STREAM_DATA(UINT); + desc_graphics.NodeMask = subobject->data; + desc_cs.NodeMask = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO: { + GET_STREAM_DATA(D3D12_CACHED_PIPELINE_STATE); + desc_graphics.CachedPSO = subobject->data; + desc_cs.CachedPSO = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS: { + GET_STREAM_DATA(D3D12_PIPELINE_STATE_FLAGS); + desc_graphics.Flags = subobject->data; + desc_cs.Flags = subobject->data; + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1: { + GET_STREAM_DATA(D3D12_DEPTH_STENCIL_DESC1); + desc_graphics.DepthStencilState.StencilEnable = subobject->data.StencilEnable; + desc_graphics.DepthStencilState.DepthEnable = subobject->data.DepthEnable; + desc_graphics.DepthStencilState.DepthFunc = subobject->data.DepthFunc; + desc_graphics.DepthStencilState.DepthWriteMask = subobject->data.DepthWriteMask; + desc_graphics.DepthStencilState.StencilWriteMask = subobject->data.StencilWriteMask; + desc_graphics.DepthStencilState.BackFace = subobject->data.BackFace; + desc_graphics.DepthStencilState.FrontFace = subobject->data.FrontFace; + if (subobject->data.DepthBoundsTestEnable) { + WARN("CreatePipelineState: ignore DepthBoundsTestEnable"); + } + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING: { + GET_STREAM_DATA(D3D12_VIEW_INSTANCING_DESC); + if (subobject->data.Flags) { + WARN("CreatePipelineState: ignore ViewInstancing"); + } + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS: { + GET_STREAM_DATA(D3D12_SHADER_BYTECODE); + if (subobject->data.pShaderBytecode) { + ERR("CreatePipelineState: unsupported AS"); + return E_NOTIMPL; + } + break; + } + case D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS: { + GET_STREAM_DATA(D3D12_SHADER_BYTECODE); + if (subobject->data.pShaderBytecode) { + ERR("CreatePipelineState: unsupported MS"); + return E_NOTIMPL; + } + break; + } + default: + ERR("CreatePipelineState: unhandled subobject type ", type); + return E_INVALIDARG; + } + } + + if (desc_cs.CS.pShaderBytecode) { + uint32_t incompatible_type = + (1 << D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS | 1 << D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS | + 1 << D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS); + if (defined_type & incompatible_type) { + ERR("CreatePipelineState: invalid compute pipeline state stream"); + return E_INVALIDARG; + } + return CreateComputePipelineState(&desc_cs, riid, ppPipelineState); + } + + return CreateGraphicsPipelineState(&desc_graphics, riid, ppPipelineState); + } + + HRESULT STDMETHODCALLTYPE + OpenExistingHeapFromAddress(const void *pAddress, REFIID riid, void **ppHeap) { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE + OpenExistingHeapFromFileMapping(HANDLE hFileMapping, REFIID riid, void **ppHeap) { + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE + EnqueueMakeResident( + D3D12_RESIDENCY_FLAGS Flags, UINT NumObjects, ID3D12Pageable *const *ppObjects, ID3D12Fence *pFence, + UINT64 FenceValue + ) { + return E_NOTIMPL; + } + WMT::ResidencySet GetGlobalResidencySet() { return residency_set_; @@ -808,6 +1049,14 @@ class MTLD3D12DeviceImpl : public MTLD3D12Object> { GetLib() { return command_library; } + + virtual FormatCapability + GetMTLPixelFormatCapability(WMTPixelFormat Format) final { + Format = ORIGINAL_FORMAT(Format); + if (!format_inspector_.textureCapabilities.contains(Format)) + return FormatCapability(0); + return format_inspector_.textureCapabilities.at(Format); + }; }; HRESULT diff --git a/src/d3d12/d3d12_device.hpp b/src/d3d12/d3d12_device.hpp index 007122f1a..52b1a6da0 100644 --- a/src/d3d12/d3d12_device.hpp +++ b/src/d3d12/d3d12_device.hpp @@ -26,6 +26,7 @@ #include "dxmt_buffer.hpp" #include "dxmt_command.hpp" #include "dxmt_fence.hpp" +#include "dxmt_format.hpp" #include "dxmt_presenter.hpp" #include "dxmt_texture.hpp" #include "log/log.hpp" @@ -39,7 +40,7 @@ namespace dxmt { -class MTLD3D12GraphicsCommandList : public ID3D12GraphicsCommandList { +class MTLD3D12GraphicsCommandList : public ID3D12GraphicsCommandList2 { public: EncoderData *entry; size_t encoder_count; @@ -156,7 +157,7 @@ class MTLD3D12ComputePipelineState : public MTLD3D12PipelineState { virtual void ReleasePrivate() = 0; }; -class MTLD3D12Device : public ID3D12Device1 { +class MTLD3D12Device : public ID3D12Device3 { public: virtual WMT::Device GetMTLDevice() = 0; @@ -176,6 +177,8 @@ class MTLD3D12Device : public ID3D12Device1 { virtual InternalCommandLibrary& GetLib() = 0; + virtual FormatCapability GetMTLPixelFormatCapability(WMTPixelFormat Format) = 0; + EventListener event_listener; }; @@ -203,8 +206,8 @@ HRESULT CreateCommittedTexture( HRESULT CreatePlacedTexture( - MTLD3D12Device *pDevice, MTLD3D12Heap *pHeap, const D3D12_RESOURCE_DESC *pDesc, D3D12_RESOURCE_STATES InitialState, - const D3D12_CLEAR_VALUE *OptimizedClearValue, REFIID riid, void **ppResource + MTLD3D12Device *pDevice, MTLD3D12Heap *pHeap, UINT64 HeapOffset, const D3D12_RESOURCE_DESC *pDesc, + D3D12_RESOURCE_STATES InitialState, const D3D12_CLEAR_VALUE *OptimizedClearValue, REFIID riid, void **ppResource ); HRESULT CreateCommittedBuffer( @@ -215,8 +218,8 @@ HRESULT CreateCommittedBuffer( HRESULT CreatePlacedBuffer( - MTLD3D12Device *pDevice, MTLD3D12Heap *pHeap, const D3D12_RESOURCE_DESC *pDesc, D3D12_RESOURCE_STATES InitialState, - const D3D12_CLEAR_VALUE *OptimizedClearValue, REFIID riid, void **ppResource + MTLD3D12Device *pDevice, MTLD3D12Heap *pHeap, UINT64 HeapOffset, const D3D12_RESOURCE_DESC *pDesc, + D3D12_RESOURCE_STATES InitialState, const D3D12_CLEAR_VALUE *OptimizedClearValue, REFIID riid, void **ppResource ); HRESULT @@ -333,4 +336,11 @@ HRESULT ValidateResourceDescs(const D3D12_RESOURCE_DESC *pDesc, D3D12_HEAP_TYPE HRESULT ValidateHeapProperties(const D3D12_HEAP_PROPERTIES *pHeapProps, D3D12_HEAP_FLAGS Flags, bool AdapterIsNUMA); +D3D12_BOX GetResourceExtent(const D3D12_RESOURCE_DESC &Desc, UINT MipSlice); + +UINT DecomposeSubresource( + const D3D12_RESOURCE_DESC &Desc, UINT Subresource = 0, UINT *pMipSlice = NULL, UINT *pArraySlice = NULL, + UINT *pPlaneSlice = NULL +); + } // namespace dxmt \ No newline at end of file diff --git a/src/d3d12/d3d12_pipeline_graphics.cpp b/src/d3d12/d3d12_pipeline_graphics.cpp index 97552d8d5..047cba425 100644 --- a/src/d3d12/d3d12_pipeline_graphics.cpp +++ b/src/d3d12/d3d12_pipeline_graphics.cpp @@ -364,10 +364,10 @@ class MTLD3D12GraphicsPipelineStateImpl : public MTLD3D12PageableGetMTLPixelFormatCapability(rt.pixel_format) & FormatCapability::Blend)) { - // return E_INVALIDARG; - // } + if (!any_bit_set(device_->GetMTLPixelFormatCapability(rt.pixel_format) & FormatCapability::Blend)) { + WARN("CreateGraphicsPipelineState: pixel format ", rt.pixel_format, " is not blendable"); + return E_INVALIDARG; + } if (BlendFactorIsDualSource(renderTarget.SrcBlendAlpha) || BlendFactorIsDualSource(renderTarget.SrcBlend) || BlendFactorIsDualSource(renderTarget.DestBlendAlpha) || BlendFactorIsDualSource(renderTarget.DestBlend)) { dual_source_blending = true; @@ -416,6 +416,11 @@ class MTLD3D12GraphicsPipelineStateImpl : public MTLD3D12PageableNumRenderTargets; i++) { + data_ps.pixel_formats[i] = ORIGINAL_FORMAT(info.colors[i].pixel_format); + } + SM50_SHADER_ROOT_SIGNATURE_DATA rootsig; rootsig.type = SM50_SHADER_ROOT_SIGNATURE; if (pDesc->pRootSignature) { diff --git a/src/d3d12/d3d12_resource_helper.cpp b/src/d3d12/d3d12_resource_helper.cpp index 324fc4677..17c79753e 100644 --- a/src/d3d12/d3d12_resource_helper.cpp +++ b/src/d3d12/d3d12_resource_helper.cpp @@ -17,6 +17,7 @@ */ #include "d3d12_device.hpp" +#include "util_bit.hpp" namespace dxmt { @@ -378,4 +379,56 @@ ValidateHeapProperties(const D3D12_HEAP_PROPERTIES *pHeapProps, D3D12_HEAP_FLAGS return S_OK; } +D3D12_BOX +GetResourceExtent(const D3D12_RESOURCE_DESC &Desc, UINT MipSlice) { + D3D12_BOX box{0, 0, 0, 1, 1, 1}; + switch (Desc.Dimension) { + default: + break; + case D3D12_RESOURCE_DIMENSION_TEXTURE3D: + box.back = std::max(1u, Desc.DepthOrArraySize >> MipSlice); + [[fallthrough]]; + case D3D12_RESOURCE_DIMENSION_TEXTURE2D: + box.bottom = std::max(1u, Desc.Height >> MipSlice); + [[fallthrough]]; + case D3D12_RESOURCE_DIMENSION_BUFFER: + case D3D12_RESOURCE_DIMENSION_TEXTURE1D: + box.right = std::max(1u, Desc.Width >> MipSlice); + break; + } + return box; +} + +UINT +DecomposeSubresource( + const D3D12_RESOURCE_DESC &Desc, UINT Subresource, UINT *pMipSlice, UINT *pArraySlice, UINT *pPlaneSlice +) { + uint32_t ExtentOr = Desc.Width; + uint32_t ArraySize = 1; + switch (Desc.Dimension) { + default: + return 1; + case D3D12_RESOURCE_DIMENSION_TEXTURE1D: + ArraySize = Desc.DepthOrArraySize; + break; + case D3D12_RESOURCE_DIMENSION_TEXTURE2D: + ExtentOr |= Desc.Height; + ArraySize = Desc.DepthOrArraySize; + break; + case D3D12_RESOURCE_DIMENSION_TEXTURE3D: + ExtentOr |= Desc.Height | Desc.DepthOrArraySize; + break; + } + auto MaxMipLevels = 32 - bit::lzcnt(ExtentOr); + auto MipLevels = Desc.MipLevels ? Desc.MipLevels : MaxMipLevels; + + if (pMipSlice) + *pMipSlice = Subresource % MipLevels; + if (pArraySlice) + *pArraySlice = ((Subresource / MipLevels) % ArraySize); + if (pPlaneSlice) + *pPlaneSlice = (Subresource / (MipLevels * ArraySize)); + return MipLevels; +} + } // namespace dxmt \ No newline at end of file diff --git a/src/d3d12/d3d12_swapchain.cpp b/src/d3d12/d3d12_swapchain.cpp index 5270baff3..2ced8c1f9 100644 --- a/src/d3d12/d3d12_swapchain.cpp +++ b/src/d3d12/d3d12_swapchain.cpp @@ -149,7 +149,7 @@ class MTLD3D12SwapChain final : public MTLDXGISubObject { D3D12_RESOURCE_DESC desc_; + D3D12_HEAP_PROPERTIES heap_props_; + D3D12_HEAP_FLAGS heap_flags_; public: MTLD3D12Texture(MTLD3D12Device *pDevice) : MTLD3D12Pageable(pDevice) {} @@ -148,10 +150,12 @@ class MTLD3D12Texture : public MTLD3D12Pageable { HRESULT Initialize( const D3D12_HEAP_PROPERTIES *pHeapProps, D3D12_HEAP_FLAGS HeapFlags, const D3D12_RESOURCE_DESC *pDesc, - D3D12_RESOURCE_STATES InitialState, MTLD3D12Heap *pHeap + D3D12_RESOURCE_STATES InitialState, MTLD3D12Heap *pHeap, UINT64 HeapOffset ) { // TODO: validate and normalize desc_ = *pDesc; + heap_props_ = *pHeapProps; + heap_flags_ = HeapFlags; switch (InitialState) { case D3D12_RESOURCE_STATE_RENDER_TARGET: { @@ -239,7 +243,11 @@ class MTLD3D12Texture : public MTLD3D12Pageable { virtual HRESULT STDMETHODCALLTYPE GetHeapProperties(D3D12_HEAP_PROPERTIES *pHeapProps, D3D12_HEAP_FLAGS *pFlags) { - return E_NOTIMPL; + if (pHeapProps) + *pHeapProps = heap_props_; + if (pFlags) + *pFlags = heap_flags_; + return S_OK; }; virtual HRESULT STDMETHODCALLTYPE @@ -739,7 +747,7 @@ CreateCommittedTexture( REFIID riid, void **ppResource ) { auto texture = Com(new MTLD3D12Texture(pDevice)); - HRESULT hr = texture->Initialize(pHeapProps, HeapFlags, pDesc, InitialState, nullptr); + HRESULT hr = texture->Initialize(pHeapProps, HeapFlags, pDesc, InitialState, nullptr, 0); if (FAILED(hr)) return hr; if (!ppResource) @@ -749,8 +757,8 @@ CreateCommittedTexture( HRESULT CreatePlacedTexture( - MTLD3D12Device *pDevice, MTLD3D12Heap *pHeap, const D3D12_RESOURCE_DESC *pDesc, D3D12_RESOURCE_STATES InitialState, - const D3D12_CLEAR_VALUE *OptimizedClearValue, REFIID riid, void **ppResource + MTLD3D12Device *pDevice, MTLD3D12Heap *pHeap, UINT64 HeapOffset, const D3D12_RESOURCE_DESC *pDesc, + D3D12_RESOURCE_STATES InitialState, const D3D12_CLEAR_VALUE *OptimizedClearValue, REFIID riid, void **ppResource ) { auto texture = Com(new MTLD3D12Texture(pDevice)); D3D12_HEAP_DESC heap_desc = pHeap->GetDesc(); @@ -758,7 +766,7 @@ CreatePlacedTexture( if (heap_desc.Flags & D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS) return E_INVALIDARG; - HRESULT hr = texture->Initialize(&heap_desc.Properties, heap_desc.Flags, pDesc, InitialState, pHeap); + HRESULT hr = texture->Initialize(&heap_desc.Properties, heap_desc.Flags, pDesc, InitialState, pHeap, HeapOffset); if (FAILED(hr)) return hr; if (!ppResource) diff --git a/src/dxgi/dxgi_adapter.cpp b/src/dxgi/dxgi_adapter.cpp index ea96fe400..abccc658d 100644 --- a/src/dxgi/dxgi_adapter.cpp +++ b/src/dxgi/dxgi_adapter.cpp @@ -268,12 +268,13 @@ class MTLDXGIAdapter : public MTLDXGIObject { HRESULT STDMETHODCALLTYPE RegisterVideoMemoryBudgetChangeNotificationEvent( HANDLE event, DWORD *cookie) override { - assert(0 && "TODO"); + *cookie = 0; + return S_OK; } void STDMETHODCALLTYPE UnregisterVideoMemoryBudgetChangeNotification(DWORD cookie) override { - assert(0 && "TODO"); + // no op } WMT::Device STDMETHODCALLTYPE GetMTLDevice() final { return device_; } diff --git a/src/winemetal/Metal.hpp b/src/winemetal/Metal.hpp index 1f51b6d48..8224a0c2f 100644 --- a/src/winemetal/Metal.hpp +++ b/src/winemetal/Metal.hpp @@ -272,6 +272,16 @@ class Texture : public Resource { data.set((void *)pixelBytes); return MTLTexture_replaceRegion(handle, origin, size, level, slice, data, bytesPerRow, bytesPerImage); } + + void + getBytes( + WMTOrigin origin, WMTSize size, uint64_t level, uint64_t slice, void *pixelBytes, uint64_t bytesPerRow, + uint64_t bytesPerImage + ) { + WMTMemoryPointer data; + data.set((void *)pixelBytes); + return MTLTexture_getBytes(handle, origin, size, level, slice, data, bytesPerRow, bytesPerImage); + } }; class Buffer : public Resource { diff --git a/src/winemetal/unix/winemetal_unix.c b/src/winemetal/unix/winemetal_unix.c index cd7df600a..5fda00910 100644 --- a/src/winemetal/unix/winemetal_unix.c +++ b/src/winemetal/unix/winemetal_unix.c @@ -781,6 +781,11 @@ _MTLBlitCommandEncoder_encodeCommands(void *obj) { withRange:NSMakeRange(body->location, body->length)]; break; } + case WMTBlitCommandCopyTexture: { + struct wmtcmd_blit_copy_texture *body = (struct wmtcmd_blit_copy_texture *)next; + [encoder copyFromTexture:(id)body->src toTexture:(id)body->dst]; + break; + } } next = next->next.ptr; @@ -3092,6 +3097,21 @@ _MTLDevice_newLibraryWithSource(void *obj) { return STATUS_SUCCESS; } +static NTSTATUS +_MTLTexture_getBytes(void *obj) { + struct unixcall_mtltexture_replaceregion *params = obj; + [(id)params->texture getBytes:params->data.ptr + bytesPerRow:params->bytes_per_row + bytesPerImage:params->bytes_per_image + fromRegion:MTLRegionMake3D( + params->origin.x, params->origin.y, params->origin.z, + params->size.width, params->size.height, params->size.depth + ) + mipmapLevel:params->level + slice:params->slice]; + return STATUS_SUCCESS; +} + /* * Definition from cache.c */ @@ -3248,6 +3268,7 @@ const void *__wine_unix_call_funcs[] = { &_MTLHeap_newTexture, &_MTLDevice_newIndirectCommandBuffer, &_MTLDevice_newLibraryWithSource, + &_MTLTexture_getBytes, }; #ifndef DXMT_NATIVE @@ -3397,5 +3418,6 @@ const void *__wine_unix_call_wow64_funcs[] = { &_MTLHeap_newTexture, &_MTLDevice_newIndirectCommandBuffer, &_MTLDevice_newLibraryWithSource, + &_MTLTexture_getBytes, }; #endif diff --git a/src/winemetal/winemetal.h b/src/winemetal/winemetal.h index a72cc8eb9..7bee6fd9b 100644 --- a/src/winemetal/winemetal.h +++ b/src/winemetal/winemetal.h @@ -890,6 +890,7 @@ enum WMTBlitCommandType : uint16_t { WMTBlitCommandCopyFromBufferToTextureWithBlitOption, WMTBlitCommandCopyFromTextureToBufferWithBlitOption, WMTBlitCommandResetCommandsInBuffer, + WMTBlitCommandCopyTexture, }; enum WMTBlitOption : uint16_t { @@ -1043,6 +1044,14 @@ struct wmtcmd_blit_resetcommands { uint32_t length; }; +struct wmtcmd_blit_copy_texture { + enum WMTBlitCommandType type; + uint16_t reserved[3]; + struct WMTMemoryPointer next; + obj_handle_t src; + obj_handle_t dst; +}; + WINEMETAL_API void MTLBlitCommandEncoder_encodeCommands(obj_handle_t encoder, const struct wmtcmd_base *cmd_head); enum WMTComputeCommandType : uint16_t { @@ -2123,4 +2132,9 @@ WINEMETAL_API obj_handle_t MTLDevice_newIndirectCommandBuffer( WINEMETAL_API obj_handle_t MTLDevice_newLibraryWithSource(obj_handle_t device, const char *source, uint64_t length, obj_handle_t *err_out); +WINEMETAL_API void MTLTexture_getBytes( + obj_handle_t texture, struct WMTOrigin origin, struct WMTSize size, uint64_t level, uint64_t slice, + struct WMTMemoryPointer data, uint64_t bytes_per_row, uint64_t bytes_per_image +); + #endif \ No newline at end of file diff --git a/src/winemetal/winemetal_thunks.c b/src/winemetal/winemetal_thunks.c index f20c774af..42286c95a 100644 --- a/src/winemetal/winemetal_thunks.c +++ b/src/winemetal/winemetal_thunks.c @@ -1313,3 +1313,21 @@ MTLDevice_newLibraryWithSource(obj_handle_t device, const char *source, uint64_t *err_out = params.ret_error; return params.ret_library; } + +WINEMETAL_API void +MTLTexture_getBytes( + obj_handle_t texture, struct WMTOrigin origin, struct WMTSize size, uint64_t level, uint64_t slice, + struct WMTMemoryPointer data, uint64_t bytes_per_row, uint64_t bytes_per_image +) { + // use compatible struct + struct unixcall_mtltexture_replaceregion params; + params.texture = texture; + params.origin = origin; + params.size = size; + params.level = level; + params.slice = slice; + params.data = data; + params.bytes_per_row = bytes_per_row; + params.bytes_per_image = bytes_per_image; + UNIX_CALL(145, ¶ms); +}