Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Engine/gapi/abstractgraphicsapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,11 @@ std::shared_ptr<AbstractGraphicsApi::Fence> AbstractGraphicsApi::submit(Device*
NonUniqResId AbstractGraphicsApi::Swapchain::syncId() const {
return NonUniqResId(0x1);
}

AbstractGraphicsApi::PSwapchainImage AbstractGraphicsApi::Swapchain::next() {
throw std::system_error(GraphicsErrc::UnsupportedExtension);
}

void AbstractGraphicsApi::present(Device*, SwapchainImage*) {
throw std::system_error(GraphicsErrc::UnsupportedExtension);
}
12 changes: 12 additions & 0 deletions Engine/gapi/abstractgraphicsapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,15 @@ namespace Tempest {

virtual void setPayload(std::vector<Detail::DSharedPtr<const AbstractGraphicsApi::Shared*>>&&) {}
};
struct SwapchainImage:Shared {
SwapchainImage(Device& device, uint32_t w, uint32_t h):device(device),width(w),height(h) {}

Device& device;
const uint32_t width;
const uint32_t height;
};
using PSwapchainImage = Detail::DSharedPtr<SwapchainImage*>;

struct Swapchain:NoCopy {
virtual ~Swapchain()=default;
virtual void reset()=0;
Expand All @@ -527,6 +536,7 @@ namespace Tempest {
virtual uint32_t imageCount() const=0;
virtual uint32_t w() const=0;
virtual uint32_t h() const=0;
virtual PSwapchainImage next();
};
struct Texture:Shared {
virtual uint32_t mipCount() const = 0;
Expand Down Expand Up @@ -663,6 +673,7 @@ namespace Tempest {
virtual void readBytes (Device* d, Buffer* buf, void* out, size_t size) = 0;

virtual void present(Device *d, Swapchain* sw) = 0;
virtual void present(Device *d, SwapchainImage* image);
virtual auto submit (Device *d, CommandBuffer* cmd) -> std::shared_ptr<AbstractGraphicsApi::Fence> = 0;

virtual void getCaps(Device *d, Props& caps)=0;
Expand All @@ -689,6 +700,7 @@ namespace Detail {
AttachmentDesc desc [MaxFramebufferAttachments+1] = {};
AbstractGraphicsApi::Texture* att [MaxFramebufferAttachments+1] = {};
AbstractGraphicsApi::Swapchain* sw [MaxFramebufferAttachments+1] = {};
AbstractGraphicsApi::SwapchainImage* image[MaxFramebufferAttachments+1] = {};
uint32_t imgId[MaxFramebufferAttachments+1] = {};
};

Expand Down
16 changes: 14 additions & 2 deletions Engine/gapi/metal/mtcommandbuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "mttexture.h"
#include "mtswapchain.h"
#include "mtaccelerationstructure.h"
#include <QuartzCore/QuartzCore.hpp>

using namespace Tempest;
using namespace Tempest::Detail;
Expand Down Expand Up @@ -65,6 +66,7 @@ void MtCommandBuffer::end() {
}

void MtCommandBuffer::reset() {
swapchainImages.clear();
auto pool = NsPtr<NS::AutoreleasePool>::init();
auto desc = NsPtr<MTL::CommandBufferDescriptor>::init();
desc->setRetainedReferences(false);
Expand Down Expand Up @@ -92,9 +94,19 @@ void MtCommandBuffer::beginRendering(const FrameBufferDesc& fbo, size_t fboSize,
continue;
}
auto clr = desc->colorAttachments()->object(i);
if(fbo.sw[i]!=nullptr) {
if(fbo.image[i]!=nullptr) {
auto& image = *static_cast<MtSwapchainImage*>(fbo.image[i]);
if(&image.device!=&device)
throw std::system_error(GraphicsErrc::InvalidTexture);
auto* texture = image.drawable->texture();
clr->setTexture(texture);
curFbo.colorFormat[curFbo.numColors] = texture->pixelFormat();
auto found = std::find_if(swapchainImages.begin(),swapchainImages.end(),[&](const auto& i){ return i.handler==&image; });
if(found==swapchainImages.end())
swapchainImages.emplace_back(&image);
} else if(fbo.sw[i]!=nullptr) {
auto& s = *reinterpret_cast<MtSwapchain*>(fbo.sw[i]);
clr->setTexture(s.img[fbo.imgId[i]].tex.get());
clr->setTexture(s.image(fbo.imgId[i]));
curFbo.colorFormat[curFbo.numColors] = s.format();
} else {
auto& t = *reinterpret_cast<MtTexture*>(fbo.att[i]);
Expand Down
1 change: 1 addition & 0 deletions Engine/gapi/metal/mtcommandbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class MtCommandBuffer : public AbstractGraphicsApi::CommandBuffer {
NsPtr<MTL::BlitCommandEncoder> encBlit;

std::vector<const void*> usedResources;
std::vector<AbstractGraphicsApi::PSwapchainImage> swapchainImages;

MtFboLayout curFbo;
Push pushData;
Expand Down
14 changes: 12 additions & 2 deletions Engine/gapi/metal/mtswapchain.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#pragma once

#include <Tempest/AbstractGraphicsApi>
#include "utility/spinlock.h"
#include "nsptr.h"

#include <Metal/Metal.hpp>
#include <mutex>

namespace CA
{
Expand All @@ -16,6 +16,13 @@ namespace Detail {

class MtDevice;

struct MtSwapchainImage : AbstractGraphicsApi::SwapchainImage {
MtSwapchainImage(MtDevice& device, CA::MetalDrawable* drawable);
~MtSwapchainImage();

NsPtr<CA::MetalDrawable> drawable;
};

class MtSwapchain : public AbstractGraphicsApi::Swapchain {
public:
MtSwapchain(MtDevice& dev, SystemApi::Window* w);
Expand All @@ -27,6 +34,9 @@ class MtSwapchain : public AbstractGraphicsApi::Swapchain {
uint32_t w() const override;
uint32_t h() const override;
void present();
AbstractGraphicsApi::PSwapchainImage next() override;
MTL::Texture* image(uint32_t id);
static void present(MtDevice& device, MtSwapchainImage& image);
NonUniqResId syncId() const override { return NonUniqResId::I_None; }

MTL::PixelFormat format() const;
Expand All @@ -40,7 +50,7 @@ class MtSwapchain : public AbstractGraphicsApi::Swapchain {
struct Impl;
std::unique_ptr<Impl> pimpl;

SpinLock sync;
std::mutex sync;
MtDevice& dev;
Tempest::Size sz;

Expand Down
75 changes: 54 additions & 21 deletions Engine/gapi/metal/mtswapchain.mm
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ - (CALayer *)makeBackingLayer {
}
};

MtSwapchainImage::MtSwapchainImage(MtDevice& device, CA::MetalDrawable* drawable)
:SwapchainImage(device,uint32_t(drawable->texture()->width()),uint32_t(drawable->texture()->height())),
drawable(drawable) {
drawable->retain();
}

MtSwapchainImage::~MtSwapchainImage() {
}

static float backingScaleFactor(SysWindow* w) {
#if defined(__OSX__)
return [w screen].backingScaleFactor;
Expand Down Expand Up @@ -93,7 +102,7 @@ static CGRect windowRect(UIWindow* wnd) {

// note : MoltenVK supports NSView, UIView, CAMetalLayer, so we should align to it
MtSwapchain::MtSwapchain(MtDevice& dev, SystemApi::Window *w)
:dev(dev), pimpl(new Impl()) {
:pimpl(new Impl()), dev(dev) {
NSObject* obj = reinterpret_cast<NSObject*>(w);
if([obj isKindOfClass : [SysWindow class]])
pimpl->wnd = reinterpret_cast<SysWindow*>(w);
Expand Down Expand Up @@ -127,13 +136,14 @@ static CGRect windowRect(UIWindow* wnd) {
}

MtSwapchain::~MtSwapchain() {
dev.waitIdle();
if(pimpl->view!=nil)
[pimpl->view release];
}

void MtSwapchain::reset() {
dev.waitIdle(); // pending commands
std::lock_guard<SpinLock> guard(sync);
std::lock_guard<std::mutex> guard(sync);

// https://developer.apple.com/documentation/quartzcore/cametallayer?language=objc
CAMetalLayer* lay = pimpl->metalLayer();
Expand All @@ -146,8 +156,6 @@ static CGRect windowRect(UIWindow* wnd) {
img.resize(imgCount);
for(size_t i=0; i<imgCount; ++i)
img[i].tex = nullptr;
for(size_t i=0; i<imgCount; ++i)
img[i].tex = mkTexture();

currentImg = 0;
}
Expand All @@ -156,18 +164,54 @@ static CGRect windowRect(UIWindow* wnd) {
return currentImg;
}

AbstractGraphicsApi::PSwapchainImage MtSwapchain::next() {
std::lock_guard<std::mutex> guard(sync);
if(sz.w<=0 || sz.h<=0)
throw SwapchainSuboptimal();
auto pool = NsPtr<NS::AutoreleasePool>::init();
auto* layer = reinterpret_cast<CA::MetalLayer*>(pimpl->metalLayer());
pimpl->metalLayer().allowsNextDrawableTimeout = YES;
auto* drawable = layer->nextDrawable();
if(drawable==nullptr || drawable->texture()->width()!=size_t(sz.w) || drawable->texture()->height()!=size_t(sz.h))
throw SwapchainSuboptimal();
return AbstractGraphicsApi::PSwapchainImage(new MtSwapchainImage(dev,drawable));
}

MTL::Texture* MtSwapchain::image(uint32_t id) {
// Keep private textures only for callers of the indexed swapchain API.
if(img[id].tex==nullptr)
img[id].tex = mkTexture();
return img[id].tex.get();
}

void MtSwapchain::present(MtDevice& device, MtSwapchainImage& image) {
auto pool = NsPtr<NS::AutoreleasePool>::init();
auto cmd = device.queue->commandBuffer();
cmd->presentDrawable(image.drawable.get());
auto* dev = &device;
dev->onSubmit();
cmd->addCompletedHandler(^(MTL::CommandBuffer* c){
if(c->status()!=MTL::CommandBufferStatusCompleted)
Log::e("swapchain fatal error");
dev->onFinish();
});
cmd->commit();
}

void MtSwapchain::present() {
auto pool = NsPtr<NS::AutoreleasePool>::init();

CA::MetalLayer* lay = reinterpret_cast<CA::MetalLayer*>(pimpl->metalLayer());
uint32_t i = currentImg;
pimpl->metalLayer().allowsNextDrawableTimeout = NO;
auto drawable = lay->nextDrawable();
if(drawable==nullptr)
throw SwapchainSuboptimal();

std::lock_guard<SpinLock> guard(sync);
std::lock_guard<std::mutex> guard(sync);
auto src = image(i);
auto dr = drawable->texture();
if(dr->width()!=img[i].tex->width() || dr->height()!=img[i].tex->height()) {
if(dr->width()!=src->width() || dr->height()!=src->height()) {
throw SwapchainSuboptimal();
}

Expand All @@ -178,29 +222,18 @@ static CGRect windowRect(UIWindow* wnd) {
auto cmd = dev.queue->commandBuffer(desc.get());
auto enc = cmd->blitCommandEncoder();

enc->copyFromTexture(img[i].tex.get(), 0, 0,
enc->copyFromTexture(src, 0, 0,
dr, 0, 0,
1, 1);
enc->endEncoding();
cmd->presentDrawable(drawable);

auto* device = &dev;
dev.onSubmit();
cmd->addCompletedHandler(^(MTL::CommandBuffer* c){
MTL::CommandBufferStatus s = c->status();
if(s==MTL::CommandBufferStatusNotEnqueued ||
s==MTL::CommandBufferStatusEnqueued ||
s==MTL::CommandBufferStatusCommitted ||
s==MTL::CommandBufferStatusScheduled)
return;

if(s!=MTL::CommandBufferStatusCompleted) {
if(c->status()!=MTL::CommandBufferStatusCompleted)
Log::e("swapchain fatal error");
dev.onFinish();
dev.waitIdle();
return;
}

dev.onFinish();
device->onFinish();
});
cmd->commit();

Expand Down
14 changes: 13 additions & 1 deletion Engine/gapi/metalapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ void MetalApi::present(AbstractGraphicsApi::Device*, AbstractGraphicsApi::Swapch
s.present();
}

void MetalApi::present(Device* d, SwapchainImage* image) {
auto& device = *static_cast<MtDevice*>(d);
MtSwapchain::present(device,*static_cast<MtSwapchainImage*>(image));
}

std::shared_ptr<AbstractGraphicsApi::Fence> MetalApi::submit(Device* d, CommandBuffer* c) {
auto* dx = reinterpret_cast<MtDevice*>(d);
auto& cx = *reinterpret_cast<MtCommandBuffer*>(c);
Expand All @@ -203,10 +208,17 @@ std::shared_ptr<AbstractGraphicsApi::Fence> MetalApi::submit(Device* d, CommandB
throw DeviceLostException();

MTL::CommandBuffer& cmd = *cx.impl;
std::shared_ptr<std::vector<PSwapchainImage>> images;
if(!cx.swapchainImages.empty())
images = std::make_shared<std::vector<PSwapchainImage>>(std::move(cx.swapchainImages));
dx->onSubmit();
cmd.addCompletedHandler(^(MTL::CommandBuffer* c){
if(images!=nullptr)
images->clear();
const MTL::CommandBufferStatus s = c->status();
dx->signalFence(*pfence, s, MTL::CommandBufferError(c->error()->code()), c->error());
auto* error = c->error();
auto code = error==nullptr ? MTL::CommandBufferError(0) : MTL::CommandBufferError(error->code());
dx->signalFence(*pfence, s, code, error);
if(s==MTL::CommandBufferStatusCompleted || s==MTL::CommandBufferStatusError)
dx->onFinish();
});
Expand Down
1 change: 1 addition & 0 deletions Engine/gapi/metalapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class MetalApi : public AbstractGraphicsApi {
CommandBuffer* createCommandBuffer(Device* d) override;

void present(Device *d, Swapchain* sw) override;
void present(Device *d, SwapchainImage* image) override;
auto submit (Device *d, CommandBuffer* cmd) -> std::shared_ptr<AbstractGraphicsApi::Fence> override;

void getCaps(Device *d, Props& caps) override;
Expand Down
23 changes: 22 additions & 1 deletion Engine/graphics/attachment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,53 @@

using namespace Tempest;

Attachment::Attachment(Attachment&& other)
:tImpl(std::move(other.tImpl)),sImpl(other.sImpl),pImpl(std::move(other.pImpl)) {
other.sImpl = {};
}

Attachment& Attachment::operator=(Attachment&& other) {
Attachment tmp(std::move(other));
std::swap(tImpl,tmp.tImpl);
std::swap(sImpl,tmp.sImpl);
std::swap(pImpl,tmp.pImpl);
return *this;
}

Attachment::Attachment(AbstractGraphicsApi::Swapchain* sw, uint32_t id) {
sImpl.swapchain = sw;
sImpl.id = id;
}

int Attachment::w() const {
if(pImpl)
return int(pImpl.handler->width);
if(sImpl.swapchain)
return int(sImpl.swapchain->w());
return tImpl.w();
}

int Attachment::h() const {
if(pImpl)
return int(pImpl.handler->height);
if(sImpl.swapchain)
return int(sImpl.swapchain->h());
return tImpl.h();
}

Size Attachment::size() const {
if(pImpl)
return Size(int(pImpl.handler->width),int(pImpl.handler->height));
if(sImpl.swapchain)
return Size(int(sImpl.swapchain->w()),int(sImpl.swapchain->h()));
return tImpl.size();
}

bool Attachment::isEmpty() const {
if(pImpl)
return false;
if(sImpl.swapchain)
return int(sImpl.swapchain->w()> 0 && sImpl.swapchain->h()>0);
return sImpl.swapchain->w()==0 || sImpl.swapchain->h()==0;
return tImpl.isEmpty();
}

Loading
Loading