src/ngfx/porting/metal/MTLGraphicsContext.mm
Source code
/*
* Copyright 2020 GoPro Inc.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "ngfx/porting/metal/MTLGraphicsContext.h"
#include "ngfx/porting/metal/MTLSurface.h"
#include "ngfx/core/DebugUtil.h"
#include <Foundation/Foundation.h>
using namespace ngfx;
using namespace std;
void MTLGraphicsContext::create(const char* appName, bool enableDepthStencil, bool debug) {
this->enableDepthStencil = enableDepthStencil;
this->debug = debug;
mtlDevice.create();
mtlCommandQueue = [mtlDevice.v newCommandQueue];
}
MTLGraphicsContext::~MTLGraphicsContext() {}
void MTLGraphicsContext::setSurface(Surface *surface) {
defaultOffscreenSurfaceFormat = PixelFormat(MTLPixelFormatRGBA8Unorm);
MTLSurface *mtl_surface = mtl(surface);
MTKView *mtkView = nullptr;
if (surface && !surface->offscreen) {
offscreen = false;
NSView *view = mtl_surface->view;
if ([view class] == [MTKView class]) {
mtkView = (MTKView*)view;
mtkView.device = mtlDevice.v;
}
CAMetalLayer *layer = mtl_surface->getMetalLayer();
mtlSurfaceFormat = layer.pixelFormat;
surfaceFormat = PixelFormat(mtlSurfaceFormat);
} else {
offscreen = true;
surfaceFormat = defaultOffscreenSurfaceFormat;
}
if (surface && numSamples != 1) {
NGFX_TODO("");
}
if (surface && enableDepthStencil) {
depthFormat = PixelFormat(MTLPixelFormatDepth24Unorm_Stencil8);
if (!surface->offscreen && mtkView) mtkView.depthStencilPixelFormat = ::MTLPixelFormat(depthFormat);
else if (!surface->offscreen) {
mtl_surface->depthStencilTexture.reset(new MTLDepthStencilTexture);
mtl_surface->depthStencilTexture->create(this, mtl_surface->w, mtl_surface->h);
}
if (numSamples != 1) {
NGFX_TODO("");
}
}
std::optional<AttachmentDescription> depthAttachmentDescription;
if (enableDepthStencil) depthAttachmentDescription = { depthFormat };
else depthAttachmentDescription = nullopt;
if (surface && !surface->offscreen) {
RenderPassConfig onscreenRenderPassConfig = {
{ { surfaceFormat, IMAGE_LAYOUT_UNDEFINED, IMAGE_LAYOUT_PRESENT_SRC } },
depthAttachmentDescription, false, numSamples
};
mtlDefaultRenderPass = (MTLRenderPass*)getRenderPass(onscreenRenderPassConfig);
}
defaultOffscreenSurfaceFormat = PixelFormat(MTLPixelFormatRGBA8Unorm);
RenderPassConfig offscreenRenderPassConfig = {
{ { defaultOffscreenSurfaceFormat } }, depthAttachmentDescription, false, numSamples
};
mtlDefaultOffscreenRenderPass = (MTLRenderPass*)getRenderPass(offscreenRenderPassConfig);
if (surface && !surface->offscreen) {
CAMetalLayer* metalLayer = mtl_surface->getMetalLayer();
numSwapchainImages = metalLayer.maximumDrawableCount;
createSwapchainFramebuffers(metalLayer.drawableSize.width, metalLayer.drawableSize.height);
}
createBindings();
this->surface = surface;
}
RenderPass* MTLGraphicsContext::getRenderPass(RenderPassConfig config) {
for (auto& r : mtlRenderPassCache) {
if (r->config == config) return &r->mtlRenderPass;
}
auto renderPassData = make_unique<MTLRenderPassData>();
auto result = &renderPassData->mtlRenderPass;
mtlRenderPassCache.emplace_back(std::move(renderPassData));
return result;
}
void MTLGraphicsContext::createSwapchainFramebuffers(uint32_t w, uint32_t h) {
mtlSwapchainFramebuffers.resize(numSwapchainImages);
for (auto& fb : mtlSwapchainFramebuffers) {
fb.w = w;
fb.h = h;
}
}
void MTLGraphicsContext::createBindings() {
device = &mtlDevice;
pipelineCache = &mtlPipelineCache;
swapchainFramebuffers.resize(numSwapchainImages);
for (int j = 0; j<mtlSwapchainFramebuffers.size(); j++)
swapchainFramebuffers[j] = &mtlSwapchainFramebuffers[j];
defaultRenderPass = mtlDefaultRenderPass;
defaultOffscreenRenderPass = mtlDefaultOffscreenRenderPass;
}
CommandBuffer* MTLGraphicsContext::drawCommandBuffer(int32_t index) {
mtlDrawCommandBuffer.v = [mtlCommandQueue commandBuffer];
return &mtlDrawCommandBuffer;
}
CommandBuffer* MTLGraphicsContext::copyCommandBuffer() {
mtlCopyCommandBuffer.v = [mtlCommandQueue commandBuffer];
return &mtlCopyCommandBuffer;
}
CommandBuffer* MTLGraphicsContext::computeCommandBuffer() {
mtlComputeCommandBuffer.v = [mtlCommandQueue commandBuffer];
return &mtlComputeCommandBuffer;
}
void MTLGraphicsContext::submit(CommandBuffer* commandBuffer) {
auto mtlCommandBuffer = mtl(commandBuffer);
mtlCommandBuffer->commit();
if (commandBuffer == &mtlComputeCommandBuffer) {
mtlCommandBuffer->waitUntilCompleted();
}
}
GraphicsContext* GraphicsContext::create(const char* appName, bool enableDepthStencil, bool debug) {
NGFX_LOG("debug: %s", (debug)?"true": "false");
auto mtlGraphicsContext = new MTLGraphicsContext();
mtlGraphicsContext->create(appName, enableDepthStencil, debug);
return mtlGraphicsContext;
}
Updated on 3 April 2021 at 20:21:51 PDT