"""Offscreen render target with colour + depth attachments."""
from __future__ import annotations
import logging
from typing import Any
import vulkan as vk
from ..gpu.memory import create_image
from .passes import create_offscreen_pass
log = logging.getLogger(__name__)
__all__ = ["RenderTarget"]
[docs]
class RenderTarget:
"""Manages an offscreen render target for render-to-texture."""
def __init__(
self,
device: Any,
physical_device: Any,
width: int,
height: int,
color_format: int = vk.VK_FORMAT_R8G8B8A8_UNORM,
use_depth: bool = True,
samplable_depth: bool = False,
) -> None:
self.device = device
self.width = width
self.height = height
self.color_format = color_format
# Colour attachment (samplable)
self.color_image, self.color_memory = create_image(
device, physical_device, width, height, color_format,
vk.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk.VK_IMAGE_USAGE_SAMPLED_BIT | vk.VK_IMAGE_USAGE_STORAGE_BIT,
)
self.color_view = vk.vkCreateImageView(device, vk.VkImageViewCreateInfo(
image=self.color_image,
viewType=vk.VK_IMAGE_VIEW_TYPE_2D,
format=color_format,
subresourceRange=vk.VkImageSubresourceRange(
aspectMask=vk.VK_IMAGE_ASPECT_COLOR_BIT,
baseMipLevel=0, levelCount=1,
baseArrayLayer=0, layerCount=1,
),
), None)
# Depth attachment
depth_fmt = vk.VK_FORMAT_D32_SFLOAT if use_depth else 0
if use_depth:
self.depth_image, self.depth_memory = create_image(
device, physical_device, width, height, depth_fmt,
vk.VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk.VK_IMAGE_USAGE_SAMPLED_BIT,
)
self.depth_view = vk.vkCreateImageView(device, vk.VkImageViewCreateInfo(
image=self.depth_image,
viewType=vk.VK_IMAGE_VIEW_TYPE_2D,
format=depth_fmt,
subresourceRange=vk.VkImageSubresourceRange(
aspectMask=vk.VK_IMAGE_ASPECT_DEPTH_BIT,
baseMipLevel=0, levelCount=1,
baseArrayLayer=0, layerCount=1,
),
), None)
else:
self.depth_image = self.depth_memory = self.depth_view = None
# Render pass and framebuffer
self.render_pass = create_offscreen_pass(
device, color_format, depth_fmt, samplable_depth=samplable_depth,
)
attachments = [self.color_view]
if self.depth_view:
attachments.append(self.depth_view)
self.framebuffer = vk.vkCreateFramebuffer(device, vk.VkFramebufferCreateInfo(
renderPass=self.render_pass,
attachmentCount=len(attachments),
pAttachments=attachments,
width=width, height=height, layers=1,
), None)
[docs]
def destroy(self) -> None:
"""Clean up all resources."""
vk.vkDestroyFramebuffer(self.device, self.framebuffer, None)
vk.vkDestroyRenderPass(self.device, self.render_pass, None)
if self.depth_view:
vk.vkDestroyImageView(self.device, self.depth_view, None)
if self.depth_image:
vk.vkDestroyImage(self.device, self.depth_image, None)
if self.depth_memory:
vk.vkFreeMemory(self.device, self.depth_memory, None)
vk.vkDestroyImageView(self.device, self.color_view, None)
vk.vkDestroyImage(self.device, self.color_image, None)
vk.vkFreeMemory(self.device, self.color_memory, None)