video_core: Cleanup surface interface

* Remove unused FramebufferView and make the opengl handles private
This commit is contained in:
GPUCode
2023-02-15 15:38:49 +02:00
parent c7d315058e
commit e67a4a739a
6 changed files with 67 additions and 111 deletions

View File

@ -40,14 +40,14 @@ void D24S8toRGBA8::Reinterpret(const Surface& source, VideoCore::Rect2D src_rect
SCOPE_EXIT({ prev_state.Apply(); });
OpenGLState state;
state.texture_units[0].texture_2d = source.texture.handle;
state.texture_units[0].texture_2d = source.Handle();
// Use glTextureView on desktop to avoid intermediate copy
if (use_texture_view) {
temp_tex.Create();
glActiveTexture(GL_TEXTURE1);
glTextureView(temp_tex.handle, GL_TEXTURE_2D, source.texture.handle, GL_DEPTH24_STENCIL8, 0,
1, 0, 1);
glTextureView(temp_tex.handle, GL_TEXTURE_2D, source.Handle(), GL_DEPTH24_STENCIL8, 0, 1, 0,
1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else {
@ -66,12 +66,12 @@ void D24S8toRGBA8::Reinterpret(const Surface& source, VideoCore::Rect2D src_rect
state.draw.shader_program = program.handle;
state.Apply();
glBindImageTexture(2, dest.texture.handle, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
glBindImageTexture(2, dest.Handle(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
glActiveTexture(GL_TEXTURE1);
if (!use_texture_view) {
glCopyImageSubData(source.texture.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom,
0, temp_tex.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0,
glCopyImageSubData(source.Handle(), GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0,
temp_tex.handle, GL_TEXTURE_2D, 0, src_rect.left, src_rect.bottom, 0,
src_rect.GetWidth(), src_rect.GetHeight(), 1);
}
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
@ -143,7 +143,7 @@ void RGBA4toRGB5A1::Reinterpret(const Surface& source, VideoCore::Rect2D src_rec
SCOPE_EXIT({ prev_state.Apply(); });
OpenGLState state;
state.texture_units[0].texture_2d = source.texture.handle;
state.texture_units[0].texture_2d = source.Handle();
state.draw.draw_framebuffer = draw_fbo.handle;
state.draw.shader_program = program.handle;
state.draw.vertex_array = vao.handle;
@ -152,8 +152,8 @@ void RGBA4toRGB5A1::Reinterpret(const Surface& source, VideoCore::Rect2D src_rec
static_cast<GLsizei>(dst_rect.GetHeight())};
state.Apply();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
dest.texture.handle, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dest.Handle(),
0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
glUniform2i(dst_size_loc, dst_rect.GetWidth(), dst_rect.GetHeight());

View File

@ -412,7 +412,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
auto surface = res_cache.GetTextureSurface(info);
if (surface != nullptr) {
target = surface->texture.handle;
target = surface->Handle();
} else {
target = 0;
}
@ -431,7 +431,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
case TextureType::Shadow2D: {
const auto surface = res_cache.GetTextureSurface(texture);
if (surface) {
state.image_shadow_texture_px = surface->texture.handle;
state.image_shadow_texture_px = surface->Handle();
} else {
state.image_shadow_texture_px = 0;
}
@ -463,7 +463,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
.format = texture.format};
state.texture_cube_unit.texture_cube =
res_cache.GetTextureCube(config)->texture.handle;
res_cache.GetTextureCube(config)->Handle();
state.texture_cube_unit.sampler = sampler.Handle();
state.texture_units[texture_index].texture_2d = 0;
@ -480,7 +480,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
auto surface = res_cache.GetTextureSurface(texture);
if (surface != nullptr) {
state.texture_units[texture_index].texture_2d = surface->texture.handle;
state.texture_units[texture_index].texture_2d = surface->Handle();
} else {
// Can occur when texture addr is null or its memory is unmapped/invalid
// HACK: In this case, the correct behaviour for the PICA is to use the last
@ -688,14 +688,14 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
return false;
}
u32 scaled_width = src_surface->GetScaledWidth();
u32 scaled_height = src_surface->GetScaledHeight();
const u32 scaled_width = src_surface->GetScaledWidth();
const u32 scaled_height = src_surface->GetScaledHeight();
screen_info.display_texcoords = Common::Rectangle<float>(
(float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
(float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
screen_info.display_texture = src_surface->texture.handle;
screen_info.display_texture = src_surface->Handle();
return true;
}

View File

@ -81,6 +81,8 @@ TextureRuntime::TextureRuntime(Driver& driver)
Register(VideoCore::PixelFormat::RGB5A1, std::make_unique<RGBA4toRGB5A1>());
}
TextureRuntime::~TextureRuntime() = default;
StagingData TextureRuntime::FindStaging(u32 size, bool upload) {
if (!upload) {
if (size > download_buffer.size()) {
@ -171,13 +173,12 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
state.draw.draw_framebuffer = draw_fbo.handle;
state.Apply();
GLint handle = surface.texture.handle;
switch (surface.type) {
case VideoCore::SurfaceType::Color:
case VideoCore::SurfaceType::Texture:
case VideoCore::SurfaceType::Fill:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle,
clear.texture_level);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
surface.Handle(), clear.texture_level);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
0);
@ -191,8 +192,8 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
break;
case VideoCore::SurfaceType::Depth:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, handle,
clear.texture_level);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
surface.Handle(), clear.texture_level);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
state.depth.write_mask = GL_TRUE;
@ -203,7 +204,7 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
case VideoCore::SurfaceType::DepthStencil:
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
handle, clear.texture_level);
surface.Handle(), clear.texture_level);
state.depth.write_mask = GL_TRUE;
state.stencil.write_mask = -1;
@ -224,8 +225,8 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
source.texture_type == TextureType::CubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
const GLenum dst_textarget =
dest.texture_type == TextureType::CubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
glCopyImageSubData(source.texture.handle, src_textarget, copy.src_level, copy.src_offset.x,
copy.src_offset.y, copy.src_layer, dest.texture.handle, dst_textarget,
glCopyImageSubData(source.Handle(), src_textarget, copy.src_level, copy.src_offset.x,
copy.src_offset.y, copy.src_layer, dest.Handle(), dst_textarget,
copy.dst_level, copy.dst_offset.x, copy.dst_offset.y, copy.dst_layer,
copy.extent.width, copy.extent.height, 1);
return true;
@ -245,12 +246,12 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
? GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.src_layer
: GL_TEXTURE_2D;
BindFramebuffer(GL_READ_FRAMEBUFFER, blit.src_level, src_textarget, source.type,
source.texture);
source.Handle());
const GLenum dst_textarget = dest.texture_type == TextureType::CubeMap
? GL_TEXTURE_CUBE_MAP_POSITIVE_X + blit.dst_layer
: GL_TEXTURE_2D;
BindFramebuffer(GL_DRAW_FRAMEBUFFER, blit.dst_level, dst_textarget, dest.type, dest.texture);
BindFramebuffer(GL_DRAW_FRAMEBUFFER, blit.dst_level, dst_textarget, dest.type, dest.Handle());
// TODO (wwylele): use GL_NEAREST for shadow map texture
// Note: shadow map is treated as RGBA8 format in PICA, as well as in the rasterizer cache, but
@ -271,7 +272,7 @@ void TextureRuntime::GenerateMipmaps(Surface& surface, u32 max_level) {
SCOPE_EXIT({ prev_state.Apply(); });
OpenGLState state{};
state.texture_units[0].texture_2d = surface.texture.handle;
state.texture_units[0].texture_2d = surface.Handle();
state.Apply();
glActiveTexture(GL_TEXTURE0);
@ -290,25 +291,24 @@ bool TextureRuntime::NeedsConvertion(VideoCore::PixelFormat format) const {
}
void TextureRuntime::BindFramebuffer(GLenum target, GLint level, GLenum textarget,
VideoCore::SurfaceType type, OGLTexture& texture) const {
VideoCore::SurfaceType type, GLuint handle) const {
const GLint framebuffer = target == GL_DRAW_FRAMEBUFFER ? draw_fbo.handle : read_fbo.handle;
glBindFramebuffer(target, framebuffer);
switch (type) {
case VideoCore::SurfaceType::Color:
case VideoCore::SurfaceType::Texture:
glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, textarget, texture.handle, level);
glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, textarget, handle, level);
glFramebufferTexture2D(target, GL_DEPTH_STENCIL_ATTACHMENT, textarget, 0, 0);
break;
case VideoCore::SurfaceType::Depth:
glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, textarget, 0, 0);
glFramebufferTexture2D(target, GL_DEPTH_ATTACHMENT, textarget, texture.handle, level);
glFramebufferTexture2D(target, GL_DEPTH_ATTACHMENT, textarget, handle, level);
glFramebufferTexture2D(target, GL_STENCIL_ATTACHMENT, textarget, 0, 0);
break;
case VideoCore::SurfaceType::DepthStencil:
glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, textarget, 0, 0);
glFramebufferTexture2D(target, GL_DEPTH_STENCIL_ATTACHMENT, textarget, texture.handle,
level);
glFramebufferTexture2D(target, GL_DEPTH_STENCIL_ATTACHMENT, textarget, handle, level);
break;
default:
UNREACHABLE_MSG("Invalid surface type!");
@ -381,7 +381,7 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(rect.GetWidth()));
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
texture);
texture.handle);
const auto& tuple = runtime.GetFormatTuple(pixel_format);
glReadPixels(rect.left, rect.bottom, rect.GetWidth(), rect.GetHeight(), tuple.format,
@ -455,7 +455,7 @@ void Surface::ScaledDownload(const VideoCore::BufferTextureCopy& download,
const auto& tuple = runtime.GetFormatTuple(pixel_format);
if (driver.IsOpenGLES()) {
runtime.BindFramebuffer(GL_READ_FRAMEBUFFER, download.texture_level, GL_TEXTURE_2D, type,
unscaled_surface.texture);
unscaled_surface.Handle());
glReadPixels(0, 0, rect_width, rect_height, tuple.format, tuple.type,
staging.mapped.data());
} else {

View File

@ -40,8 +40,8 @@ class TextureRuntime {
friend class Framebuffer;
public:
TextureRuntime(Driver& driver);
~TextureRuntime() = default;
explicit TextureRuntime(Driver& driver);
~TextureRuntime();
/// Maps an internal staging buffer of the provided size of pixel uploads/downloads
StagingData FindStaging(u32 size, bool upload);
@ -78,7 +78,7 @@ public:
private:
/// Returns the framebuffer used for texture downloads
void BindFramebuffer(GLenum target, GLint level, GLenum textarget, VideoCore::SurfaceType type,
OGLTexture& texture) const;
GLuint handle) const;
/// Returns the OpenGL driver class
const Driver& GetDriver() const {
@ -103,7 +103,7 @@ private:
class Surface : public VideoCore::SurfaceBase {
public:
Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime);
explicit Surface(VideoCore::SurfaceParams& params, TextureRuntime& runtime);
~Surface();
/// Returns the surface image handle
@ -132,8 +132,6 @@ private:
private:
TextureRuntime& runtime;
const Driver& driver;
public:
OGLTexture texture{};
};

View File

@ -21,6 +21,7 @@ namespace Vulkan {
using VideoCore::GetFormatType;
using VideoCore::MipLevels;
using VideoCore::PixelFormatAsString;
using VideoCore::TextureType;
struct RecordParams {
vk::ImageAspectFlags aspect;
@ -130,9 +131,6 @@ TextureRuntime::~TextureRuntime() {
for (const auto& [key, alloc] : texture_recycler) {
vmaDestroyImage(allocator, alloc.image, alloc.allocation);
if (alloc.base_view && alloc.base_view != alloc.image_view) {
device.destroyImageView(alloc.base_view);
}
device.destroyImageView(alloc.image_view);
if (alloc.depth_view) {
device.destroyImageView(alloc.depth_view);
@ -162,23 +160,19 @@ void TextureRuntime::Finish() {
scheduler.Finish();
}
ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
Allocation TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
VideoCore::PixelFormat format, VideoCore::TextureType type) {
const FormatTraits traits = instance.GetTraits(format);
return Allocate(width, height, levels, format, type, traits.native, traits.usage,
traits.aspect);
}
ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
Allocation TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
VideoCore::PixelFormat pixel_format,
VideoCore::TextureType type, vk::Format format,
vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect) {
MICROPROFILE_SCOPE(Vulkan_ImageAlloc);
ImageAlloc alloc{};
alloc.format = format;
alloc.aspect = aspect;
// The internal format does not provide enough guarantee of texture uniqueness
// especially when many pixel formats fallback to RGBA8
ASSERT(pixel_format != VideoCore::PixelFormat::Invalid);
@ -191,9 +185,8 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
.levels = levels,
};
// Attempt to recycle an unused allocation
if (auto it = texture_recycler.find(key); it != texture_recycler.end()) {
ImageAlloc alloc = std::move(it->second);
Allocation alloc = std::move(it->second);
texture_recycler.erase(it);
return alloc;
}
@ -242,24 +235,23 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
VkImage unsafe_image{};
VkImageCreateInfo unsafe_image_info = static_cast<VkImageCreateInfo>(image_info);
VmaAllocation allocation{};
VkResult result = vmaCreateImage(instance.GetAllocator(), &unsafe_image_info, &alloc_info,
&unsafe_image, &alloc.allocation, nullptr);
&unsafe_image, &allocation, nullptr);
if (result != VK_SUCCESS) [[unlikely]] {
LOG_CRITICAL(Render_Vulkan, "Failed allocating texture with error {}", result);
UNREACHABLE();
}
const vk::Image image{unsafe_image};
const vk::ImageViewType view_type =
type == VideoCore::TextureType::CubeMap ? vk::ImageViewType::eCube : vk::ImageViewType::e2D;
alloc.image = vk::Image{unsafe_image};
const vk::ImageViewCreateInfo view_info = {
.image = alloc.image,
.viewType = view_type,
.image = image,
.viewType =
type == TextureType::CubeMap ? vk::ImageViewType::eCube : vk::ImageViewType::e2D,
.format = format,
.subresourceRange{
.aspectMask = alloc.aspect,
.aspectMask = aspect,
.baseMipLevel = 0,
.levelCount = levels,
.baseArrayLayer = 0,
@ -268,13 +260,10 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
};
vk::Device device = instance.GetDevice();
alloc.image_view = device.createImageView(view_info);
if (levels == 1) {
alloc.base_view = alloc.image_view;
}
const vk::ImageView image_view = device.createImageView(view_info);
renderpass_cache.ExitRenderpass();
scheduler.Record([image = alloc.image, aspect = alloc.aspect](vk::CommandBuffer cmdbuf) {
scheduler.Record([image, aspect](vk::CommandBuffer cmdbuf) {
const vk::ImageMemoryBarrier init_barrier = {
.srcAccessMask = vk::AccessFlagBits::eNone,
.dstAccessMask = vk::AccessFlagBits::eNone,
@ -297,10 +286,16 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, u32 levels,
vk::DependencyFlagBits::eByRegion, {}, {}, init_barrier);
});
return alloc;
return Allocation{
.image = image,
.image_view = image_view,
.allocation = allocation,
.aspect = aspect,
.format = format,
};
}
void TextureRuntime::Recycle(const HostTextureTag tag, ImageAlloc&& alloc) {
void TextureRuntime::Recycle(const HostTextureTag tag, Allocation&& alloc) {
texture_recycler.emplace(tag, std::move(alloc));
}
@ -745,7 +740,7 @@ bool TextureRuntime::NeedsConvertion(VideoCore::PixelFormat format) const {
Surface::Surface(const VideoCore::SurfaceParams& params, TextureRuntime& runtime)
: VideoCore::SurfaceBase{params}, runtime{runtime}, instance{runtime.GetInstance()},
scheduler{runtime.GetScheduler()}, traits{instance.GetTraits(pixel_format)} {
scheduler{runtime.GetScheduler()} {
if (pixel_format != VideoCore::PixelFormat::Invalid) {
alloc = runtime.Allocate(GetScaledWidth(), GetScaledHeight(), levels, params.pixel_format,
@ -994,28 +989,6 @@ vk::PipelineStageFlags Surface::PipelineStageFlags() const noexcept {
: vk::PipelineStageFlagBits::eNone);
}
vk::ImageView Surface::FramebufferView() noexcept {
vk::ImageView& base_view = alloc.base_view;
if (base_view) {
return base_view;
}
const vk::ImageViewCreateInfo base_view_info = {
.image = alloc.image,
.viewType = vk::ImageViewType::e2D,
.format = instance.GetTraits(pixel_format).native,
.subresourceRange{
.aspectMask = alloc.aspect,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
base_view = instance.GetDevice().createImageView(base_view_info);
return base_view;
}
vk::ImageView Surface::DepthView() noexcept {
vk::ImageView& depth_view = alloc.depth_view;
if (depth_view) {

View File

@ -26,26 +26,15 @@ struct StagingData {
u64 buffer_offset = 0;
};
struct ImageAlloc {
ImageAlloc() = default;
ImageAlloc(const ImageAlloc&) = delete;
ImageAlloc& operator=(const ImageAlloc&) = delete;
ImageAlloc(ImageAlloc&&) = default;
ImageAlloc& operator=(ImageAlloc&&) = default;
struct Allocation {
vk::Image image;
vk::ImageView image_view;
vk::ImageView base_view;
vk::ImageView depth_view;
vk::ImageView stencil_view;
vk::ImageView storage_view;
VmaAllocation allocation;
vk::ImageUsageFlags usage;
vk::ImageAspectFlags aspect;
vk::Format format;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
vk::ImageLayout layout;
};
struct HostTextureTag {
@ -98,17 +87,17 @@ public:
void Finish();
/// Takes back ownership of the allocation for recycling
void Recycle(const HostTextureTag tag, ImageAlloc&& alloc);
void Recycle(const HostTextureTag tag, Allocation&& alloc);
/// Maps an internal staging buffer of the provided size of pixel uploads/downloads
[[nodiscard]] StagingData FindStaging(u32 size, bool upload);
/// Allocates a vulkan image possibly resusing an existing one
[[nodiscard]] ImageAlloc Allocate(u32 width, u32 height, u32 levels,
[[nodiscard]] Allocation Allocate(u32 width, u32 height, u32 levels,
VideoCore::PixelFormat format, VideoCore::TextureType type);
/// Allocates a vulkan image
[[nodiscard]] ImageAlloc Allocate(u32 width, u32 height, u32 levels,
[[nodiscard]] Allocation Allocate(u32 width, u32 height, u32 levels,
VideoCore::PixelFormat pixel_format,
VideoCore::TextureType type, vk::Format format,
vk::ImageUsageFlags usage, vk::ImageAspectFlags aspect);
@ -159,7 +148,7 @@ private:
StreamBuffer upload_buffer;
StreamBuffer download_buffer;
std::array<ReinterpreterList, VideoCore::PIXEL_FORMAT_COUNT> reinterpreters;
std::unordered_multimap<HostTextureTag, ImageAlloc> texture_recycler;
std::unordered_multimap<HostTextureTag, Allocation> texture_recycler;
};
class Surface : public VideoCore::SurfaceBase {
@ -201,9 +190,6 @@ public:
/// Returns the pipeline stage flags indicative of the surface
vk::PipelineStageFlags PipelineStageFlags() const noexcept;
/// Returns an image view used to create a framebuffer
vk::ImageView FramebufferView() noexcept;
/// Returns the depth only image view of the surface
vk::ImageView DepthView() noexcept;
@ -228,8 +214,7 @@ private:
TextureRuntime& runtime;
const Instance& instance;
Scheduler& scheduler;
ImageAlloc alloc;
FormatTraits traits;
Allocation alloc;
bool is_framebuffer{};
bool is_storage{};
};