|
|
|
@@ -55,7 +55,8 @@ Driver* MetalDriver::create(MetalPlatform* const platform) {
|
|
|
|
|
MetalDriver::MetalDriver(backend::MetalPlatform* platform) noexcept
|
|
|
|
|
: DriverBase(new ConcreteDispatcher<MetalDriver>()),
|
|
|
|
|
mPlatform(*platform),
|
|
|
|
|
mContext(new MetalContext) {
|
|
|
|
|
mContext(new MetalContext),
|
|
|
|
|
mHandleAllocator("Handles", FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U) {
|
|
|
|
|
mContext->driver = this;
|
|
|
|
|
|
|
|
|
|
mContext->device = mPlatform.createDevice();
|
|
|
|
@@ -145,13 +146,13 @@ void MetalDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
|
|
|
|
|
|
|
|
|
|
void MetalDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
|
|
|
|
|
backend::FrameScheduledCallback callback, void* user) {
|
|
|
|
|
auto* swapChain = handle_cast<MetalSwapChain>(mHandleMap, sch);
|
|
|
|
|
auto* swapChain = handle_cast<MetalSwapChain>(sch);
|
|
|
|
|
swapChain->setFrameScheduledCallback(callback, user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
|
|
|
|
|
backend::FrameCompletedCallback callback, void* user) {
|
|
|
|
|
auto* swapChain = handle_cast<MetalSwapChain>(mHandleMap, sch);
|
|
|
|
|
auto* swapChain = handle_cast<MetalSwapChain>(sch);
|
|
|
|
|
swapChain->setFrameCompletedCallback(callback, user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -205,19 +206,19 @@ void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint8_t buffer
|
|
|
|
|
uint8_t attributeCount, uint32_t vertexCount, AttributeArray attributes,
|
|
|
|
|
BufferUsage usage) {
|
|
|
|
|
// TODO: Take BufferUsage into account when creating the buffer.
|
|
|
|
|
construct_handle<MetalVertexBuffer>(mHandleMap, vbh, *mContext, bufferCount,
|
|
|
|
|
construct_handle<MetalVertexBuffer>(vbh, *mContext, bufferCount,
|
|
|
|
|
attributeCount, vertexCount, attributes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
|
|
|
|
|
uint32_t indexCount, BufferUsage) {
|
|
|
|
|
auto elementSize = (uint8_t) getElementTypeSize(elementType);
|
|
|
|
|
construct_handle<MetalIndexBuffer>(mHandleMap, ibh, *mContext, elementSize, indexCount);
|
|
|
|
|
construct_handle<MetalIndexBuffer>(ibh, *mContext, elementSize, indexCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
|
|
|
|
|
BufferObjectBinding bindingType, BufferUsage) {
|
|
|
|
|
construct_handle<MetalBufferObject>(mHandleMap, boh, *mContext, byteCount);
|
|
|
|
|
construct_handle<MetalBufferObject>(boh, *mContext, byteCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
|
|
|
|
@@ -227,7 +228,7 @@ void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8
|
|
|
|
|
auto& sc = mContext->sampleCountLookup;
|
|
|
|
|
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
|
|
|
|
|
|
|
|
|
|
construct_handle<MetalTexture>(mHandleMap, th, *mContext, target, levels, format, samples,
|
|
|
|
|
construct_handle<MetalTexture>(th, *mContext, target, levels, format, samples,
|
|
|
|
|
width, height, depth, usage, TextureSwizzle::CHANNEL_0, TextureSwizzle::CHANNEL_1,
|
|
|
|
|
TextureSwizzle::CHANNEL_2, TextureSwizzle::CHANNEL_3);
|
|
|
|
|
}
|
|
|
|
@@ -240,7 +241,7 @@ void MetalDriver::createTextureSwizzledR(Handle<HwTexture> th, SamplerType targe
|
|
|
|
|
auto& sc = mContext->sampleCountLookup;
|
|
|
|
|
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
|
|
|
|
|
|
|
|
|
|
construct_handle<MetalTexture>(mHandleMap, th, *mContext, target, levels, format, samples,
|
|
|
|
|
construct_handle<MetalTexture>(th, *mContext, target, levels, format, samples,
|
|
|
|
|
width, height, depth, usage, r, g, b, a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -266,24 +267,24 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
|
|
|
|
|
ASSERT_PRECONDITION(metalTexture.textureType == filamentMetalType,
|
|
|
|
|
"Imported id<MTLTexture> type (%d) != Filament texture type (%d)",
|
|
|
|
|
metalTexture.textureType, filamentMetalType);
|
|
|
|
|
construct_handle<MetalTexture>(mHandleMap, th, *mContext, target, levels, format, samples,
|
|
|
|
|
construct_handle<MetalTexture>(th, *mContext, target, levels, format, samples,
|
|
|
|
|
width, height, depth, usage, metalTexture);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createSamplerGroupR(Handle<HwSamplerGroup> sbh, uint32_t size) {
|
|
|
|
|
mContext->samplerGroups.insert(construct_handle<MetalSamplerGroup>(mHandleMap, sbh, size));
|
|
|
|
|
mContext->samplerGroups.insert(construct_handle<MetalSamplerGroup>(sbh, size));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph, int dummy) {
|
|
|
|
|
construct_handle<MetalRenderPrimitive>(mHandleMap, rph);
|
|
|
|
|
construct_handle<MetalRenderPrimitive>(rph);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program) {
|
|
|
|
|
construct_handle<MetalProgram>(mHandleMap, rph, mContext->device, program);
|
|
|
|
|
construct_handle<MetalProgram>(rph, mContext->device, program);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dummy) {
|
|
|
|
|
construct_handle<MetalRenderTarget>(mHandleMap, rth, mContext);
|
|
|
|
|
construct_handle<MetalRenderTarget>(rth, mContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|
|
|
@@ -303,7 +304,7 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto colorTexture = handle_cast<MetalTexture>(mHandleMap, buffer.handle);
|
|
|
|
|
auto colorTexture = handle_cast<MetalTexture>(buffer.handle);
|
|
|
|
|
ASSERT_PRECONDITION(colorTexture->texture,
|
|
|
|
|
"Color texture passed to render target has no texture allocation");
|
|
|
|
|
colorTexture->updateLodRange(buffer.level);
|
|
|
|
@@ -314,7 +315,7 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|
|
|
|
|
|
|
|
|
MetalRenderTarget::Attachment depthAttachment = { nil };
|
|
|
|
|
if (depth.handle) {
|
|
|
|
|
auto depthTexture = handle_cast<MetalTexture>(mHandleMap, depth.handle);
|
|
|
|
|
auto depthTexture = handle_cast<MetalTexture>(depth.handle);
|
|
|
|
|
ASSERT_PRECONDITION(depthTexture->texture,
|
|
|
|
|
"Depth texture passed to render target has no texture allocation.");
|
|
|
|
|
depthTexture->updateLodRange(depth.level);
|
|
|
|
@@ -325,7 +326,7 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|
|
|
|
ASSERT_POSTCONDITION(!depth.handle || any(targetBufferFlags & TargetBufferFlags::DEPTH),
|
|
|
|
|
"The DEPTH flag was specified, but no depth texture provided.");
|
|
|
|
|
|
|
|
|
|
construct_handle<MetalRenderTarget>(mHandleMap, rth, mContext, width, height, samples,
|
|
|
|
|
construct_handle<MetalRenderTarget>(rth, mContext, width, height, samples,
|
|
|
|
|
colorAttachments, depthAttachment);
|
|
|
|
|
|
|
|
|
|
ASSERT_POSTCONDITION(
|
|
|
|
@@ -335,28 +336,28 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createFenceR(Handle<HwFence> fh, int dummy) {
|
|
|
|
|
auto* fence = handle_cast<MetalFence>(mHandleMap, fh);
|
|
|
|
|
auto* fence = handle_cast<MetalFence>(fh);
|
|
|
|
|
fence->encode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createSyncR(Handle<HwSync> sh, int) {
|
|
|
|
|
auto* fence = handle_cast<MetalFence>(mHandleMap, sh);
|
|
|
|
|
auto* fence = handle_cast<MetalFence>(sh);
|
|
|
|
|
fence->encode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
|
|
|
|
|
if (UTILS_UNLIKELY(flags & backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) {
|
|
|
|
|
CVPixelBufferRef pixelBuffer = (CVPixelBufferRef) nativeWindow;
|
|
|
|
|
construct_handle<MetalSwapChain>(mHandleMap, sch, *mContext, pixelBuffer, flags);
|
|
|
|
|
construct_handle<MetalSwapChain>(sch, *mContext, pixelBuffer, flags);
|
|
|
|
|
} else {
|
|
|
|
|
auto* metalLayer = (__bridge CAMetalLayer*) nativeWindow;
|
|
|
|
|
construct_handle<MetalSwapChain>(mHandleMap, sch, *mContext, metalLayer, flags);
|
|
|
|
|
construct_handle<MetalSwapChain>(sch, *mContext, metalLayer, flags);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
|
|
|
|
|
uint32_t width, uint32_t height, uint64_t flags) {
|
|
|
|
|
construct_handle<MetalSwapChain>(mHandleMap, sch, *mContext, width, height, flags);
|
|
|
|
|
construct_handle<MetalSwapChain>(sch, *mContext, width, height, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::createStreamFromTextureIdR(Handle<HwStream>, intptr_t externalTextureId,
|
|
|
|
@@ -368,47 +369,47 @@ void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwVertexBuffer> MetalDriver::createVertexBufferS() noexcept {
|
|
|
|
|
return alloc_handle<MetalVertexBuffer, HwVertexBuffer>();
|
|
|
|
|
return alloc_handle<MetalVertexBuffer>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwIndexBuffer> MetalDriver::createIndexBufferS() noexcept {
|
|
|
|
|
return alloc_handle<MetalIndexBuffer, HwIndexBuffer>();
|
|
|
|
|
return alloc_handle<MetalIndexBuffer>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwBufferObject> MetalDriver::createBufferObjectS() noexcept {
|
|
|
|
|
return alloc_handle<MetalBufferObject, HwBufferObject>();
|
|
|
|
|
return alloc_handle<MetalBufferObject>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwTexture> MetalDriver::createTextureS() noexcept {
|
|
|
|
|
return alloc_handle<MetalTexture, HwTexture>();
|
|
|
|
|
return alloc_handle<MetalTexture>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwTexture> MetalDriver::createTextureSwizzledS() noexcept {
|
|
|
|
|
return alloc_handle<MetalTexture, HwTexture>();
|
|
|
|
|
return alloc_handle<MetalTexture>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwTexture> MetalDriver::importTextureS() noexcept {
|
|
|
|
|
return alloc_handle<MetalTexture, HwTexture>();
|
|
|
|
|
return alloc_handle<MetalTexture>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwSamplerGroup> MetalDriver::createSamplerGroupS() noexcept {
|
|
|
|
|
return alloc_handle<MetalSamplerGroup, HwSamplerGroup>();
|
|
|
|
|
return alloc_handle<MetalSamplerGroup>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwRenderPrimitive> MetalDriver::createRenderPrimitiveS() noexcept {
|
|
|
|
|
return alloc_handle<MetalRenderPrimitive, HwRenderPrimitive>();
|
|
|
|
|
return alloc_handle<MetalRenderPrimitive>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwProgram> MetalDriver::createProgramS() noexcept {
|
|
|
|
|
return alloc_handle<MetalProgram, HwProgram>();
|
|
|
|
|
return alloc_handle<MetalProgram>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwRenderTarget> MetalDriver::createDefaultRenderTargetS() noexcept {
|
|
|
|
|
return alloc_handle<MetalRenderTarget, HwRenderTarget>();
|
|
|
|
|
return alloc_handle<MetalRenderTarget>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwRenderTarget> MetalDriver::createRenderTargetS() noexcept {
|
|
|
|
|
return alloc_handle<MetalRenderTarget, HwRenderTarget>();
|
|
|
|
|
return alloc_handle<MetalRenderTarget>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwFence> MetalDriver::createFenceS() noexcept {
|
|
|
|
@@ -424,11 +425,11 @@ Handle<HwSync> MetalDriver::createSyncS() noexcept {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwSwapChain> MetalDriver::createSwapChainS() noexcept {
|
|
|
|
|
return alloc_handle<MetalSwapChain, HwSwapChain>();
|
|
|
|
|
return alloc_handle<MetalSwapChain>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwSwapChain> MetalDriver::createSwapChainHeadlessS() noexcept {
|
|
|
|
|
return alloc_handle<MetalSwapChain, HwSwapChain>();
|
|
|
|
|
return alloc_handle<MetalSwapChain>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Handle<HwStream> MetalDriver::createStreamFromTextureIdS() noexcept {
|
|
|
|
@@ -443,13 +444,13 @@ Handle<HwTimerQuery> MetalDriver::createTimerQueryS() noexcept {
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
|
|
|
|
|
if (vbh) {
|
|
|
|
|
destruct_handle<MetalVertexBuffer>(mHandleMap, vbh);
|
|
|
|
|
destruct_handle<MetalVertexBuffer>(vbh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
|
|
|
|
|
if (ibh) {
|
|
|
|
|
destruct_handle<MetalIndexBuffer>(mHandleMap, ibh);
|
|
|
|
|
destruct_handle<MetalIndexBuffer>(ibh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -458,24 +459,24 @@ void MetalDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// TODO: we can skip this loop if we're not a uniform buffer
|
|
|
|
|
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
|
|
|
|
|
auto* bo = handle_cast<MetalBufferObject>(boh);
|
|
|
|
|
for (auto& thisUniform : mContext->uniformState) {
|
|
|
|
|
if (thisUniform.buffer == bo->getBuffer()) {
|
|
|
|
|
thisUniform.bound = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
destruct_handle<MetalBufferObject>(mHandleMap, boh);
|
|
|
|
|
destruct_handle<MetalBufferObject>(boh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
|
|
|
|
if (rph) {
|
|
|
|
|
destruct_handle<MetalRenderPrimitive>(mHandleMap, rph);
|
|
|
|
|
destruct_handle<MetalRenderPrimitive>(rph);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroyProgram(Handle<HwProgram> ph) {
|
|
|
|
|
if (ph) {
|
|
|
|
|
destruct_handle<MetalProgram>(mHandleMap, ph);
|
|
|
|
|
destruct_handle<MetalProgram>(ph);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -484,14 +485,14 @@ void MetalDriver::destroySamplerGroup(Handle<HwSamplerGroup> sbh) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Unbind this sampler group from our internal state.
|
|
|
|
|
auto* metalSampler = handle_cast<MetalSamplerGroup>(mHandleMap, sbh);
|
|
|
|
|
auto* metalSampler = handle_cast<MetalSamplerGroup>(sbh);
|
|
|
|
|
for (auto& samplerBinding : mContext->samplerBindings) {
|
|
|
|
|
if (samplerBinding == metalSampler) {
|
|
|
|
|
samplerBinding = {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mContext->samplerGroups.erase(metalSampler);
|
|
|
|
|
destruct_handle<MetalSamplerGroup>(mHandleMap, sbh);
|
|
|
|
|
destruct_handle<MetalSamplerGroup>(sbh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroyTexture(Handle<HwTexture> th) {
|
|
|
|
@@ -510,18 +511,18 @@ void MetalDriver::destroyTexture(Handle<HwTexture> th) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
destruct_handle<MetalTexture>(mHandleMap, th);
|
|
|
|
|
destruct_handle<MetalTexture>(th);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
|
|
|
|
if (rth) {
|
|
|
|
|
destruct_handle<MetalRenderTarget>(mHandleMap, rth);
|
|
|
|
|
destruct_handle<MetalRenderTarget>(rth);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroySwapChain(Handle<HwSwapChain> sch) {
|
|
|
|
|
if (sch) {
|
|
|
|
|
destruct_handle<MetalSwapChain>(mHandleMap, sch);
|
|
|
|
|
destruct_handle<MetalSwapChain>(sch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -531,13 +532,13 @@ void MetalDriver::destroyStream(Handle<HwStream> sh) {
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroyTimerQuery(Handle<HwTimerQuery> tqh) {
|
|
|
|
|
if (tqh) {
|
|
|
|
|
destruct_handle<MetalTimerQuery>(mHandleMap, tqh);
|
|
|
|
|
destruct_handle<MetalTimerQuery>(tqh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroySync(Handle<HwSync> sh) {
|
|
|
|
|
if (sh) {
|
|
|
|
|
destruct_handle<MetalFence>(mHandleMap, sh);
|
|
|
|
|
destruct_handle<MetalFence>(sh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -589,12 +590,12 @@ void MetalDriver::updateStreams(backend::DriverApi* driver) {
|
|
|
|
|
|
|
|
|
|
void MetalDriver::destroyFence(Handle<HwFence> fh) {
|
|
|
|
|
if (fh) {
|
|
|
|
|
destruct_handle<MetalFence>(mHandleMap, fh);
|
|
|
|
|
destruct_handle<MetalFence>(fh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FenceStatus MetalDriver::wait(Handle<HwFence> fh, uint64_t timeout) {
|
|
|
|
|
auto* fence = handle_cast<MetalFence>(mHandleMap, fh);
|
|
|
|
|
auto* fence = handle_cast<MetalFence>(fh);
|
|
|
|
|
if (!fence) {
|
|
|
|
|
return FenceStatus::ERROR;
|
|
|
|
|
}
|
|
|
|
@@ -682,22 +683,22 @@ uint8_t MetalDriver::getMaxDrawBuffers() {
|
|
|
|
|
void MetalDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& data,
|
|
|
|
|
uint32_t byteOffset) {
|
|
|
|
|
assert_invariant(byteOffset == 0); // TODO: handle byteOffset for index buffers
|
|
|
|
|
auto* ib = handle_cast<MetalIndexBuffer>(mHandleMap, ibh);
|
|
|
|
|
auto* ib = handle_cast<MetalIndexBuffer>(ibh);
|
|
|
|
|
ib->buffer.copyIntoBuffer(data.buffer, data.size);
|
|
|
|
|
scheduleDestroy(std::move(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::updateBufferObject(Handle<HwBufferObject> boh, BufferDescriptor&& data,
|
|
|
|
|
uint32_t byteOffset) {
|
|
|
|
|
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
|
|
|
|
|
auto* bo = handle_cast<MetalBufferObject>(boh);
|
|
|
|
|
bo->updateBuffer(data.buffer, data.size, byteOffset);
|
|
|
|
|
scheduleDestroy(std::move(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
|
|
|
|
|
Handle<HwBufferObject> boh) {
|
|
|
|
|
auto* vertexBuffer = handle_cast<MetalVertexBuffer>(mHandleMap, vbh);
|
|
|
|
|
auto* bufferObject = handle_cast<MetalBufferObject>(mHandleMap, boh);
|
|
|
|
|
auto* vertexBuffer = handle_cast<MetalVertexBuffer>(vbh);
|
|
|
|
|
auto* bufferObject = handle_cast<MetalBufferObject>(boh);
|
|
|
|
|
assert_invariant(index < vertexBuffer->buffers.size());
|
|
|
|
|
vertexBuffer->buffers[index] = bufferObject->getBuffer();
|
|
|
|
|
}
|
|
|
|
@@ -706,7 +707,7 @@ void MetalDriver::update2DImage(Handle<HwTexture> th, uint32_t level, uint32_t x
|
|
|
|
|
uint32_t yoffset, uint32_t width, uint32_t height, PixelBufferDescriptor&& data) {
|
|
|
|
|
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
|
|
|
|
"update2DImage must be called outside of a render pass.");
|
|
|
|
|
auto tex = handle_cast<MetalTexture>(mHandleMap, th);
|
|
|
|
|
auto tex = handle_cast<MetalTexture>(th);
|
|
|
|
|
tex->loadImage(level, MTLRegionMake2D(xoffset, yoffset, width, height), data);
|
|
|
|
|
scheduleDestroy(std::move(data));
|
|
|
|
|
}
|
|
|
|
@@ -720,7 +721,7 @@ void MetalDriver::update3DImage(Handle<HwTexture> th, uint32_t level,
|
|
|
|
|
PixelBufferDescriptor&& data) {
|
|
|
|
|
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
|
|
|
|
"update3DImage must be called outside of a render pass.");
|
|
|
|
|
auto tex = handle_cast<MetalTexture>(mHandleMap, th);
|
|
|
|
|
auto tex = handle_cast<MetalTexture>(th);
|
|
|
|
|
tex->loadImage(level, MTLRegionMake3D(xoffset, yoffset, zoffset, width, height, depth), data);
|
|
|
|
|
scheduleDestroy(std::move(data));
|
|
|
|
|
}
|
|
|
|
@@ -729,7 +730,7 @@ void MetalDriver::updateCubeImage(Handle<HwTexture> th, uint32_t level,
|
|
|
|
|
PixelBufferDescriptor&& data, FaceOffsets faceOffsets) {
|
|
|
|
|
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
|
|
|
|
"updateCubeImage must be called outside of a render pass.");
|
|
|
|
|
auto tex = handle_cast<MetalTexture>(mHandleMap, th);
|
|
|
|
|
auto tex = handle_cast<MetalTexture>(th);
|
|
|
|
|
tex->loadCubeImage(faceOffsets, level, data);
|
|
|
|
|
scheduleDestroy(std::move(data));
|
|
|
|
|
}
|
|
|
|
@@ -749,12 +750,12 @@ void MetalDriver::cancelExternalImage(void* image) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::setExternalImage(Handle<HwTexture> th, void* image) {
|
|
|
|
|
auto texture = handle_cast<MetalTexture>(mHandleMap, th);
|
|
|
|
|
auto texture = handle_cast<MetalTexture>(th);
|
|
|
|
|
texture->externalImage.set((CVPixelBufferRef) image);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
|
|
|
|
|
auto texture = handle_cast<MetalTexture>(mHandleMap, th);
|
|
|
|
|
auto texture = handle_cast<MetalTexture>(th);
|
|
|
|
|
texture->externalImage.set((CVPixelBufferRef) image, plane);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -762,12 +763,12 @@ void MetalDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool MetalDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64_t* elapsedTime) {
|
|
|
|
|
auto* tq = handle_cast<MetalTimerQuery>(mHandleMap, tqh);
|
|
|
|
|
auto* tq = handle_cast<MetalTimerQuery>(tqh);
|
|
|
|
|
return mContext->timerQueryImpl->getQueryResult(tq, elapsedTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SyncStatus MetalDriver::getSyncStatus(Handle<HwSync> sh) {
|
|
|
|
|
auto* fence = handle_cast<MetalFence>(mHandleMap, sh);
|
|
|
|
|
auto* fence = handle_cast<MetalFence>(sh);
|
|
|
|
|
FenceStatus status = fence->wait(0);
|
|
|
|
|
if (status == FenceStatus::TIMEOUT_EXPIRED) {
|
|
|
|
|
return SyncStatus::NOT_SIGNALED;
|
|
|
|
@@ -780,7 +781,7 @@ SyncStatus MetalDriver::getSyncStatus(Handle<HwSync> sh) {
|
|
|
|
|
void MetalDriver::generateMipmaps(Handle<HwTexture> th) {
|
|
|
|
|
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
|
|
|
|
"generateMipmaps must be called outside of a render pass.");
|
|
|
|
|
auto tex = handle_cast<MetalTexture>(mHandleMap, th);
|
|
|
|
|
auto tex = handle_cast<MetalTexture>(th);
|
|
|
|
|
id <MTLBlitCommandEncoder> blitEncoder = [getPendingCommandBuffer(mContext) blitCommandEncoder];
|
|
|
|
|
[blitEncoder generateMipmapsForTexture:tex->texture];
|
|
|
|
|
[blitEncoder endEncoding];
|
|
|
|
@@ -794,13 +795,13 @@ bool MetalDriver::canGenerateMipmaps() {
|
|
|
|
|
|
|
|
|
|
void MetalDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
|
|
|
|
|
SamplerGroup&& samplerGroup) {
|
|
|
|
|
auto sb = handle_cast<MetalSamplerGroup>(mHandleMap, sbh);
|
|
|
|
|
auto sb = handle_cast<MetalSamplerGroup>(sbh);
|
|
|
|
|
*sb->sb = samplerGroup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
|
|
|
|
const RenderPassParams& params) {
|
|
|
|
|
auto renderTarget = handle_cast<MetalRenderTarget>(mHandleMap, rth);
|
|
|
|
|
auto renderTarget = handle_cast<MetalRenderTarget>(rth);
|
|
|
|
|
mContext->currentRenderTarget = renderTarget;
|
|
|
|
|
mContext->currentRenderPassFlags = params.flags;
|
|
|
|
|
|
|
|
|
@@ -851,16 +852,16 @@ void MetalDriver::endRenderPass(int dummy) {
|
|
|
|
|
|
|
|
|
|
void MetalDriver::setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph,
|
|
|
|
|
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh) {
|
|
|
|
|
auto primitive = handle_cast<MetalRenderPrimitive>(mHandleMap, rph);
|
|
|
|
|
auto vertexBuffer = handle_cast<MetalVertexBuffer>(mHandleMap, vbh);
|
|
|
|
|
auto indexBuffer = handle_cast<MetalIndexBuffer>(mHandleMap, ibh);
|
|
|
|
|
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
|
|
|
|
|
auto vertexBuffer = handle_cast<MetalVertexBuffer>(vbh);
|
|
|
|
|
auto indexBuffer = handle_cast<MetalIndexBuffer>(ibh);
|
|
|
|
|
primitive->setBuffers(vertexBuffer, indexBuffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph,
|
|
|
|
|
PrimitiveType pt, uint32_t offset, uint32_t minIndex, uint32_t maxIndex,
|
|
|
|
|
uint32_t count) {
|
|
|
|
|
auto primitive = handle_cast<MetalRenderPrimitive>(mHandleMap, rph);
|
|
|
|
|
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
|
|
|
|
|
primitive->type = pt;
|
|
|
|
|
primitive->offset = offset * primitive->indexBuffer->elementSize;
|
|
|
|
|
primitive->count = count;
|
|
|
|
@@ -870,24 +871,24 @@ void MetalDriver::setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph,
|
|
|
|
|
|
|
|
|
|
void MetalDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain> schRead) {
|
|
|
|
|
ASSERT_PRECONDITION_NON_FATAL(schDraw, "A draw SwapChain must be set.");
|
|
|
|
|
auto* drawSwapChain = handle_cast<MetalSwapChain>(mHandleMap, schDraw);
|
|
|
|
|
auto* drawSwapChain = handle_cast<MetalSwapChain>(schDraw);
|
|
|
|
|
mContext->currentDrawSwapChain = drawSwapChain;
|
|
|
|
|
|
|
|
|
|
if (schRead) {
|
|
|
|
|
auto* readSwapChain = handle_cast<MetalSwapChain>(mHandleMap, schRead);
|
|
|
|
|
auto* readSwapChain = handle_cast<MetalSwapChain>(schRead);
|
|
|
|
|
mContext->currentReadSwapChain = readSwapChain;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::commit(Handle<HwSwapChain> sch) {
|
|
|
|
|
auto* swapChain = handle_cast<MetalSwapChain>(mHandleMap, sch);
|
|
|
|
|
auto* swapChain = handle_cast<MetalSwapChain>(sch);
|
|
|
|
|
swapChain->present();
|
|
|
|
|
submitPendingCommands(mContext);
|
|
|
|
|
swapChain->releaseDrawable();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::bindUniformBuffer(uint32_t index, Handle<HwBufferObject> boh) {
|
|
|
|
|
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
|
|
|
|
|
auto* bo = handle_cast<MetalBufferObject>(boh);
|
|
|
|
|
mContext->uniformState[index] = UniformBufferState{
|
|
|
|
|
.buffer = bo->getBuffer(),
|
|
|
|
|
.offset = 0,
|
|
|
|
@@ -897,7 +898,7 @@ void MetalDriver::bindUniformBuffer(uint32_t index, Handle<HwBufferObject> boh)
|
|
|
|
|
|
|
|
|
|
void MetalDriver::bindUniformBufferRange(uint32_t index, Handle<HwBufferObject> boh,
|
|
|
|
|
uint32_t offset, uint32_t size) {
|
|
|
|
|
auto* bo = handle_cast<MetalBufferObject>(mHandleMap, boh);
|
|
|
|
|
auto* bo = handle_cast<MetalBufferObject>(boh);
|
|
|
|
|
mContext->uniformState[index] = UniformBufferState{
|
|
|
|
|
.buffer = bo->getBuffer(),
|
|
|
|
|
.offset = offset,
|
|
|
|
@@ -906,7 +907,7 @@ void MetalDriver::bindUniformBufferRange(uint32_t index, Handle<HwBufferObject>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
|
|
|
|
|
auto sb = handle_cast<MetalSamplerGroup>(mHandleMap, sbh);
|
|
|
|
|
auto sb = handle_cast<MetalSamplerGroup>(sbh);
|
|
|
|
|
mContext->samplerBindings[index] = sb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -950,7 +951,7 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
|
|
|
|
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
|
|
|
|
"readPixels must be called outside of a render pass.");
|
|
|
|
|
|
|
|
|
|
auto srcTarget = handle_cast<MetalRenderTarget>(mHandleMap, src);
|
|
|
|
|
auto srcTarget = handle_cast<MetalRenderTarget>(src);
|
|
|
|
|
// We always readPixels from the COLOR0 attachment.
|
|
|
|
|
MetalRenderTarget::Attachment color = srcTarget->getDrawColorAttachment(0);
|
|
|
|
|
id<MTLTexture> srcTexture = color.texture;
|
|
|
|
@@ -1039,8 +1040,8 @@ void MetalDriver::blit(TargetBufferFlags buffers,
|
|
|
|
|
mContext->currentRenderPassEncoder = nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto srcTarget = handle_cast<MetalRenderTarget>(mHandleMap, src);
|
|
|
|
|
auto dstTarget = handle_cast<MetalRenderTarget>(mHandleMap, dst);
|
|
|
|
|
auto srcTarget = handle_cast<MetalRenderTarget>(src);
|
|
|
|
|
auto dstTarget = handle_cast<MetalRenderTarget>(dst);
|
|
|
|
|
|
|
|
|
|
ASSERT_PRECONDITION(srcRect.left >= 0 && srcRect.bottom >= 0 &&
|
|
|
|
|
dstRect.left >= 0 && dstRect.bottom >= 0,
|
|
|
|
@@ -1139,8 +1140,8 @@ void MetalDriver::blit(TargetBufferFlags buffers,
|
|
|
|
|
void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph) {
|
|
|
|
|
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder != nullptr,
|
|
|
|
|
"Attempted to draw without a valid command encoder.");
|
|
|
|
|
auto primitive = handle_cast<MetalRenderPrimitive>(mHandleMap, rph);
|
|
|
|
|
auto program = handle_cast<MetalProgram>(mHandleMap, ps.program);
|
|
|
|
|
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
|
|
|
|
|
auto program = handle_cast<MetalProgram>(ps.program);
|
|
|
|
|
const auto& rs = ps.rasterState;
|
|
|
|
|
|
|
|
|
|
// If the material debugger is enabled, avoid fatal (or cascading) errors and that can occur
|
|
|
|
@@ -1264,7 +1265,7 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph)
|
|
|
|
|
if (binding >= SAMPLER_BINDING_COUNT) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const auto metalTexture = handle_const_cast<MetalTexture>(mHandleMap, sampler->t);
|
|
|
|
|
const auto metalTexture = handle_const_cast<MetalTexture>(sampler->t);
|
|
|
|
|
texturesToBind[binding] = metalTexture->swizzledTextureView ? metalTexture->swizzledTextureView
|
|
|
|
|
: metalTexture->texture;
|
|
|
|
|
|
|
|
|
@@ -1352,14 +1353,14 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph)
|
|
|
|
|
void MetalDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
|
|
|
|
|
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
|
|
|
|
"beginTimerQuery must be called outside of a render pass.");
|
|
|
|
|
auto* tq = handle_cast<MetalTimerQuery>(mHandleMap, tqh);
|
|
|
|
|
auto* tq = handle_cast<MetalTimerQuery>(tqh);
|
|
|
|
|
mContext->timerQueryImpl->beginTimeElapsedQuery(tq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MetalDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
|
|
|
|
|
ASSERT_PRECONDITION(!isInRenderPass(mContext),
|
|
|
|
|
"endTimerQuery must be called outside of a render pass.");
|
|
|
|
|
auto* tq = handle_cast<MetalTimerQuery>(mHandleMap, tqh);
|
|
|
|
|
auto* tq = handle_cast<MetalTimerQuery>(tqh);
|
|
|
|
|
mContext->timerQueryImpl->endTimeElapsedQuery(tq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|