blob: ac5dafd92b485ed601c3722b4659a006b294ddaf [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan CTS Framework
* --------------------
*
* Copyright (c) 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Windowing System Integration (WSI) Utilities.
*//*--------------------------------------------------------------------*/
#include "vkRefUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkWsiUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "deArrayUtil.hpp"
#include "deMemory.h"
#include <limits>
#include <vector>
using std::vector;
#if defined (DEQP_SUPPORT_X11)
# include <X11/Xlib.h>
# if defined (DEQP_SUPPORT_XCB)
# include <xcb/xcb.h>
# endif // DEQP_SUPPORT_XCB
#endif // DEQP_SUPPORT_X11
#if defined (DEQP_SUPPORT_WAYLAND)
# include "tcuLnxWayland.hpp"
# define WAYLAND_DISPLAY DE_NULL
#endif // DEQP_SUPPORT_WAYLAND
#if ( DE_OS == DE_OS_WIN32 )
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
namespace vk
{
namespace wsi
{
//! Get canonical WSI name that should be used for example in test case and group names.
const char* getName (Type wsiType)
{
static const char* const s_names[] =
{
"xlib",
"xcb",
"wayland",
"android",
"win32",
"macos",
};
return de::getSizedArrayElement<TYPE_LAST>(s_names, wsiType);
}
const char* getExtensionName (Type wsiType)
{
static const char* const s_extNames[] =
{
"VK_KHR_xlib_surface",
"VK_KHR_xcb_surface",
"VK_KHR_wayland_surface",
"VK_KHR_android_surface",
"VK_KHR_win32_surface",
"VK_MVK_macos_surface"
};
return de::getSizedArrayElement<TYPE_LAST>(s_extNames, wsiType);
}
const PlatformProperties& getPlatformProperties (Type wsiType)
{
// \note These are declared here (rather than queried through vk::Platform for example)
// on purpose. The behavior of a platform is partly defined by the platform spec,
// and partly by WSI extensions, and platform ports should not need to override
// that definition.
const deUint32 noDisplayLimit = std::numeric_limits<deUint32>::max();
const deUint32 noWindowLimit = std::numeric_limits<deUint32>::max();
static const PlatformProperties s_properties[] =
{
// VK_KHR_xlib_surface
{
PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE|PlatformProperties::FEATURE_RESIZE_WINDOW,
PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
noDisplayLimit,
noWindowLimit,
},
// VK_KHR_xcb_surface
{
PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE|PlatformProperties::FEATURE_RESIZE_WINDOW,
PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
noDisplayLimit,
noWindowLimit,
},
// VK_KHR_wayland_surface
{
0u,
PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE,
noDisplayLimit,
noWindowLimit,
},
// VK_KHR_android_surface
{
PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE,
PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE,
1u,
1u, // Only one window available
},
// VK_KHR_win32_surface
{
PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE|PlatformProperties::FEATURE_RESIZE_WINDOW,
PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
noDisplayLimit,
noWindowLimit,
},
// VK_MVK_macos_surface
{
PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE|PlatformProperties::FEATURE_RESIZE_WINDOW,
PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
noDisplayLimit,
noWindowLimit,
},
};
return de::getSizedArrayElement<TYPE_LAST>(s_properties, wsiType);
}
VkResult createSurface (const InstanceInterface& vki,
VkInstance instance,
Type wsiType,
const Display& nativeDisplay,
const Window& nativeWindow,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface)
{
// Update this function if you add more WSI implementations
DE_STATIC_ASSERT(TYPE_LAST == 6);
switch (wsiType)
{
case TYPE_XLIB:
{
const XlibDisplayInterface& xlibDisplay = dynamic_cast<const XlibDisplayInterface&>(nativeDisplay);
const XlibWindowInterface& xlibWindow = dynamic_cast<const XlibWindowInterface&>(nativeWindow);
const VkXlibSurfaceCreateInfoKHR createInfo =
{
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
DE_NULL,
(VkXlibSurfaceCreateFlagsKHR)0,
xlibDisplay.getNative(),
xlibWindow.getNative()
};
return vki.createXlibSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
}
case TYPE_XCB:
{
const XcbDisplayInterface& xcbDisplay = dynamic_cast<const XcbDisplayInterface&>(nativeDisplay);
const XcbWindowInterface& xcbWindow = dynamic_cast<const XcbWindowInterface&>(nativeWindow);
const VkXcbSurfaceCreateInfoKHR createInfo =
{
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
DE_NULL,
(VkXcbSurfaceCreateFlagsKHR)0,
xcbDisplay.getNative(),
xcbWindow.getNative()
};
return vki.createXcbSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
}
case TYPE_WAYLAND:
{
const WaylandDisplayInterface& waylandDisplay = dynamic_cast<const WaylandDisplayInterface&>(nativeDisplay);
const WaylandWindowInterface& waylandWindow = dynamic_cast<const WaylandWindowInterface&>(nativeWindow);
const VkWaylandSurfaceCreateInfoKHR createInfo =
{
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
DE_NULL,
(VkWaylandSurfaceCreateFlagsKHR)0,
waylandDisplay.getNative(),
waylandWindow.getNative()
};
return vki.createWaylandSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
}
case TYPE_ANDROID:
{
const AndroidWindowInterface& androidWindow = dynamic_cast<const AndroidWindowInterface&>(nativeWindow);
const VkAndroidSurfaceCreateInfoKHR createInfo =
{
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
DE_NULL,
(VkAndroidSurfaceCreateFlagsKHR)0,
androidWindow.getNative()
};
return vki.createAndroidSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
}
case TYPE_WIN32:
{
const Win32DisplayInterface& win32Display = dynamic_cast<const Win32DisplayInterface&>(nativeDisplay);
const Win32WindowInterface& win32Window = dynamic_cast<const Win32WindowInterface&>(nativeWindow);
const VkWin32SurfaceCreateInfoKHR createInfo =
{
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
DE_NULL,
(VkWin32SurfaceCreateFlagsKHR)0,
win32Display.getNative(),
win32Window.getNative()
};
return vki.createWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface);
}
case TYPE_MACOS:
{
const MacOSWindowInterface& macOSWindow = dynamic_cast<const MacOSWindowInterface&>(nativeWindow);
const VkMacOSSurfaceCreateInfoMVK createInfo =
{
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK,
DE_NULL,
(VkMacOSSurfaceCreateFlagsMVK)0,
macOSWindow.getNative()
};
return vki.createMacOSSurfaceMVK(instance, &createInfo, pAllocator, pSurface);
}
default:
DE_FATAL("Unknown WSI type");
return VK_ERROR_SURFACE_LOST_KHR;
}
}
Move<VkSurfaceKHR> createSurface (const InstanceInterface& vki,
VkInstance instance,
Type wsiType,
const Display& nativeDisplay,
const Window& nativeWindow,
const VkAllocationCallbacks* pAllocator)
{
VkSurfaceKHR object = 0;
VK_CHECK(createSurface(vki, instance, wsiType, nativeDisplay, nativeWindow, pAllocator, &object));
return Move<VkSurfaceKHR>(check<VkSurfaceKHR>(object), Deleter<VkSurfaceKHR>(vki, instance, pAllocator));
}
VkBool32 getPhysicalDeviceSurfaceSupport (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
deUint32 queueFamilyIndex,
VkSurfaceKHR surface)
{
VkBool32 result = 0;
VK_CHECK(vki.getPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, &result));
return result;
}
VkBool32 getPhysicalDevicePresentationSupport (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
deUint32 queueFamilyIndex,
Type wsiType,
const Display& nativeDisplay)
{
switch (wsiType)
{
case TYPE_XLIB:
{
const XlibDisplayInterface& xlibDisplay = dynamic_cast<const XlibDisplayInterface&>(nativeDisplay);
pt::XlibVisualID visualID (0U);
#if defined (DEQP_SUPPORT_X11)
::Display* displayPtr = (::Display*)(xlibDisplay.getNative().internal);
visualID.internal = (deUint32)(::XDefaultVisual(displayPtr,0)->visualid);
#endif
return vki.getPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, xlibDisplay.getNative(), visualID);
}
case TYPE_XCB:
{
const XcbDisplayInterface& xcbDisplay = dynamic_cast<const XcbDisplayInterface&>(nativeDisplay);
pt::XcbVisualid visualID (0U);
#if defined (DEQP_SUPPORT_XCB)
xcb_connection_t* connPtr = (xcb_connection_t*)(xcbDisplay.getNative().internal);
xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(connPtr)).data;
visualID.internal = (deUint32)(screen->root_visual);
#endif
return vki.getPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex, xcbDisplay.getNative(), visualID);
}
case TYPE_WAYLAND:
{
const WaylandDisplayInterface& waylandDisplay = dynamic_cast<const WaylandDisplayInterface&>(nativeDisplay);
return vki.getPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, waylandDisplay.getNative());
}
case TYPE_WIN32:
{
return vki.getPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
}
case TYPE_ANDROID:
case TYPE_MACOS:
{
return 1;
}
default:
DE_FATAL("Unknown WSI type");
return 0;
}
return 1;
}
VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface)
{
VkSurfaceCapabilitiesKHR capabilities;
deMemset(&capabilities, 0, sizeof(capabilities));
VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities));
return capabilities;
}
VkSurfaceCapabilities2EXT getPhysicalDeviceSurfaceCapabilities2EXT (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface)
{
VkSurfaceCapabilities2EXT capabilities;
deMemset(&capabilities, 0, sizeof(capabilities));
capabilities.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT;
VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, &capabilities));
return capabilities;
}
bool sameSurfaceCapabilities (const VkSurfaceCapabilitiesKHR& khr,
const VkSurfaceCapabilities2EXT& ext)
{
return ( khr.minImageCount == ext.minImageCount &&
khr.maxImageCount == ext.maxImageCount &&
khr.currentExtent.width == ext.currentExtent.width &&
khr.currentExtent.height == ext.currentExtent.height &&
khr.minImageExtent.width == ext.minImageExtent.width &&
khr.minImageExtent.height == ext.minImageExtent.height &&
khr.maxImageExtent.width == ext.maxImageExtent.width &&
khr.maxImageExtent.height == ext.maxImageExtent.height &&
khr.maxImageArrayLayers == ext.maxImageArrayLayers &&
khr.supportedTransforms == ext.supportedTransforms &&
khr.currentTransform == ext.currentTransform &&
khr.supportedCompositeAlpha == ext.supportedCompositeAlpha &&
khr.supportedUsageFlags == ext.supportedUsageFlags );
}
std::vector<VkSurfaceFormatKHR> getPhysicalDeviceSurfaceFormats (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface)
{
deUint32 numFormats = 0;
VK_CHECK(vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &numFormats, DE_NULL));
if (numFormats > 0)
{
std::vector<VkSurfaceFormatKHR> formats (numFormats);
VK_CHECK(vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &numFormats, &formats[0]));
return formats;
}
else
return std::vector<VkSurfaceFormatKHR>();
}
std::vector<VkPresentModeKHR> getPhysicalDeviceSurfacePresentModes (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface)
{
deUint32 numModes = 0;
VK_CHECK(vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numModes, DE_NULL));
if (numModes > 0)
{
std::vector<VkPresentModeKHR> modes (numModes);
VK_CHECK(vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numModes, &modes[0]));
return modes;
}
else
return std::vector<VkPresentModeKHR>();
}
std::vector<VkImage> getSwapchainImages (const DeviceInterface& vkd,
VkDevice device,
VkSwapchainKHR swapchain)
{
deUint32 numImages = 0;
VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, DE_NULL));
if (numImages > 0)
{
std::vector<VkImage> images (numImages);
VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, &images[0]));
return images;
}
else
return std::vector<VkImage>();
}
namespace
{
std::vector<deUint32> getSupportedQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
{
deUint32 numTotalFamilyIndices;
vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, DE_NULL);
std::vector<VkQueueFamilyProperties> queueFamilyProperties(numTotalFamilyIndices);
vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, &queueFamilyProperties[0]);
std::vector<deUint32> supportedFamilyIndices;
for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
{
if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
supportedFamilyIndices.push_back(queueFamilyNdx);
}
return supportedFamilyIndices;
}
std::vector<deUint32> getSortedSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
{
std::vector<deUint32> indices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
std::sort(begin(indices), end(indices));
return indices;
}
} // anonymous
deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, const std::vector<vk::VkSurfaceKHR>& surfaces)
{
auto indices = getCompatibleQueueFamilyIndices(vki, physicalDevice, surfaces);
if (indices.empty())
TCU_THROW(NotSupportedError, "Device does not support presentation to the given surfaces");
return indices[0];
}
deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
{
return chooseQueueFamilyIndex(vki, physicalDevice, std::vector<vk::VkSurfaceKHR>(1u, surface));
}
std::vector<deUint32> getCompatibleQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, const std::vector<VkSurfaceKHR>& surfaces)
{
DE_ASSERT(!surfaces.empty());
auto indices = getSortedSupportedQueueFamilyIndices(vki, physicalDevice, surfaces[0]);
for (size_t i = 1; i < surfaces.size(); ++i)
{
auto newIndices = getSortedSupportedQueueFamilyIndices(vki, physicalDevice, surfaces[i]);
// Set intersection and overwrite.
decltype(indices) intersection;
std::set_intersection(begin(indices), end(indices), begin(newIndices), end(newIndices), std::back_inserter(intersection));
indices = std::move(intersection);
}
return indices;
}
tcu::UVec2 getFullScreenSize (const vk::wsi::Type wsiType, const vk::wsi::Display& display, const tcu::UVec2& fallbackSize)
{
tcu::UVec2 result = fallbackSize;
switch (wsiType)
{
case TYPE_XLIB:
{
#if defined (DEQP_SUPPORT_X11)
const XlibDisplayInterface& xlibDisplay = dynamic_cast<const XlibDisplayInterface&>(display);
::Display* displayPtr = (::Display*)(xlibDisplay.getNative().internal);
const Screen* screen = ScreenOfDisplay(displayPtr, 0);
result.x() = deUint32(screen->width);
result.y() = deUint32(screen->height);
#endif
break;
}
case TYPE_XCB:
{
#if defined (DEQP_SUPPORT_XCB)
// const XcbDisplayInterface& xcbDisplay = dynamic_cast<const XcbDisplayInterface&>(display);
// xcb_connection_t* connPtr = (xcb_connection_t*)(xcbDisplay.getNative().internal);
// xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(connPtr)).data;
// result.x() = deUint32(screen->width_in_pixels);
// result.y() = deUint32(screen->height_in_pixels);
#endif
break;
}
case TYPE_WAYLAND:
{
#if defined (DEQP_SUPPORT_WAYLAND)
#endif
break;
}
case TYPE_ANDROID:
{
#if ( DE_OS == DE_OS_ANDROID )
#endif
break;
}
case TYPE_WIN32:
{
#if ( DE_OS == DE_OS_WIN32 )
de::MovePtr<Window> nullWindow (display.createWindow(tcu::nothing<tcu::UVec2>()));
const Win32WindowInterface& win32Window = dynamic_cast<const Win32WindowInterface&>(*nullWindow);
HMONITOR hMonitor = (HMONITOR)MonitorFromWindow((HWND)win32Window.getNative().internal, MONITOR_DEFAULTTONEAREST);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hMonitor, &monitorInfo);
result.x() = deUint32(abs(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left));
result.y() = deUint32(abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom));
#endif
break;
}
case TYPE_MACOS:
{
#if ( DE_OS == DE_OS_OSX )
#endif
break;
}
default:
DE_FATAL("Unknown WSI type");
break;
}
DE_UNREF(display);
return result;
}
Move<VkRenderPass> WsiTriangleRenderer::createRenderPass (const DeviceInterface& vkd,
const VkDevice device,
const VkFormat colorAttachmentFormat,
const bool explicitLayoutTransitions)
{
const VkAttachmentDescription colorAttDesc =
{
(VkAttachmentDescriptionFlags)0,
colorAttachmentFormat,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_CLEAR,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
(explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
(explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
};
const VkAttachmentReference colorAttRef =
{
0u,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
};
const VkSubpassDescription subpassDesc =
{
(VkSubpassDescriptionFlags)0u,
VK_PIPELINE_BIND_POINT_GRAPHICS,
0u, // inputAttachmentCount
DE_NULL, // pInputAttachments
1u, // colorAttachmentCount
&colorAttRef, // pColorAttachments
DE_NULL, // pResolveAttachments
DE_NULL, // depthStencilAttachment
0u, // preserveAttachmentCount
DE_NULL, // pPreserveAttachments
};
const VkSubpassDependency dependencies[] =
{
{
VK_SUBPASS_EXTERNAL, // srcSubpass
0u, // dstSubpass
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_MEMORY_READ_BIT,
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
VK_DEPENDENCY_BY_REGION_BIT
},
{
0u, // srcSubpass
VK_SUBPASS_EXTERNAL, // dstSubpass
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
VK_ACCESS_MEMORY_READ_BIT,
VK_DEPENDENCY_BY_REGION_BIT
},
};
const VkRenderPassCreateInfo renderPassParams =
{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
DE_NULL,
(VkRenderPassCreateFlags)0,
1u,
&colorAttDesc,
1u,
&subpassDesc,
DE_LENGTH_OF_ARRAY(dependencies),
dependencies,
};
return vk::createRenderPass(vkd, device, &renderPassParams);
}
Move<VkPipelineLayout> WsiTriangleRenderer::createPipelineLayout (const DeviceInterface& vkd,
const VkDevice device)
{
const VkPushConstantRange pushConstantRange =
{
VK_SHADER_STAGE_VERTEX_BIT,
0u, // offset
(deUint32)sizeof(deUint32), // size
};
const VkPipelineLayoutCreateInfo pipelineLayoutParams =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(vk::VkPipelineLayoutCreateFlags)0,
0u, // setLayoutCount
DE_NULL, // pSetLayouts
1u,
&pushConstantRange,
};
return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
}
Move<VkPipeline> WsiTriangleRenderer::createPipeline (const DeviceInterface& vkd,
const VkDevice device,
const VkRenderPass renderPass,
const VkPipelineLayout pipelineLayout,
const BinaryCollection& binaryCollection,
const tcu::UVec2& renderSize)
{
// \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
// and can be deleted immediately following that call.
const Unique<VkShaderModule> vertShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
const Unique<VkShaderModule> fragShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
const std::vector<VkViewport> viewports (1, makeViewport(renderSize));
const std::vector<VkRect2D> scissors (1, makeRect2D(renderSize));
return vk::makeGraphicsPipeline(vkd, // const DeviceInterface& vk
device, // const VkDevice device
pipelineLayout, // const VkPipelineLayout pipelineLayout
*vertShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlShaderModule
DE_NULL, // const VkShaderModule tessellationEvalShaderModule
DE_NULL, // const VkShaderModule geometryShaderModule
*fragShaderModule, // const VkShaderModule fragmentShaderModule
renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors); // const std::vector<VkRect2D>& scissors
}
Move<VkImageView> WsiTriangleRenderer::createAttachmentView (const DeviceInterface& vkd,
const VkDevice device,
const VkImage image,
const VkFormat format)
{
const VkImageViewCreateInfo viewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
DE_NULL,
(VkImageViewCreateFlags)0,
image,
VK_IMAGE_VIEW_TYPE_2D,
format,
vk::makeComponentMappingRGBA(),
{
VK_IMAGE_ASPECT_COLOR_BIT,
0u, // baseMipLevel
1u, // levelCount
0u, // baseArrayLayer
1u, // layerCount
},
};
return vk::createImageView(vkd, device, &viewParams);
}
Move<VkFramebuffer> WsiTriangleRenderer::createFramebuffer (const DeviceInterface& vkd,
const VkDevice device,
const VkRenderPass renderPass,
const VkImageView colorAttachment,
const tcu::UVec2& renderSize)
{
const VkFramebufferCreateInfo framebufferParams =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
DE_NULL,
(VkFramebufferCreateFlags)0,
renderPass,
1u,
&colorAttachment,
renderSize.x(),
renderSize.y(),
1u, // layers
};
return vk::createFramebuffer(vkd, device, &framebufferParams);
}
Move<VkBuffer> WsiTriangleRenderer::createBuffer (const DeviceInterface& vkd,
VkDevice device,
VkDeviceSize size,
VkBufferUsageFlags usage)
{
const VkBufferCreateInfo bufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
(VkBufferCreateFlags)0,
size,
usage,
VK_SHARING_MODE_EXCLUSIVE,
0,
DE_NULL
};
return vk::createBuffer(vkd, device, &bufferParams);
}
WsiTriangleRenderer::WsiTriangleRenderer (const DeviceInterface& vkd,
const VkDevice device,
Allocator& allocator,
const BinaryCollection& binaryRegistry,
bool explicitLayoutTransitions,
const vector<VkImage> swapchainImages,
const vector<VkImage> aliasImages,
const VkFormat framebufferFormat,
const tcu::UVec2& renderSize)
: m_vkd (vkd)
, m_explicitLayoutTransitions (explicitLayoutTransitions)
, m_swapchainImages (swapchainImages)
, m_aliasImages (aliasImages)
, m_renderSize (renderSize)
, m_renderPass (createRenderPass(vkd, device, framebufferFormat, m_explicitLayoutTransitions))
, m_pipelineLayout (createPipelineLayout(vkd, device))
, m_pipeline (createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
, m_vertexBuffer (createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
, m_vertexBufferMemory (allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
MemoryRequirement::HostVisible))
{
m_attachmentViews.resize(swapchainImages.size());
m_attachmentLayouts.resize(swapchainImages.size());
m_framebuffers.resize(swapchainImages.size());
for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
{
m_attachmentViews[imageNdx] = ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_UNDEFINED;
m_framebuffers[imageNdx] = FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
}
VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
{
const VkMappedMemoryRange memRange =
{
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
DE_NULL,
m_vertexBufferMemory->getMemory(),
m_vertexBufferMemory->getOffset(),
VK_WHOLE_SIZE
};
const tcu::Vec4 vertices[] =
{
tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
};
DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
}
}
WsiTriangleRenderer::WsiTriangleRenderer (WsiTriangleRenderer&& other)
: m_vkd (other.m_vkd)
, m_explicitLayoutTransitions (other.m_explicitLayoutTransitions)
, m_swapchainImages (other.m_swapchainImages)
, m_aliasImages (other.m_aliasImages)
, m_renderSize (other.m_renderSize)
, m_renderPass (other.m_renderPass)
, m_pipelineLayout (other.m_pipelineLayout)
, m_pipeline (other.m_pipeline)
, m_vertexBuffer (other.m_vertexBuffer)
, m_vertexBufferMemory (other.m_vertexBufferMemory)
, m_attachmentViews (other.m_attachmentViews)
, m_attachmentLayouts (other.m_attachmentLayouts)
, m_framebuffers (other.m_framebuffers)
{
}
WsiTriangleRenderer::~WsiTriangleRenderer (void)
{
}
void WsiTriangleRenderer::recordFrame (VkCommandBuffer cmdBuffer,
deUint32 imageNdx,
deUint32 frameNdx) const
{
const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
beginCommandBuffer(m_vkd, cmdBuffer, 0u);
if (m_explicitLayoutTransitions || m_attachmentLayouts[imageNdx] == VK_IMAGE_LAYOUT_UNDEFINED)
{
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
const VkImageMemoryBarrier barrier = makeImageMemoryBarrier (0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
m_attachmentLayouts[imageNdx], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
m_aliasImages[imageNdx], range);
m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
{
const VkDeviceSize bindingOffset = 0;
m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
}
m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
endRenderPass(m_vkd, cmdBuffer);
if (m_explicitLayoutTransitions)
{
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
const VkImageMemoryBarrier barrier = makeImageMemoryBarrier (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0,
m_attachmentLayouts[imageNdx], VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
m_aliasImages[imageNdx], range);
m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
}
endCommandBuffer(m_vkd, cmdBuffer);
}
void WsiTriangleRenderer::recordDeviceGroupFrame (VkCommandBuffer cmdBuffer,
deUint32 firstDeviceID,
deUint32 secondDeviceID,
deUint32 devicesCount,
deUint32 imageNdx,
deUint32 frameNdx) const
{
const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
beginCommandBuffer(m_vkd, cmdBuffer, 0u);
if (m_explicitLayoutTransitions || m_attachmentLayouts[imageNdx] == VK_IMAGE_LAYOUT_UNDEFINED)
{
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
const VkImageMemoryBarrier barrier = makeImageMemoryBarrier (0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
m_attachmentLayouts[imageNdx], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
m_aliasImages[imageNdx], range);
m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
// begin renderpass
{
const VkClearValue clearValue = makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
VkRect2D zeroRect = { { 0, 0, },{ 0, 0, } };
vector<VkRect2D> renderAreas;
for (deUint32 i = 0; i < devicesCount; i++)
renderAreas.push_back(zeroRect);
// Render completely if there is only 1 device
if (devicesCount == 1u)
{
renderAreas[0].extent.width = (deInt32)m_renderSize.x();
renderAreas[0].extent.height = (deInt32)m_renderSize.y();
}
else
{
// Split into 2 vertical halves
renderAreas[firstDeviceID].extent.width = (deInt32)m_renderSize.x() / 2;
renderAreas[firstDeviceID].extent.height = (deInt32)m_renderSize.y();
renderAreas[secondDeviceID] = renderAreas[firstDeviceID];
renderAreas[secondDeviceID].offset.x = (deInt32)m_renderSize.x() / 2;
}
const VkDeviceGroupRenderPassBeginInfo deviceGroupRPBeginInfo =
{
VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO,
DE_NULL,
(deUint32)((1 << devicesCount) - 1),
devicesCount,
&renderAreas[0]
};
const VkRenderPassBeginInfo passBeginParams =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // sType
&deviceGroupRPBeginInfo, // pNext
*m_renderPass, // renderPass
curFramebuffer, // framebuffer
{
{ 0, 0 },
{ m_renderSize.x(), m_renderSize.y() }
}, // renderArea
1u, // clearValueCount
&clearValue, // pClearValues
};
m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
}
m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
{
const VkDeviceSize bindingOffset = 0;
m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
}
m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
endRenderPass(m_vkd, cmdBuffer);
if (m_explicitLayoutTransitions)
{
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
const VkImageMemoryBarrier barrier = makeImageMemoryBarrier (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0,
m_attachmentLayouts[imageNdx], VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
m_aliasImages[imageNdx], range);
m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
}
endCommandBuffer(m_vkd, cmdBuffer);
}
void WsiTriangleRenderer::getPrograms (SourceCollections& dst)
{
dst.glslSources.add("tri-vert") << glu::VertexSource(
"#version 310 es\n"
"layout(location = 0) in highp vec4 a_position;\n"
"layout(push_constant) uniform FrameData\n"
"{\n"
" highp uint frameNdx;\n"
"} frameData;\n"
"void main (void)\n"
"{\n"
" highp float angle = float(frameData.frameNdx) / 100.0;\n"
" highp float c = cos(angle);\n"
" highp float s = sin(angle);\n"
" highp mat4 t = mat4( c, -s, 0, 0,\n"
" s, c, 0, 0,\n"
" 0, 0, 1, 0,\n"
" 0, 0, 0, 1);\n"
" gl_Position = t * a_position;\n"
"}\n");
dst.glslSources.add("tri-frag") << glu::FragmentSource(
"#version 310 es\n"
"layout(location = 0) out lowp vec4 o_color;\n"
"void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
}
} // wsi
} // vk