Vulkan: simplify management of "default" render target.
This commit is contained in:
@@ -39,8 +39,8 @@ struct BlitterUniforms {
|
||||
};
|
||||
|
||||
void VulkanBlitter::blitColor(BlitArgs args) {
|
||||
const VulkanAttachment src = args.srcTarget->getColor(mContext.currentSurface, args.targetIndex);
|
||||
const VulkanAttachment dst = args.dstTarget->getColor(mContext.currentSurface, 0);
|
||||
const VulkanAttachment src = args.srcTarget->getColor(args.targetIndex);
|
||||
const VulkanAttachment dst = args.dstTarget->getColor(0);
|
||||
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT
|
||||
@@ -58,14 +58,13 @@ void VulkanBlitter::blitColor(BlitArgs args) {
|
||||
}
|
||||
#endif
|
||||
|
||||
blitFast(aspect, args.filter, args.srcTarget->getExtent(mContext.currentSurface), src, dst,
|
||||
blitFast(aspect, args.filter, args.srcTarget->getExtent(), src, dst,
|
||||
args.srcRectPair, args.dstRectPair);
|
||||
}
|
||||
|
||||
void VulkanBlitter::blitDepth(BlitArgs args) {
|
||||
VulkanSwapChain* const sc = mContext.currentSurface;
|
||||
const VulkanAttachment src = args.srcTarget->getDepth(sc);
|
||||
const VulkanAttachment dst = args.dstTarget->getDepth(sc);
|
||||
const VulkanAttachment src = args.srcTarget->getDepth();
|
||||
const VulkanAttachment dst = args.dstTarget->getDepth();
|
||||
const VkImageAspectFlags aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
|
||||
#if FILAMENT_VULKAN_CHECK_BLIT_FORMAT
|
||||
@@ -86,12 +85,12 @@ void VulkanBlitter::blitDepth(BlitArgs args) {
|
||||
assert_invariant(src.texture && dst.texture);
|
||||
|
||||
if (src.texture->samples > 1 && dst.texture->samples == 1) {
|
||||
blitSlowDepth(aspect, args.filter, args.srcTarget->getExtent(sc), src, dst, args.srcRectPair,
|
||||
blitSlowDepth(aspect, args.filter, args.srcTarget->getExtent(), src, dst, args.srcRectPair,
|
||||
args.dstRectPair);
|
||||
return;
|
||||
}
|
||||
|
||||
blitFast(aspect, args.filter, args.srcTarget->getExtent(sc), src, dst, args.srcRectPair,
|
||||
blitFast(aspect, args.filter, args.srcTarget->getExtent(), src, dst, args.srcRectPair,
|
||||
args.dstRectPair);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ struct VulkanAttachment {
|
||||
VkImageView view;
|
||||
VkDeviceMemory memory;
|
||||
VulkanTexture* texture = nullptr;
|
||||
VkImageLayout layout;
|
||||
VkImageLayout layout; // TODO remove
|
||||
uint8_t level;
|
||||
uint16_t layer;
|
||||
};
|
||||
@@ -90,6 +90,7 @@ struct VulkanContext {
|
||||
bool maintenanceSupported[3] = {};
|
||||
VulkanPipelineCache::RasterState rasterState;
|
||||
VulkanSwapChain* currentSurface;
|
||||
Handle<HwRenderTarget> defaultRenderTarget;
|
||||
VulkanRenderPass currentRenderPass;
|
||||
VkViewport viewport;
|
||||
VkFormat finalDepthFormat;
|
||||
|
||||
@@ -322,6 +322,8 @@ void VulkanDriver::terminate() {
|
||||
delete mContext.commands;
|
||||
delete mContext.emptyTexture;
|
||||
|
||||
destruct<VulkanRenderTarget>(mContext.defaultRenderTarget);
|
||||
|
||||
mBlitter.shutdown();
|
||||
|
||||
// Allow the stage pool and disposer to clean up.
|
||||
@@ -519,10 +521,9 @@ void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
|
||||
}
|
||||
|
||||
void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int) {
|
||||
auto renderTarget = construct<VulkanRenderTarget>(rth, mContext);
|
||||
mDisposer.createDisposable(renderTarget, [this, rth] () {
|
||||
destruct<VulkanRenderTarget>(rth);
|
||||
});
|
||||
assert_invariant(!mContext.defaultRenderTarget);
|
||||
mContext.defaultRenderTarget = rth;
|
||||
construct<VulkanRenderTarget>(rth, mContext);
|
||||
}
|
||||
|
||||
void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
@@ -557,7 +558,10 @@ void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
|
||||
|
||||
void VulkanDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
|
||||
if (rth) {
|
||||
mDisposer.removeReference(handle_cast<VulkanRenderTarget*>(rth));
|
||||
if (UTILS_LIKELY(mContext.defaultRenderTarget != rth)) {
|
||||
VulkanRenderTarget* rt = handle_cast<VulkanRenderTarget*>(rth);
|
||||
mDisposer.removeReference(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -983,9 +987,8 @@ void VulkanDriver::updateSamplerGroup(Handle<HwSamplerGroup> sbh,
|
||||
void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassParams& params) {
|
||||
mCurrentRenderTarget = handle_cast<VulkanRenderTarget*>(rth);
|
||||
VulkanRenderTarget* const rt = mCurrentRenderTarget;
|
||||
VulkanSwapChain* const sc = mContext.currentSurface;
|
||||
|
||||
const VkExtent2D extent = rt->getExtent(sc);
|
||||
const VkExtent2D extent = rt->getExtent();
|
||||
assert_invariant(extent.width > 0 && extent.height > 0);
|
||||
|
||||
// Filament has the expectation that the contents of the swap chain are not preserved on the
|
||||
@@ -993,16 +996,16 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
// passes, due to multiple views.
|
||||
TargetBufferFlags discardStart = params.flags.discardStart;
|
||||
if (rt->isSwapChain()) {
|
||||
VulkanSwapChain* const sc = mContext.currentSurface;
|
||||
assert_invariant(sc);
|
||||
VulkanSwapChain& surface = *sc;
|
||||
if (surface.firstRenderPass) {
|
||||
if (sc->firstRenderPass) {
|
||||
discardStart |= TargetBufferFlags::COLOR;
|
||||
surface.firstRenderPass = false;
|
||||
sc->firstRenderPass = false;
|
||||
}
|
||||
}
|
||||
|
||||
const VkCommandBuffer cmdbuffer = mContext.commands->get().cmdbuffer;
|
||||
VulkanAttachment depth = rt->getSamples() == 1 ? rt->getDepth(sc) : rt->getMsaaDepth();
|
||||
VulkanAttachment depth = rt->getSamples() == 1 ? rt->getDepth() : rt->getMsaaDepth();
|
||||
VulkanTexture* depthFeedback = nullptr;
|
||||
|
||||
VulkanDepthLayout initialDepthLayout = fromVkImageLayout(depth.layout);
|
||||
@@ -1047,7 +1050,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
.subpassMask = uint8_t(params.subpassMask),
|
||||
};
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
const VulkanAttachment& info = rt->getColor(sc, i);
|
||||
const VulkanAttachment& info = rt->getColor(i);
|
||||
if (info.layout != VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||
rpkey.initialColorLayoutMask |= 1 << i;
|
||||
}
|
||||
@@ -1073,18 +1076,18 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
.samples = rpkey.samples,
|
||||
};
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
if (rt->getColor(sc, i).format == VK_FORMAT_UNDEFINED) {
|
||||
if (rt->getColor(i).format == VK_FORMAT_UNDEFINED) {
|
||||
fbkey.color[i] = VK_NULL_HANDLE;
|
||||
fbkey.resolve[i] = VK_NULL_HANDLE;
|
||||
} else if (fbkey.samples == 1) {
|
||||
fbkey.color[i] = rt->getColor(sc, i).view;
|
||||
fbkey.color[i] = rt->getColor(i).view;
|
||||
fbkey.resolve[i] = VK_NULL_HANDLE;
|
||||
assert_invariant(fbkey.color[i]);
|
||||
} else {
|
||||
fbkey.color[i] = rt->getMsaaColor(i).view;
|
||||
VulkanTexture* texture = rt->getColor(sc, i).texture;
|
||||
VulkanTexture* texture = rt->getColor(i).texture;
|
||||
if (texture && texture->samples == 1) {
|
||||
fbkey.resolve[i] = rt->getColor(sc, i).view;
|
||||
fbkey.resolve[i] = rt->getColor(i).view;
|
||||
assert_invariant(fbkey.resolve[i]);
|
||||
}
|
||||
assert_invariant(fbkey.color[i]);
|
||||
@@ -1112,7 +1115,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
mDisposer.acquire(rt);
|
||||
mDisposer.acquire(depth.texture);
|
||||
for (int i = 0; i < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
||||
mDisposer.acquire(rt->getColor(sc, i).texture);
|
||||
mDisposer.acquire(rt->getColor(i).texture);
|
||||
}
|
||||
|
||||
// Populate the structures required for vkCmdBeginRenderPass.
|
||||
@@ -1126,7 +1129,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
.renderArea = { .offset = {}, .extent = extent }
|
||||
};
|
||||
|
||||
rt->transformClientRectToPlatform(sc, &renderPassInfo.renderArea);
|
||||
rt->transformClientRectToPlatform(&renderPassInfo.renderArea);
|
||||
|
||||
VkClearValue clearValues[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT + MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT + 1] = {};
|
||||
|
||||
@@ -1165,7 +1168,7 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
|
||||
.maxDepth = params.depthRange.far
|
||||
};
|
||||
|
||||
mCurrentRenderTarget->transformClientRectToPlatform(sc, &viewport);
|
||||
mCurrentRenderTarget->transformClientRectToPlatform(&viewport);
|
||||
vkCmdSetViewport(cmdbuffer, 0, 1, &viewport);
|
||||
|
||||
mContext.currentRenderPass = {
|
||||
@@ -1188,10 +1191,7 @@ void VulkanDriver::endRenderPass(int) {
|
||||
// and notify the texture wrapper for proper tracking.
|
||||
VulkanTexture* depthFeedbackTexture = mContext.currentRenderPass.depthFeedback;
|
||||
if (depthFeedbackTexture) {
|
||||
|
||||
VulkanSwapChain* const sc = mContext.currentSurface;
|
||||
const VulkanAttachment& depth = mCurrentRenderTarget->getDepth(sc);
|
||||
|
||||
const VulkanAttachment& depth = mCurrentRenderTarget->getDepth();
|
||||
depthFeedbackTexture->trackLayout(depth.level, depth.layer,
|
||||
getDefaultImageLayout(TextureUsage::DEPTH_ATTACHMENT));
|
||||
}
|
||||
@@ -1251,7 +1251,7 @@ void VulkanDriver::nextSubpass(int) {
|
||||
|
||||
for (uint32_t i = 0; i < VulkanPipelineCache::TARGET_BINDING_COUNT; i++) {
|
||||
if ((1 << i) & mContext.currentRenderPass.subpassMask) {
|
||||
VulkanAttachment subpassInput = mCurrentRenderTarget->getColor(swapChain, i);
|
||||
VulkanAttachment subpassInput = mCurrentRenderTarget->getColor(i);
|
||||
VkDescriptorImageInfo info = {
|
||||
.imageView = subpassInput.view,
|
||||
.imageLayout = subpassInput.layout,
|
||||
@@ -1287,6 +1287,10 @@ void VulkanDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
|
||||
|
||||
// Leave early if the swap chain image has already been acquired but not yet presented.
|
||||
if (surf.acquired) {
|
||||
if (UTILS_LIKELY(mContext.defaultRenderTarget)) {
|
||||
VulkanRenderTarget* rt = handle_cast<VulkanRenderTarget*>(mContext.defaultRenderTarget);
|
||||
rt->bindToSwapChain(surf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1299,6 +1303,11 @@ void VulkanDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain>
|
||||
// Call vkAcquireNextImageKHR and insert its signal semaphore into the command manager's
|
||||
// dependency chain.
|
||||
surf.acquire();
|
||||
|
||||
if (UTILS_LIKELY(mContext.defaultRenderTarget)) {
|
||||
VulkanRenderTarget* rt = handle_cast<VulkanRenderTarget*>(mContext.defaultRenderTarget);
|
||||
rt->bindToSwapChain(surf);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanDriver::commit(Handle<HwSwapChain> sch) {
|
||||
@@ -1425,7 +1434,7 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
|
||||
uint32_t width, uint32_t height, PixelBufferDescriptor&& pbd) {
|
||||
const VkDevice device = mContext.device;
|
||||
VulkanRenderTarget* srcTarget = handle_cast<VulkanRenderTarget*>(src);
|
||||
VulkanTexture* srcTexture = srcTarget->getColor(mContext.currentSurface, 0).texture;
|
||||
VulkanTexture* srcTexture = srcTarget->getColor(0).texture;
|
||||
assert_invariant(srcTexture);
|
||||
const VkFormat srcFormat = srcTexture->getVkFormat();
|
||||
const bool swizzle = srcFormat == VK_FORMAT_B8G8R8A8_UNORM;
|
||||
@@ -1487,7 +1496,7 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
});
|
||||
|
||||
const VulkanAttachment srcAttachment = srcTarget->getColor(mContext.currentSurface, 0);
|
||||
const VulkanAttachment srcAttachment = srcTarget->getColor(0);
|
||||
|
||||
VkImageCopy imageCopyRegion = {
|
||||
.srcSubresource = {
|
||||
@@ -1498,7 +1507,7 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
|
||||
},
|
||||
.srcOffset = {
|
||||
.x = (int32_t) x,
|
||||
.y = (int32_t) (srcTarget->getExtent(mContext.currentSurface).height - (height + y)),
|
||||
.y = (int32_t) (srcTarget->getExtent().height - (height + y)),
|
||||
},
|
||||
.dstSubresource = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
@@ -1526,7 +1535,7 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
|
||||
// Perform the copy into the staging area. At this point we know that the src layout is
|
||||
// TRANSFER_SRC_OPTIMAL and the staging area is GENERAL.
|
||||
|
||||
vkCmdCopyImage(cmdbuffer, srcTarget->getColor(mContext.currentSurface, 0).image,
|
||||
vkCmdCopyImage(cmdbuffer, srcTarget->getColor(0).image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingImage, VK_IMAGE_LAYOUT_GENERAL,
|
||||
1, &imageCopyRegion);
|
||||
|
||||
@@ -1592,14 +1601,14 @@ void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, V
|
||||
|
||||
VkFilter vkfilter = filter == SamplerMagFilter::NEAREST ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
|
||||
|
||||
const VkExtent2D srcExtent = srcTarget->getExtent(mContext.currentSurface);
|
||||
const VkExtent2D srcExtent = srcTarget->getExtent();
|
||||
const int32_t srcLeft = std::min(srcRect.left, (int32_t) srcExtent.width);
|
||||
const int32_t srcBottom = std::min(srcRect.bottom, (int32_t) srcExtent.height);
|
||||
const int32_t srcRight = std::min(srcRect.left + srcRect.width, srcExtent.width);
|
||||
const int32_t srcTop = std::min(srcRect.bottom + srcRect.height, srcExtent.height);
|
||||
const VkOffset3D srcOffsets[2] = { { srcLeft, srcBottom, 0 }, { srcRight, srcTop, 1 }};
|
||||
|
||||
const VkExtent2D dstExtent = dstTarget->getExtent(mContext.currentSurface);
|
||||
const VkExtent2D dstExtent = dstTarget->getExtent();
|
||||
const int32_t dstLeft = std::min(dstRect.left, (int32_t) dstExtent.width);
|
||||
const int32_t dstBottom = std::min(dstRect.bottom, (int32_t) dstExtent.height);
|
||||
const int32_t dstRight = std::min(dstRect.left + dstRect.width, dstExtent.width);
|
||||
@@ -1817,7 +1826,7 @@ void VulkanDriver::draw(PipelineState pipelineState, Handle<HwRenderPrimitive> r
|
||||
.extent = { (uint32_t)right - x, (uint32_t)top - y }
|
||||
};
|
||||
|
||||
rt->transformClientRectToPlatform(mContext.currentSurface, &scissor);
|
||||
rt->transformClientRectToPlatform(&scissor);
|
||||
mPipelineCache.bindScissor(cmdbuffer, scissor);
|
||||
|
||||
// Bind a new pipeline if the pipeline state changed.
|
||||
|
||||
@@ -112,10 +112,17 @@ static VulkanAttachment createAttachment(VulkanContext& context, VulkanAttachmen
|
||||
}
|
||||
|
||||
// Creates a special "default" render target (i.e. associated with the swap chain)
|
||||
// Note that the attachment structs are unused in this case in favor of VulkanSwapChain.
|
||||
VulkanRenderTarget::VulkanRenderTarget(VulkanContext& context) : HwRenderTarget(0, 0),
|
||||
mOffscreen(false), mSamples(1) {}
|
||||
|
||||
void VulkanRenderTarget::bindToSwapChain(VulkanSwapChain& swapChain) {
|
||||
assert_invariant(!mOffscreen);
|
||||
mColor[0] = swapChain.getColorAttachment();
|
||||
mDepth = swapChain.getDepthAttachment();
|
||||
width = swapChain.clientSize.width;
|
||||
height = swapChain.clientSize.height;
|
||||
}
|
||||
|
||||
VulkanRenderTarget::VulkanRenderTarget(VulkanContext& context, uint32_t width, uint32_t height,
|
||||
uint8_t samples, VulkanAttachment color[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT],
|
||||
VulkanAttachment depthStencil[2], VulkanStagePool& stagePool) :
|
||||
@@ -209,33 +216,30 @@ VulkanRenderTarget::VulkanRenderTarget(VulkanContext& context, uint32_t width, u
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
}
|
||||
|
||||
void VulkanRenderTarget::transformClientRectToPlatform(VulkanSwapChain* currentSurface, VkRect2D* bounds) const {
|
||||
const auto& extent = getExtent(currentSurface);
|
||||
void VulkanRenderTarget::transformClientRectToPlatform(VkRect2D* bounds) const {
|
||||
const auto& extent = getExtent();
|
||||
flipVertically(bounds, extent.height);
|
||||
clampToFramebuffer(bounds, extent.width, extent.height);
|
||||
}
|
||||
|
||||
void VulkanRenderTarget::transformClientRectToPlatform(VulkanSwapChain* currentSurface, VkViewport* bounds) const {
|
||||
flipVertically(bounds, getExtent(currentSurface).height);
|
||||
void VulkanRenderTarget::transformClientRectToPlatform(VkViewport* bounds) const {
|
||||
flipVertically(bounds, getExtent().height);
|
||||
}
|
||||
|
||||
VkExtent2D VulkanRenderTarget::getExtent(VulkanSwapChain* currentSurface) const {
|
||||
if (mOffscreen) {
|
||||
return {width, height};
|
||||
}
|
||||
return currentSurface->clientSize;
|
||||
VkExtent2D VulkanRenderTarget::getExtent() const {
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
VulkanAttachment VulkanRenderTarget::getColor(VulkanSwapChain* currentSurface, int target) const {
|
||||
return (mOffscreen || target > 0) ? mColor[target] : currentSurface->getColorAttachment();
|
||||
VulkanAttachment VulkanRenderTarget::getColor(int target) const {
|
||||
return mColor[target];
|
||||
}
|
||||
|
||||
VulkanAttachment VulkanRenderTarget::getMsaaColor(int target) const {
|
||||
return mMsaaAttachments[target];
|
||||
}
|
||||
|
||||
VulkanAttachment VulkanRenderTarget::getDepth(VulkanSwapChain* currentSurface) const {
|
||||
return mOffscreen ? mDepth : currentSurface->getDepthAttachment();
|
||||
VulkanAttachment VulkanRenderTarget::getDepth() const {
|
||||
return mDepth;
|
||||
}
|
||||
|
||||
VulkanAttachment VulkanRenderTarget::getMsaaDepth() const {
|
||||
|
||||
@@ -53,17 +53,18 @@ struct VulkanRenderTarget : private HwRenderTarget {
|
||||
// Creates a special "default" render target (i.e. associated with the swap chain)
|
||||
explicit VulkanRenderTarget(VulkanContext& context);
|
||||
|
||||
void transformClientRectToPlatform(VulkanSwapChain* currentSurface, VkRect2D* bounds) const;
|
||||
void transformClientRectToPlatform(VulkanSwapChain* currentSurface, VkViewport* bounds) const;
|
||||
VkExtent2D getExtent(VulkanSwapChain* currentSurface) const;
|
||||
VulkanAttachment getColor(VulkanSwapChain* currentSurface, int target) const;
|
||||
void transformClientRectToPlatform(VkRect2D* bounds) const;
|
||||
void transformClientRectToPlatform(VkViewport* bounds) const;
|
||||
VkExtent2D getExtent() const;
|
||||
VulkanAttachment getColor(int target) const;
|
||||
VulkanAttachment getMsaaColor(int target) const;
|
||||
VulkanAttachment getDepth(VulkanSwapChain* currentSurface) const;
|
||||
VulkanAttachment getDepth() const;
|
||||
VulkanAttachment getMsaaDepth() const;
|
||||
int getColorTargetCount(const VulkanRenderPass& pass) const;
|
||||
uint8_t getSamples() const { return mSamples; }
|
||||
bool hasDepth() const { return mDepth.format != VK_FORMAT_UNDEFINED; }
|
||||
bool isSwapChain() const { return !mOffscreen; }
|
||||
void bindToSwapChain(VulkanSwapChain& surf);
|
||||
|
||||
private:
|
||||
VulkanAttachment mColor[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
||||
|
||||
Reference in New Issue
Block a user