1#include "GraphicsDeviceVK.h"
3#include "Foundation/StringView.h"
4#include "Foundation/Platform/WindowData.h"
18 VkBool32 DebugCallback(VkDebugReportFlagsEXT flags,
19 VkDebugReportObjectTypeEXT objectType,
23 const char * pLayerPrefix,
24 const char * pMessage,
27 const auto format =
"[%s] %s";
30 if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
31 LOG_ERROR(logger, format, pLayerPrefix, pMessage);
32 }
else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
33 LOG_WARNING(logger, format, pLayerPrefix, pMessage);
34 }
else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
35 LOG_INFO(logger, format, pLayerPrefix, pMessage);
36 }
else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
37 LOG_DEBUG(logger, format, pLayerPrefix, pMessage);
45bool Cogs::GraphicsDeviceVK::initializeInstance()
49 uint32_t layerCount = 0;
50 vkEnumerateInstanceLayerProperties(&layerCount,
nullptr);
52 std::vector<VkLayerProperties> layers(layerCount);
53 vkEnumerateInstanceLayerProperties(&layerCount, layers.data());
55 uint32_t extensionCount = 0;
56 vkEnumerateInstanceExtensionProperties(
nullptr, &extensionCount,
nullptr);
58 std::vector<VkExtensionProperties> extensions(extensionCount);
59 vkEnumerateInstanceExtensionProperties(
nullptr, &extensionCount, extensions.data());
61 VkApplicationInfo applicationInfo = {
62 VK_STRUCTURE_TYPE_APPLICATION_INFO,
71 std::vector<const char *> activeExtensions;
72 std::vector<const char *> activeLayers;
74 std::vector<StringView> desiredLayers = {
77 "VK_LAYER_LUNARG_threading",
78 "VK_LAYER_LUNARG_mem_tracker",
80 "VK_LAYER_LUNARG_draw_state",
81 "VK_LAYER_LUNARG_param_checker",
82 "VK_LAYER_LUNARG_swapchain",
83 "VK_LAYER_LUNARG_device_limits",
84 "VK_LAYER_LUNARG_image",
85 "VK_LAYER_GOOGLE_unique_objects",
89 for (
auto & layer : layers) {
90 for (
auto desiredLayer : desiredLayers) {
91 if (desiredLayer == layer.layerName) {
92 activeLayers.push_back(layer.layerName);
97 std::vector<StringView> desiredExtensions = {
98 VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
99 VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
100 VK_KHR_SURFACE_EXTENSION_NAME
103 for (
auto & extension : extensions) {
104 for (
auto & desiredExtension : desiredExtensions) {
105 if (desiredExtension == extension.extensionName) {
106 activeExtensions.push_back(extension.extensionName);
111 if (activeExtensions.size() != desiredExtensions.size()) {
112 LOG_WARNING(logger,
"Could not find all desired extensions.");
115 VkInstanceCreateInfo instanceInfo = {
116 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
nullptr, 0,
118 static_cast<uint32_t
>(activeLayers.size()),
120 static_cast<uint32_t
>(activeExtensions.size()),
121 activeExtensions.data()
124 auto result = vkCreateInstance(&instanceInfo,
nullptr, &instance);
126 if (VK_FAILED(result) || !instance) {
127 LOG_ERROR(logger,
"Could not create Vulkan API instance.");
131#ifndef COGS_USE_VK_SDK
132 LOAD_INSTANCE_FUNCTION(vkCreateDebugReportCallbackEXT);
133 LOAD_INSTANCE_FUNCTION(vkDebugReportMessageEXT);
135 if (vkCreateDebugReportCallbackEXT) {
136 VkDebugReportCallbackCreateInfoEXT reportCallbackInfo = {};
137 reportCallbackInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
138 reportCallbackInfo.pNext =
nullptr;
139 reportCallbackInfo.pfnCallback = DebugCallback;
140 reportCallbackInfo.pUserData =
this;
141 reportCallbackInfo.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
142 VK_DEBUG_REPORT_WARNING_BIT_EXT |
143 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
144 VK_DEBUG_REPORT_ERROR_BIT_EXT |
145 VK_DEBUG_REPORT_DEBUG_BIT_EXT;
147 VkDebugReportCallbackEXT reportCallback;
148 result = vkCreateDebugReportCallbackEXT(instance, &reportCallbackInfo,
nullptr, &reportCallback);
150 if (result != VK_SUCCESS) {
154 vkDebugReportMessageEXT(instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, 0, 0,
"Cogs",
"Initialized debug callbacks.");
157 instanceAssign(CreateDebugReportCallbackEXT, instance,
"vkCreateDebugReportCallbackEXT");
158 instanceAssign(DebugReportMessageEXT, instance,
"vkDebugReportMessageEXT");
160 if (CreateDebugReportCallbackEXT) {
161 VkDebugReportCallbackCreateInfoEXT reportCallbackInfo = {};
162 reportCallbackInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
163 reportCallbackInfo.pNext =
nullptr;
164 reportCallbackInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)DebugCallback;
165 reportCallbackInfo.pUserData =
this;
166 reportCallbackInfo.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
167 VK_DEBUG_REPORT_WARNING_BIT_EXT |
168 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
169 VK_DEBUG_REPORT_ERROR_BIT_EXT |
170 VK_DEBUG_REPORT_DEBUG_BIT_EXT;
172 VkDebugReportCallbackEXT reportCallback;
173 result = CreateDebugReportCallbackEXT(instance, &reportCallbackInfo,
nullptr, &reportCallback);
175 if (result != VK_SUCCESS) {
179 DebugReportMessageEXT(instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, 0, 0, 0,
"Cogs",
"Initialized debug callbacks.");
183 loaderInitInstance(instance);
188bool Cogs::GraphicsDeviceVK::initializeDevice()
190 uint32_t physicalDeviceCount = 0;
191 vkEnumeratePhysicalDevices(instance, &physicalDeviceCount,
nullptr);
193 std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
194 auto result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data());
196 if (VK_FAILED(result)) {
197 VK_LOG_ERROR(result,
"Failed to enumerate physical devices.");
201 if (!physicalDeviceCount) {
202 LOG_ERROR(logger,
"No physical devices available.");
206 uint32_t queueFamilyIndex = 0;
208 for (
auto & physicalDevice : physicalDevices) {
209 VkPhysicalDeviceFeatures features;
210 vkGetPhysicalDeviceFeatures(physicalDevice, &features);
212 uint32_t queueFamilyCount = 0;
213 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount,
nullptr);
215 std::vector<VkQueueFamilyProperties> queueFamilyProperties(queueFamilyCount);
216 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilyProperties.data());
218 for (
size_t i = 0; i < queueFamilyProperties.size(); ++i) {
219 if (queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
220 queueFamilyIndex =
static_cast<uint32_t
>(i);
225 VkBool32 supported = 0;
226 vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, 0, surface, &supported);
232 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities.surfaceCapabilities);
234 uint32_t presentModeCount = 0;
235 vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount,
nullptr);
237 capabilities.presentModes.resize(presentModeCount);
238 vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, capabilities.presentModes.data());
240 uint32_t surfaceFormatCount = 0;
241 vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount,
nullptr);
243 capabilities.surfaceFormats.resize(surfaceFormatCount);
244 vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount, capabilities.surfaceFormats.data());
247 this->physicalDevice = physicalDevice;
248 physicalDeviceFeatures = features;
253 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
255 VkPhysicalDeviceProperties deviceProperties;
256 vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
258 uint32_t layerCount = 0;
259 vkEnumerateDeviceLayerProperties(physicalDevice, &layerCount,
nullptr);
261 std::vector<VkLayerProperties> layers;
262 vkEnumerateDeviceLayerProperties(physicalDevice, &layerCount, layers.data());
264 uint32_t extensionCount = 0;
265 vkEnumerateDeviceExtensionProperties(physicalDevice,
nullptr, &extensionCount,
nullptr);
267 std::vector<VkExtensionProperties> deviceExtensions(extensionCount);
268 vkEnumerateDeviceExtensionProperties(physicalDevice,
nullptr, &extensionCount, deviceExtensions.data());
270 std::vector<const char *> activeLayers;
271 std::vector<const char *> activeExtensions;
273 for (
auto & layer : layers) {
274 activeLayers.push_back(layer.layerName);
277 bool foundKHRSwapchain =
false;
278 bool foundNVGLSL =
false;
279 for (
auto & extension : deviceExtensions) {
280 if (StringView(VK_KHR_SWAPCHAIN_EXTENSION_NAME) == extension.extensionName) {
281 foundKHRSwapchain =
true;
282 }
else if (StringView(
"VK_NV_glsl_shader") == extension.extensionName) {
286 activeExtensions.push_back(extension.extensionName);
289 if (!foundKHRSwapchain) {
290 LOG_ERROR(logger,
"Could not find VK_KHR_SWAPCHAIN_EXTENSION.");
295 LOG_WARNING(logger,
"Could not find VK_NV_glsl_shader. GLSL usage may fail.");
298 float priority = 1.0f;
300 VkDeviceQueueCreateInfo queueCreateInfo = {
301 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
309 VkDeviceCreateInfo createInfo = {
310 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
315 static_cast<uint32_t
>(activeLayers.size()),
317 static_cast<uint32_t
>(activeExtensions.size()),
318 activeExtensions.data(),
319 &physicalDeviceFeatures
322 VkAllocationCallbacks allocator = {
326 result = vkCreateDevice(physicalDevice, &createInfo,
nullptr, &device);
328 if (VK_FAILED(result)) {
329 VK_LOG_ERROR(result,
"Could not create Vulkan device.");
333 vkGetDeviceQueue(device, 0, 0, &queue);
335 loaderInitDevice(instance, device);
340bool Cogs::GraphicsDeviceVK::initializeSwapChain()
342 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities.surfaceCapabilities);
344 VkExtent2D swapchainExtent;
345 swapchainExtent.width = std::min((uint32_t)width, capabilities.surfaceCapabilities.currentExtent.width);
346 swapchainExtent.height = std::min((uint32_t)height, capabilities.surfaceCapabilities.currentExtent.height);;
348 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
350 uint32_t desiredNumberOfSwapchainImages = 3;
352 auto oldSwapchain = swapChain;
354 VkSwapchainCreateInfoKHR swapChainInfo = {};
355 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
356 swapChainInfo.pNext =
nullptr;
357 swapChainInfo.surface = surface;
358 swapChainInfo.minImageCount = desiredNumberOfSwapchainImages;
359 swapChainInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
360 swapChainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
361 swapChainInfo.imageExtent = swapchainExtent;
362 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
363 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
364 swapChainInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
365 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
366 swapChainInfo.imageArrayLayers = 1;
367 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
368 swapChainInfo.queueFamilyIndexCount = 0;
369 swapChainInfo.pQueueFamilyIndices =
nullptr;
370 swapChainInfo.presentMode = swapchainPresentMode;
371 swapChainInfo.oldSwapchain = oldSwapchain;
372 swapChainInfo.clipped =
true;
374 auto result = vkCreateSwapchainKHR(device, &swapChainInfo,
nullptr, &swapChain);
376 if (VK_FAILED(result)) {
377 VK_LOG_ERROR(result,
"Could not create swap chain.");
381 uint32_t numSwapChainImages = 0;
382 vkGetSwapchainImagesKHR(device, swapChain, &numSwapChainImages,
nullptr);
384 swapChainImages.resize(numSwapChainImages);
385 vkGetSwapchainImagesKHR(device, swapChain, &numSwapChainImages, swapChainImages.data());
387 backBuffers.resize(numSwapChainImages);
389 if (settings.numSamples > 1) {
390 backBuffersMS.resize(numSwapChainImages);
393 for (uint32_t i = 0; i < numSwapChainImages; ++i) {
396 if (settings.numSamples > 1) {
397 backBuffersMS[i] = textures.loadTexture(
nullptr, width, height, TextureFormat::R8G8B8A8_UNORM, settings.numSamples,
TextureFlags::RenderTarget);
401 LOG_ERROR(logger,
"Failed creating back buffer texture wrappers.");
408bool Cogs::GraphicsDeviceVK::initializeCommandPool()
410 const VkCommandPoolCreateInfo commandPoolInfo = {
411 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
413 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
417 auto result = vkCreateCommandPool(device, &commandPoolInfo,
nullptr, &commandPool);
419 if (VK_FAILED(result)) {
420 VK_LOG_ERROR(result,
"Could not create command pool.");
427Cogs::GraphicsDeviceVK::GraphicsDeviceVK(RenderingAllocatorInfo * allocator)
433 if (!initializeInstance()) {
434 LOG_ERROR(logger,
"Could not initialize instance.");
438 VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {};
439 surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
440 surfaceCreateInfo.pNext =
nullptr;
441 surfaceCreateInfo.flags = 0;
442 surfaceCreateInfo.hinstance = ::GetModuleHandle(0);
443 surfaceCreateInfo.hwnd = settings.windowData->windowHandle;
445 auto result = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo,
nullptr, &surface);
447 if (VK_FAILED(result)) {
448 VK_LOG_ERROR(result,
"Could not create surface.");
452 if (!initializeDevice()) {
453 LOG_ERROR(logger,
"Could not initialize device.");
457 buffers.initialize(
this);
458 textures.initialize(
this);
459 renderTargets.initialize(
this);
461 if (!initializeSwapChain()) {
462 LOG_ERROR(logger,
"Could not initialize swap chain.");
466 if (!initializeCommandPool()) {
467 LOG_ERROR(logger,
"Could not initialize command pool.");
471 context.initialize(
this);
472 buffers.graphicsDevice =
this;
473 effects.initialize(
this);
475 if (settings.ioHandler) effects.setIOHandler(settings.ioHandler);
477 if (!initializeDepth()) {
481 if (!initializeFramebuffers()) {
488bool Cogs::GraphicsDeviceVK::initializeDepth()
490 depthTextureHandle = textures.loadTexture(
nullptr, width, height, settings.depthFormat, settings.numSamples,
TextureFlags::DepthBuffer);
495void Cogs::GraphicsDeviceVK::flushSetup()
497 if (setupCommands == VK_NULL_HANDLE) {
501 auto result = vkEndCommandBuffer(setupCommands);
504 const VkCommandBuffer commandBuffers[] = { setupCommands };
506 VkSubmitInfo submitInfo = {};
507 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
508 submitInfo.commandBufferCount = 1;
509 submitInfo.pCommandBuffers = commandBuffers;
511 result = vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
514 result = vkQueueWaitIdle(queue);
517 vkFreeCommandBuffers(device, commandPool, 1, commandBuffers);
519 setupCommands = VK_NULL_HANDLE;
522bool Cogs::GraphicsDeviceVK::initializeFramebuffers()
524 framebuffers.resize(swapChainImages.size());
526 for (
size_t i = 0; i < swapChainImages.size(); i++) {
527 if (settings.numSamples == 1) {
528 framebuffers[i] = renderTargets.createRenderTarget(backBuffers[i]);
530 framebuffers[i] = renderTargets.createRenderTarget(backBuffersMS[i]);
533 auto dsv = renderTargets.createDepthStencilTarget(framebuffers[i], depthTextureHandle);
536 LOG_ERROR(logger,
"Failed creating render targets.");
543bool Cogs::GraphicsDeviceVK::getMemoryType(uint32_t typeBits, VkFlags requirementsMask, uint32_t * typeIndex)
545 for (uint32_t i = 0; i < 32; i++) {
546 if ((typeBits & 1) == 1) {
548 if ((memoryProperties.memoryTypes[i].propertyFlags &
549 requirementsMask) == requirementsMask) {
562 if (width == this->width && height == this->height)
return;
565 this->height = height;
573 height = this->height;
579 VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
580 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
585 auto err = vkCreateSemaphore(device, &presentCompleteSemaphoreCreateInfo,
nullptr, &presentCompleteSemaphore);
593 err = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, presentCompleteSemaphore,
595 ¤tFrameBuffer);
597 context.defaultRenderTarget = framebuffers[currentFrameBuffer];
601 context.beginFrame();
603 if (context.currentFrameResources->presentSemaphore) {
604 vkDestroySemaphore(device, context.currentFrameResources->presentSemaphore,
nullptr);
607 context.currentFrameResources->presentSemaphore = presentCompleteSemaphore;
616 VkPipelineStageFlags stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
618 VkSubmitInfo submitInfo = {};
619 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
620 submitInfo.pNext =
nullptr;
621 submitInfo.waitSemaphoreCount = 1;
622 submitInfo.pWaitSemaphores = &presentCompleteSemaphore;
623 submitInfo.pWaitDstStageMask = &stageFlags;
624 submitInfo.commandBufferCount = 1;
625 submitInfo.pCommandBuffers = &context.currentFrameResources->commandBuffer;
626 submitInfo.signalSemaphoreCount = 0;
627 submitInfo.pSignalSemaphores =
nullptr;
629 auto err = vkQueueSubmit(queue, 1, &submitInfo, context.currentFrameResources->fence);
631 if (VK_FAILED(err)) {
632 VK_LOG_ERROR(err,
"Queue submit failed.");
635 context.currentFrameResources =
nullptr;
637 VkPresentInfoKHR presentInfo = {
638 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
648 vkQueuePresentKHR(queue, &presentInfo);
650 ++currentFrameBuffer;
651 if (currentFrameBuffer > 1) currentFrameBuffer = 0;
669VkCommandBuffer Cogs::GraphicsDeviceVK::getCommandBuffer()
671 if (context.currentFrameResources) {
672 return context.currentFrameResources->commandBuffer;
674 if (setupCommands == VK_NULL_HANDLE) {
675 VkCommandBufferAllocateInfo cmd = {};
676 cmd.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
678 cmd.commandPool = commandPool;
679 cmd.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
680 cmd.commandBufferCount = 1;
682 auto result = vkAllocateCommandBuffers(device, &cmd, &setupCommands);
684 if (VK_FAILED(result)) {
685 VK_LOG_ERROR(result,
"Failed to allocate setup command buffer.");
686 return VK_NULL_HANDLE;
689 VkCommandBufferBeginInfo commandBufferInfo = {};
690 commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
691 commandBufferInfo.pNext =
nullptr;
692 commandBufferInfo.flags = 0;
693 commandBufferInfo.pInheritanceInfo =
nullptr;
695 result = vkBeginCommandBuffer(setupCommands, &commandBufferInfo);
698 return setupCommands;
702void Cogs::GraphicsDeviceVK::resize()
704 vkDeviceWaitIdle(device);
706 for (
auto & frameBuffer : framebuffers) {
707 renderTargets.releaseRenderTarget(frameBuffer);
710 framebuffers.clear();
712 for (
auto & t : backBuffers) {
713 textures.releaseTexture(t);
718 textures.releaseTexture(depthTextureHandle);
720 initializeSwapChain();
722 initializeFramebuffers();
void releaseResources() override
Release all resources allocated.
bool initialize() override
Initializes the graphics device with the settings previous set through calling setSettings.
bool getSize(int &width, int &height) const override
Retrieve the size previously set by setSize.
void beginFrame() override
Signal the beginning of a new frame to the graphics device.
void waitForCommandSync() override
Wait for any GPU commands on the current device to finish before returning.
void setSize(int width, int height) override
Set the size of the main drawing buffer used by the graphics device in pixels.
void endFrame(uint32_t syncInterval=0, uint32_t presentFlags=PresentFlags::None) override
Signal the end of a frame to the graphics device.
ISwapChain * getDefaultSwapChain() override
Get a pointer to the default swap chain for this graphics device.
Log implementation class.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ DepthBuffer
The texture can be used as a depth target and have depth buffer values written into.
@ RenderTarget
The texture can be used as a render target and drawn into.