vk: Move anv_x11.c to anv_wsi_x11.c
[mesa.git] / src / vulkan / anv_wsi_x11.c
1 /*
2 * Copyright © 2015 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "anv_private.h"
25
26 #include <xcb/xcb.h>
27 #include <xcb/dri3.h>
28 #include <xcb/present.h>
29
30 static const VkFormat formats[] = {
31 VK_FORMAT_B5G6R5_UNORM,
32 VK_FORMAT_B8G8R8A8_UNORM,
33 VK_FORMAT_B8G8R8A8_SRGB,
34 };
35
36 VkResult anv_GetDisplayInfoWSI(
37 VkDisplayWSI display,
38 VkDisplayInfoTypeWSI infoType,
39 size_t* pDataSize,
40 void* pData)
41 {
42 VkDisplayFormatPropertiesWSI *properties = pData;
43 size_t size;
44
45 if (pDataSize == NULL)
46 return VK_ERROR_INVALID_POINTER;
47
48 switch (infoType) {
49 case VK_DISPLAY_INFO_TYPE_FORMAT_PROPERTIES_WSI:
50 size = sizeof(properties[0]) * ARRAY_SIZE(formats);
51
52 if (pData == NULL) {
53 *pDataSize = size;
54 return VK_SUCCESS;
55 }
56
57 if (*pDataSize < size)
58 return vk_error(VK_ERROR_INVALID_VALUE);
59
60 *pDataSize = size;
61
62 for (uint32_t i = 0; i < ARRAY_SIZE(formats); i++)
63 properties[i].swapChainFormat = formats[i];
64
65 return VK_SUCCESS;
66
67 default:
68 return VK_UNSUPPORTED;
69 }
70 }
71
72 struct anv_swap_chain {
73 struct anv_device * device;
74 xcb_connection_t * conn;
75 xcb_window_t window;
76 xcb_gc_t gc;
77 VkExtent2D extent;
78 uint32_t count;
79 struct {
80 struct anv_image * image;
81 struct anv_device_memory * memory;
82 xcb_pixmap_t pixmap;
83 } images[0];
84 };
85
86 VkResult anv_CreateSwapChainWSI(
87 VkDevice _device,
88 const VkSwapChainCreateInfoWSI* pCreateInfo,
89 VkSwapChainWSI* pSwapChain)
90 {
91 ANV_FROM_HANDLE(anv_device, device, _device);
92
93 struct anv_swap_chain *chain;
94 xcb_void_cookie_t cookie;
95 VkResult result;
96 size_t size;
97 int ret;
98
99 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI);
100
101 size = sizeof(*chain) + pCreateInfo->imageCount * sizeof(chain->images[0]);
102 chain = anv_device_alloc(device, size, 8,
103 VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
104 if (chain == NULL)
105 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
106
107 chain->device = device;
108 chain->conn = (xcb_connection_t *) pCreateInfo->pNativeWindowSystemHandle;
109 chain->window = (xcb_window_t) (uintptr_t) pCreateInfo->pNativeWindowHandle;
110 chain->count = pCreateInfo->imageCount;
111 chain->extent = pCreateInfo->imageExtent;
112
113 for (uint32_t i = 0; i < chain->count; i++) {
114 VkDeviceMemory memory_h;
115 VkImage image_h;
116 struct anv_image *image;
117 struct anv_surface *surface;
118 struct anv_device_memory *memory;
119
120 anv_image_create(_device,
121 &(struct anv_image_create_info) {
122 .force_tile_mode = true,
123 .tile_mode = XMAJOR,
124 .stride = 0,
125 .vk_info =
126 &(VkImageCreateInfo) {
127 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
128 .imageType = VK_IMAGE_TYPE_2D,
129 .format = pCreateInfo->imageFormat,
130 .extent = {
131 .width = pCreateInfo->imageExtent.width,
132 .height = pCreateInfo->imageExtent.height,
133 .depth = 1
134 },
135 .mipLevels = 1,
136 .arraySize = 1,
137 .samples = 1,
138 /* FIXME: Need a way to use X tiling to allow scanout */
139 .tiling = VK_IMAGE_TILING_OPTIMAL,
140 .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
141 .flags = 0,
142 }},
143 &image_h);
144
145 image = anv_image_from_handle(image_h);
146 assert(anv_format_is_color(image->format));
147
148 surface = &image->color_surface;
149
150 anv_AllocMemory(_device,
151 &(VkMemoryAllocInfo) {
152 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
153 .allocationSize = image->size,
154 .memoryTypeIndex = 0,
155 },
156 &memory_h);
157
158 memory = anv_device_memory_from_handle(memory_h);
159
160 anv_BindImageMemory(VK_NULL_HANDLE, anv_image_to_handle(image),
161 memory_h, 0);
162
163 ret = anv_gem_set_tiling(device, memory->bo.gem_handle,
164 surface->stride, I915_TILING_X);
165 if (ret) {
166 result = vk_errorf(VK_ERROR_UNKNOWN, "set_tiling failed: %m");
167 goto fail;
168 }
169
170 int fd = anv_gem_handle_to_fd(device, memory->bo.gem_handle);
171 if (fd == -1) {
172 result = vk_errorf(VK_ERROR_UNKNOWN, "handle_to_fd failed: %m");
173 goto fail;
174 }
175
176 uint32_t bpp = 32;
177 uint32_t depth = 24;
178 xcb_pixmap_t pixmap = xcb_generate_id(chain->conn);
179
180 cookie =
181 xcb_dri3_pixmap_from_buffer_checked(chain->conn,
182 pixmap,
183 chain->window,
184 image->size,
185 pCreateInfo->imageExtent.width,
186 pCreateInfo->imageExtent.height,
187 surface->stride,
188 depth, bpp, fd);
189
190 chain->images[i].image = image;
191 chain->images[i].memory = memory;
192 chain->images[i].pixmap = pixmap;
193 image->swap_chain = chain;
194
195 xcb_discard_reply(chain->conn, cookie.sequence);
196 }
197
198 chain->gc = xcb_generate_id(chain->conn);
199 if (!chain->gc) {
200 result = vk_error(VK_ERROR_UNKNOWN);
201 goto fail;
202 }
203
204 cookie = xcb_create_gc(chain->conn,
205 chain->gc,
206 chain->window,
207 XCB_GC_GRAPHICS_EXPOSURES,
208 (uint32_t []) { 0 });
209 xcb_discard_reply(chain->conn, cookie.sequence);
210
211 *pSwapChain = anv_swap_chain_to_handle(chain);
212
213 return VK_SUCCESS;
214
215 fail:
216 return result;
217 }
218
219 VkResult anv_DestroySwapChainWSI(
220 VkSwapChainWSI _chain)
221 {
222 ANV_FROM_HANDLE(anv_swap_chain, chain, _chain);
223
224 anv_device_free(chain->device, chain);
225
226 return VK_SUCCESS;
227 }
228
229 VkResult anv_GetSwapChainInfoWSI(
230 VkSwapChainWSI _chain,
231 VkSwapChainInfoTypeWSI infoType,
232 size_t* pDataSize,
233 void* pData)
234 {
235 ANV_FROM_HANDLE(anv_swap_chain, chain, _chain);
236
237 VkSwapChainImageInfoWSI *images;
238 size_t size;
239
240 switch (infoType) {
241 case VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI:
242 size = sizeof(*images) * chain->count;
243 if (pData && *pDataSize < size)
244 return VK_ERROR_INVALID_VALUE;
245
246 *pDataSize = size;
247 if (!pData)
248 return VK_SUCCESS;
249
250 images = pData;
251 for (uint32_t i = 0; i < chain->count; i++) {
252 images[i].image = anv_image_to_handle(chain->images[i].image);
253 images[i].memory = anv_device_memory_to_handle(chain->images[i].memory);
254 }
255
256 return VK_SUCCESS;
257
258 default:
259 return VK_UNSUPPORTED;
260 }
261 }
262
263 VkResult anv_QueuePresentWSI(
264 VkQueue queue_,
265 const VkPresentInfoWSI* pPresentInfo)
266 {
267 ANV_FROM_HANDLE(anv_image, image, pPresentInfo->image);
268
269 struct anv_swap_chain *chain = image->swap_chain;
270 xcb_void_cookie_t cookie;
271 xcb_pixmap_t pixmap;
272
273 assert(pPresentInfo->sType == VK_STRUCTURE_TYPE_PRESENT_INFO_WSI);
274
275 if (chain == NULL)
276 return vk_error(VK_ERROR_INVALID_VALUE);
277
278 pixmap = XCB_NONE;
279 for (uint32_t i = 0; i < chain->count; i++) {
280 if (image == chain->images[i].image) {
281 pixmap = chain->images[i].pixmap;
282 break;
283 }
284 }
285
286 if (pixmap == XCB_NONE)
287 return vk_error(VK_ERROR_INVALID_VALUE);
288
289 cookie = xcb_copy_area(chain->conn,
290 pixmap,
291 chain->window,
292 chain->gc,
293 0, 0,
294 0, 0,
295 chain->extent.width,
296 chain->extent.height);
297 xcb_discard_reply(chain->conn, cookie.sequence);
298
299 xcb_flush(chain->conn);
300
301 return VK_SUCCESS;
302 }