15 : _device(device), _desc(desc)
17 assert(device &&
"MetalTextureStream requires a valid MTL::Device");
18 assert(desc.
width > 0 && desc.
height > 0 &&
"Texture dimensions must be positive");
23 auto* texDesc = MTL::TextureDescriptor::texture2DDescriptor(
26 texDesc->setStorageMode(MTL::StorageModeShared);
27 texDesc->setUsage(MTL::TextureUsageShaderRead);
30 texDesc->setCpuCacheMode(MTL::CPUCacheModeWriteCombined);
34 _textures[i] = device->newTexture(texDesc);
36 auto labelStr = std::string(desc.
label) +
"_" + std::to_string(i);
37 _textures[i]->setLabel(
38 NS::String::string(labelStr.c_str(), NS::UTF8StringEncoding));
45 _slotSemaphore = dispatch_semaphore_create(
kNumSlots);
47 spdlog::info(
"[MetalTextureStream] Created: {}x{} {} ({} slots, {:.1f} MB total)",
49 desc.
format == MTL::PixelFormatBGRA8Unorm ?
"BGRA8" :
50 desc.
format == MTL::PixelFormatRGBA8Unorm ?
"RGBA8" :
51 desc.
format == MTL::PixelFormatRGBA16Float ?
"RGBA16F" :
52 desc.
format == MTL::PixelFormatR32Float ?
"R32F" :
"other",
84 MTL::Region region, uint32_t mipLevel)
86 assert(data &&
"writeRegion: data must not be null");
88 const int idx = _writeIndex.load(std::memory_order_acquire);
89 _textures[idx]->replaceRegion(region, mipLevel, 0, data, bytesPerRow, 0);
97 const int oldWrite = _writeIndex.load(std::memory_order_acquire);
98 const int oldReady = _readyIndex.load(std::memory_order_acquire);
100 _readyIndex.store(oldWrite, std::memory_order_release);
101 _writeIndex.store(oldReady, std::memory_order_release);
103 _publishCount.fetch_add(1, std::memory_order_relaxed);
104 _hasPublished =
true;
120 auto* ext = _externalReady.exchange(
nullptr, std::memory_order_acq_rel);
125 if (!_hasPublished) {
130 const int oldReady = _readyIndex.load(std::memory_order_acquire);
131 const int oldRead = _readIndex.load(std::memory_order_acquire);
133 _readIndex.store(oldReady, std::memory_order_release);
134 _readyIndex.store(oldRead, std::memory_order_release);
136 return _textures[_readIndex.load(std::memory_order_acquire)];