blob: 2b433bd244bf4674f60cee6451d0573de86104c2 [file] [log] [blame]
Jamie Madill9e54b5a2016-05-25 12:57:39 -04001//
2// Copyright 2016 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// SurfaceVk.cpp:
7// Implements the class methods for SurfaceVk.
8//
9
10#include "libANGLE/renderer/vulkan/SurfaceVk.h"
11
12#include "common/debug.h"
Jamie Madill4d0bf552016-12-28 15:45:24 -050013#include "libANGLE/Surface.h"
14#include "libANGLE/renderer/vulkan/DisplayVk.h"
Jamie Madille09bd5d2016-11-29 16:20:35 -050015#include "libANGLE/renderer/vulkan/FramebufferVk.h"
16#include "libANGLE/renderer/vulkan/RendererVk.h"
Jamie Madill9e54b5a2016-05-25 12:57:39 -040017
18namespace rx
19{
20
Jamie Madill4d0bf552016-12-28 15:45:24 -050021namespace
22{
23
24VkFormat GetVkFormatFromConfig(const egl::Config &config)
25{
26 // TODO(jmadill): Properly handle format interpretation.
27 return VK_FORMAT_B8G8R8A8_UNORM;
28}
29
30} // namespace
31
Jamie Madille09bd5d2016-11-29 16:20:35 -050032OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState,
33 EGLint width,
34 EGLint height)
35 : SurfaceImpl(surfaceState), mWidth(width), mHeight(height)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040036{
37}
38
Jamie Madille09bd5d2016-11-29 16:20:35 -050039OffscreenSurfaceVk::~OffscreenSurfaceVk()
Jamie Madill9e54b5a2016-05-25 12:57:39 -040040{
41}
42
Jamie Madille09bd5d2016-11-29 16:20:35 -050043egl::Error OffscreenSurfaceVk::initialize(const DisplayImpl *displayImpl)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040044{
Jamie Madille09bd5d2016-11-29 16:20:35 -050045 return egl::Error(EGL_SUCCESS);
Jamie Madill9e54b5a2016-05-25 12:57:39 -040046}
47
Jamie Madille09bd5d2016-11-29 16:20:35 -050048FramebufferImpl *OffscreenSurfaceVk::createDefaultFramebuffer(const gl::FramebufferState &state)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040049{
Jamie Madille09bd5d2016-11-29 16:20:35 -050050 return new FramebufferVk(state);
Jamie Madill9e54b5a2016-05-25 12:57:39 -040051}
52
Jamie Madille09bd5d2016-11-29 16:20:35 -050053egl::Error OffscreenSurfaceVk::swap(const DisplayImpl *displayImpl)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040054{
Jamie Madille09bd5d2016-11-29 16:20:35 -050055 return egl::Error(EGL_SUCCESS);
Jamie Madill9e54b5a2016-05-25 12:57:39 -040056}
57
Jamie Madille09bd5d2016-11-29 16:20:35 -050058egl::Error OffscreenSurfaceVk::postSubBuffer(EGLint /*x*/,
59 EGLint /*y*/,
60 EGLint /*width*/,
61 EGLint /*height*/)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040062{
Jamie Madille09bd5d2016-11-29 16:20:35 -050063 return egl::Error(EGL_SUCCESS);
Jamie Madill9e54b5a2016-05-25 12:57:39 -040064}
65
Jamie Madille09bd5d2016-11-29 16:20:35 -050066egl::Error OffscreenSurfaceVk::querySurfacePointerANGLE(EGLint /*attribute*/, void ** /*value*/)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040067{
Jamie Madille09bd5d2016-11-29 16:20:35 -050068 UNREACHABLE();
69 return egl::Error(EGL_BAD_CURRENT_SURFACE);
Jamie Madill9e54b5a2016-05-25 12:57:39 -040070}
71
Jamie Madille09bd5d2016-11-29 16:20:35 -050072egl::Error OffscreenSurfaceVk::bindTexImage(gl::Texture * /*texture*/, EGLint /*buffer*/)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040073{
Jamie Madille09bd5d2016-11-29 16:20:35 -050074 return egl::Error(EGL_SUCCESS);
Jamie Madill9e54b5a2016-05-25 12:57:39 -040075}
76
Jamie Madille09bd5d2016-11-29 16:20:35 -050077egl::Error OffscreenSurfaceVk::releaseTexImage(EGLint /*buffer*/)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040078{
Jamie Madille09bd5d2016-11-29 16:20:35 -050079 return egl::Error(EGL_SUCCESS);
Jamie Madill9e54b5a2016-05-25 12:57:39 -040080}
81
Jamie Madille09bd5d2016-11-29 16:20:35 -050082void OffscreenSurfaceVk::setSwapInterval(EGLint /*interval*/)
Jamie Madill9e54b5a2016-05-25 12:57:39 -040083{
Jamie Madill9e54b5a2016-05-25 12:57:39 -040084}
85
Jamie Madille09bd5d2016-11-29 16:20:35 -050086EGLint OffscreenSurfaceVk::getWidth() const
Jamie Madill9e54b5a2016-05-25 12:57:39 -040087{
Jamie Madille09bd5d2016-11-29 16:20:35 -050088 return mWidth;
Jamie Madill9e54b5a2016-05-25 12:57:39 -040089}
90
Jamie Madille09bd5d2016-11-29 16:20:35 -050091EGLint OffscreenSurfaceVk::getHeight() const
Jamie Madill9e54b5a2016-05-25 12:57:39 -040092{
Jamie Madille09bd5d2016-11-29 16:20:35 -050093 return mHeight;
Jamie Madill9e54b5a2016-05-25 12:57:39 -040094}
95
Jamie Madille09bd5d2016-11-29 16:20:35 -050096EGLint OffscreenSurfaceVk::isPostSubBufferSupported() const
Jamie Madill9e54b5a2016-05-25 12:57:39 -040097{
Jamie Madille09bd5d2016-11-29 16:20:35 -050098 return EGL_FALSE;
Jamie Madill9e54b5a2016-05-25 12:57:39 -040099}
100
Jamie Madille09bd5d2016-11-29 16:20:35 -0500101EGLint OffscreenSurfaceVk::getSwapBehavior() const
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400102{
Jamie Madille09bd5d2016-11-29 16:20:35 -0500103 return EGL_BUFFER_PRESERVED;
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400104}
105
Jamie Madille09bd5d2016-11-29 16:20:35 -0500106gl::Error OffscreenSurfaceVk::getAttachmentRenderTarget(
107 const gl::FramebufferAttachment::Target & /*target*/,
108 FramebufferAttachmentRenderTarget ** /*rtOut*/)
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400109{
Jamie Madille09bd5d2016-11-29 16:20:35 -0500110 UNREACHABLE();
111 return gl::Error(GL_INVALID_OPERATION);
112}
113
Jamie Madill4d0bf552016-12-28 15:45:24 -0500114WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
115 EGLNativeWindowType window,
116 EGLint width,
117 EGLint height)
118 : SurfaceImpl(surfaceState),
119 mNativeWindowType(window),
120 mWidth(width),
121 mHeight(height),
122 mSurface(VK_NULL_HANDLE),
123 mSwapchain(VK_NULL_HANDLE),
124 mDevice(VK_NULL_HANDLE),
125 mInstance(VK_NULL_HANDLE)
Jamie Madille09bd5d2016-11-29 16:20:35 -0500126{
127}
128
129WindowSurfaceVk::~WindowSurfaceVk()
130{
Jamie Madill4d0bf552016-12-28 15:45:24 -0500131 mSwapchainImages.clear();
132
133 if (mSwapchain)
134 {
135 vkDestroySwapchainKHR(mDevice, mSwapchain, nullptr);
136 mSwapchain = VK_NULL_HANDLE;
137 }
138
139 if (mSurface)
140 {
141 vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
142 mSurface = VK_NULL_HANDLE;
143 }
Jamie Madille09bd5d2016-11-29 16:20:35 -0500144}
145
146egl::Error WindowSurfaceVk::initialize(const DisplayImpl *displayImpl)
147{
Jamie Madill4d0bf552016-12-28 15:45:24 -0500148 const DisplayVk *displayVk = GetAs<DisplayVk>(displayImpl);
149 return initializeImpl(displayVk->getRenderer()).toEGL(EGL_BAD_SURFACE);
150}
151
152vk::Error WindowSurfaceVk::initializeImpl(RendererVk *renderer)
153{
154 // These are needed for resource deallocation.
155 // TODO(jmadill): Don't cache these.
156 mDevice = renderer->getDevice();
157 mInstance = renderer->getInstance();
158
159 // TODO(jmadill): Make this platform-specific.
160 VkWin32SurfaceCreateInfoKHR createInfo;
161
162 createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
163 createInfo.pNext = nullptr;
164 createInfo.flags = 0;
165 createInfo.hinstance = GetModuleHandle(nullptr);
166 createInfo.hwnd = mNativeWindowType;
167 ANGLE_VK_TRY(vkCreateWin32SurfaceKHR(renderer->getInstance(), &createInfo, nullptr, &mSurface));
168
169 uint32_t presentQueue = 0;
170 ANGLE_TRY_RESULT(renderer->selectPresentQueueForSurface(mSurface), presentQueue);
171
172 const auto &physicalDevice = renderer->getPhysicalDevice();
173
174 VkSurfaceCapabilitiesKHR surfaceCaps;
175 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, &surfaceCaps));
176
177 // Adjust width and height to the swapchain if necessary.
178 if (surfaceCaps.currentExtent.width != 0xFFFFFFFFu)
179 {
180 ASSERT(surfaceCaps.currentExtent.height != 0xFFFFFFFFu);
181 mWidth = static_cast<EGLint>(surfaceCaps.currentExtent.width);
182 mHeight = static_cast<EGLint>(surfaceCaps.currentExtent.height);
183 }
184 else
185 {
186 ASSERT(surfaceCaps.currentExtent.height == 0xFFFFFFFFu);
187
188 RECT rect;
189 ANGLE_VK_CHECK(GetClientRect(mNativeWindowType, &rect) == TRUE,
190 VK_ERROR_INITIALIZATION_FAILED);
191 if (mWidth == 0)
192 {
193 mWidth = static_cast<EGLint>(rect.right - rect.left);
194 }
195 if (mHeight == 0)
196 {
197 mHeight = static_cast<EGLint>(rect.bottom - rect.top);
198 }
199 }
200
201 uint32_t presentModeCount = 0;
202 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface,
203 &presentModeCount, nullptr));
204 ASSERT(presentModeCount > 0);
205
206 std::vector<VkPresentModeKHR> presentModes(presentModeCount);
207 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface,
208 &presentModeCount, presentModes.data()));
209
210 // Use FIFO mode if available, since it throttles you to the display rate. Mailbox can lead
211 // to rendering frames which are never seen by the user, wasting power.
212 VkPresentModeKHR swapchainPresentMode = presentModes[0];
213 for (auto presentMode : presentModes)
214 {
215 if (presentMode == VK_PRESENT_MODE_FIFO_KHR)
216 {
217 swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
218 break;
219 }
220
221 // Fallback to immediate mode if FIFO is unavailable.
222 if (presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR)
223 {
224 swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
225 }
226 }
227
228 // Determine number of swapchain images. Aim for one more than the minimum.
229 uint32_t minImageCount = surfaceCaps.minImageCount + 1;
230 if (surfaceCaps.maxImageCount > 0 && minImageCount > surfaceCaps.maxImageCount)
231 {
232 minImageCount = surfaceCaps.maxImageCount;
233 }
234
235 // Default to identity transform.
236 VkSurfaceTransformFlagBitsKHR preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
237 if ((surfaceCaps.supportedTransforms & preTransform) == 0)
238 {
239 preTransform = surfaceCaps.currentTransform;
240 }
241
242 VkFormat configSurfaceFormat = GetVkFormatFromConfig(*mState.config);
243
244 uint32_t surfaceFormatCount = 0;
245 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount,
246 nullptr));
247
248 std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
249 ANGLE_VK_TRY(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount,
250 surfaceFormats.data()));
251
252 if (surfaceFormatCount == 1u && surfaceFormats[0].format == VK_FORMAT_UNDEFINED)
253 {
254 // This is fine.
255 }
256 else
257 {
258 bool foundFormat = false;
259 for (const auto &surfaceFormat : surfaceFormats)
260 {
261 if (surfaceFormat.format == configSurfaceFormat)
262 {
263 foundFormat = true;
264 break;
265 }
266 }
267
268 ANGLE_VK_CHECK(foundFormat, VK_ERROR_INITIALIZATION_FAILED);
269 }
270
271 VkSwapchainCreateInfoKHR swapchainInfo;
272 swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
273 swapchainInfo.pNext = nullptr;
274 swapchainInfo.flags = 0;
275 swapchainInfo.surface = mSurface;
276 swapchainInfo.minImageCount = minImageCount;
277 swapchainInfo.imageFormat = configSurfaceFormat;
278 swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
279 swapchainInfo.imageExtent.width = mWidth;
280 swapchainInfo.imageExtent.height = mHeight;
281 swapchainInfo.imageArrayLayers = 1;
282 swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
283 swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
284 swapchainInfo.queueFamilyIndexCount = 0;
285 swapchainInfo.pQueueFamilyIndices = nullptr;
286 swapchainInfo.preTransform = preTransform;
287 swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
288 swapchainInfo.presentMode = swapchainPresentMode;
289 swapchainInfo.clipped = VK_TRUE;
290 swapchainInfo.oldSwapchain = VK_NULL_HANDLE;
291
292 const auto &device = renderer->getDevice();
293 ANGLE_VK_TRY(vkCreateSwapchainKHR(device, &swapchainInfo, nullptr, &mSwapchain));
294
295 // Intialize the swapchain image views.
296 uint32_t imageCount = 0;
297 ANGLE_VK_TRY(vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, nullptr));
298
299 std::vector<VkImage> swapchainImages(imageCount);
300 ANGLE_VK_TRY(vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data()));
301
302 // CommandBuffer is a singleton in the Renderer.
303 vk::CommandBuffer *commandBuffer = renderer->getCommandBuffer();
304 ANGLE_TRY(commandBuffer->begin());
305
306 for (auto swapchainImage : swapchainImages)
307 {
308 VkImageViewCreateInfo imageViewInfo;
309 imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
310 imageViewInfo.pNext = nullptr;
311 imageViewInfo.flags = 0;
312 imageViewInfo.image = swapchainImage;
313 imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
314 imageViewInfo.format = configSurfaceFormat;
315 imageViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
316 imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
317 imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
318 imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
319 imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
320 imageViewInfo.subresourceRange.baseMipLevel = 0;
321 imageViewInfo.subresourceRange.levelCount = 1;
322 imageViewInfo.subresourceRange.baseArrayLayer = 0;
323 imageViewInfo.subresourceRange.layerCount = 1;
324
325 vk::Image image(swapchainImage);
326 vk::ImageView imageView(device);
327 ANGLE_TRY(imageView.init(imageViewInfo));
328
329 // Set optimal color layout for the image.
330 image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
331 commandBuffer);
332
333 mSwapchainImages.push_back(std::move(image));
334 mSwapchainImageViews.push_back(std::move(imageView));
335 }
336
337 ANGLE_TRY(commandBuffer->end());
338 ANGLE_TRY(renderer->submitAndFinishCommandBuffer(*commandBuffer));
339
340 return vk::NoError();
Jamie Madille09bd5d2016-11-29 16:20:35 -0500341}
342
343FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::FramebufferState &state)
344{
345 return new FramebufferVk(state);
346}
347
348egl::Error WindowSurfaceVk::swap(const DisplayImpl *displayImpl)
349{
350 // TODO(jmadill)
351 return egl::Error(EGL_SUCCESS);
352}
353
354egl::Error WindowSurfaceVk::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
355{
356 // TODO(jmadill)
357 return egl::Error(EGL_SUCCESS);
358}
359
360egl::Error WindowSurfaceVk::querySurfacePointerANGLE(EGLint attribute, void **value)
361{
362 UNREACHABLE();
363 return egl::Error(EGL_BAD_CURRENT_SURFACE);
364}
365
366egl::Error WindowSurfaceVk::bindTexImage(gl::Texture *texture, EGLint buffer)
367{
368 return egl::Error(EGL_SUCCESS);
369}
370
371egl::Error WindowSurfaceVk::releaseTexImage(EGLint buffer)
372{
373 return egl::Error(EGL_SUCCESS);
374}
375
376void WindowSurfaceVk::setSwapInterval(EGLint interval)
377{
378}
379
380EGLint WindowSurfaceVk::getWidth() const
381{
Jamie Madill4d0bf552016-12-28 15:45:24 -0500382 return mWidth;
Jamie Madille09bd5d2016-11-29 16:20:35 -0500383}
384
385EGLint WindowSurfaceVk::getHeight() const
386{
Jamie Madill4d0bf552016-12-28 15:45:24 -0500387 return mHeight;
Jamie Madille09bd5d2016-11-29 16:20:35 -0500388}
389
390EGLint WindowSurfaceVk::isPostSubBufferSupported() const
391{
392 // TODO(jmadill)
393 return EGL_FALSE;
394}
395
396EGLint WindowSurfaceVk::getSwapBehavior() const
397{
398 // TODO(jmadill)
399 return EGL_BUFFER_DESTROYED;
400}
401
402gl::Error WindowSurfaceVk::getAttachmentRenderTarget(
403 const gl::FramebufferAttachment::Target &target,
404 FramebufferAttachmentRenderTarget **rtOut)
405{
406 UNREACHABLE();
Jamie Madill9e54b5a2016-05-25 12:57:39 -0400407 return gl::Error(GL_INVALID_OPERATION);
408}
409
410} // namespace rx