st/egl: Update GDI backend to use resource_surface.
[mesa.git] / src / gallium / state_trackers / egl / gdi / native_gdi.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Chia-I Wu <olv@lunarg.com>
27 */
28
29 #include <windows.h>
30
31 #include "pipe/p_compiler.h"
32 #include "util/u_memory.h"
33 #include "util/u_format.h"
34 #include "util/u_inlines.h"
35 #include "target-helpers/wrap_screen.h"
36 #include "llvmpipe/lp_public.h"
37 #include "softpipe/sp_public.h"
38 #include "gdi/gdi_sw_winsys.h"
39
40 #include "common/native_helper.h"
41 #include "common/native.h"
42
43 struct gdi_display {
44 struct native_display base;
45
46 HDC hDC;
47 struct native_event_handler *event_handler;
48
49 struct native_config *configs;
50 int num_configs;
51 };
52
53 struct gdi_surface {
54 struct native_surface base;
55
56 HWND hWnd;
57 enum pipe_format color_format;
58
59 struct gdi_display *gdpy;
60
61 unsigned int server_stamp;
62 unsigned int client_stamp;
63
64 struct resource_surface *rsurf;
65 };
66
67 static INLINE struct gdi_display *
68 gdi_display(const struct native_display *ndpy)
69 {
70 return (struct gdi_display *) ndpy;
71 }
72
73 static INLINE struct gdi_surface *
74 gdi_surface(const struct native_surface *nsurf)
75 {
76 return (struct gdi_surface *) nsurf;
77 }
78
79 /**
80 * Update the geometry of the surface. This is a slow functions.
81 */
82 static void
83 gdi_surface_update_geometry(struct native_surface *nsurf)
84 {
85 struct gdi_surface *gsurf = gdi_surface(nsurf);
86 RECT rect;
87 uint w, h;
88
89 GetClientRect(gsurf->hWnd, &rect);
90 w = rect.right - rect.left;
91 h = rect.bottom - rect.top;
92
93 if (resource_surface_set_size(gsurf->rsurf, w, h))
94 gsurf->server_stamp++;
95 }
96
97 /**
98 * Update the buffers of the surface.
99 */
100 static boolean
101 gdi_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
102 {
103 struct gdi_surface *gsurf = gdi_surface(nsurf);
104 boolean ret;
105
106 gdi_surface_update_geometry(&gsurf->base);
107 ret = resource_surface_add_resources(gsurf->rsurf, buffer_mask);
108 gsurf->client_stamp = gsurf->server_stamp;
109
110 return ret;
111 }
112
113 /**
114 * Emulate an invalidate event.
115 */
116 static void
117 gdi_surface_invalidate(struct native_surface *nsurf)
118 {
119 struct gdi_surface *gsurf = gdi_surface(nsurf);
120 struct gdi_display *gdpy = gsurf->gdpy;
121
122 gsurf->server_stamp++;
123 gdpy->event_handler->invalid_surface(&gdpy->base,
124 &gsurf->base, gsurf->server_stamp);
125 }
126
127 static boolean
128 gdi_surface_flush_frontbuffer(struct native_surface *nsurf)
129 {
130 struct gdi_surface *gsurf = gdi_surface(nsurf);
131 HDC hDC;
132 boolean ret;
133
134 hDC = GetDC(gsurf->hWnd);
135 ret = resource_surface_present(gsurf->rsurf,
136 NATIVE_ATTACHMENT_FRONT_LEFT, (void *) hDC);
137 ReleaseDC(gsurf->hWnd, hDC);
138
139 /* force buffers to be updated in next validation call */
140 gdi_surface_invalidate(&gsurf->base);
141
142 return ret;
143 }
144
145 static boolean
146 gdi_surface_swap_buffers(struct native_surface *nsurf)
147 {
148 struct gdi_surface *gsurf = gdi_surface(nsurf);
149 HDC hDC;
150 boolean ret;
151
152 hDC = GetDC(gsurf->hWnd);
153 ret = resource_surface_present(gsurf->rsurf,
154 NATIVE_ATTACHMENT_BACK_LEFT, (void *) hDC);
155 ReleaseDC(gsurf->hWnd, hDC);
156
157 resource_surface_swap_buffers(gsurf->rsurf,
158 NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
159 /* the front/back buffers have been swapped */
160 gdi_surface_invalidate(&gsurf->base);
161
162 return ret;
163 }
164
165 static boolean
166 gdi_surface_validate(struct native_surface *nsurf, uint attachment_mask,
167 unsigned int *seq_num, struct pipe_resource **textures,
168 int *width, int *height)
169 {
170 struct gdi_surface *gsurf = gdi_surface(nsurf);
171 uint w, h;
172
173 if (gsurf->client_stamp != gsurf->server_stamp) {
174 if (!gdi_surface_update_buffers(&gsurf->base, attachment_mask))
175 return FALSE;
176 }
177
178 if (seq_num)
179 *seq_num = gsurf->client_stamp;
180
181 if (textures)
182 resource_surface_get_resources(gsurf->rsurf, textures, attachment_mask);
183
184 resource_surface_get_size(gsurf->rsurf, &w, &h);
185 if (width)
186 *width = w;
187 if (height)
188 *height = h;
189
190 return TRUE;
191 }
192
193 static void
194 gdi_surface_wait(struct native_surface *nsurf)
195 {
196 /* no-op */
197 }
198
199 static void
200 gdi_surface_destroy(struct native_surface *nsurf)
201 {
202 struct gdi_surface *gsurf = gdi_surface(nsurf);
203
204 resource_surface_destroy(gsurf->rsurf);
205 FREE(gsurf);
206 }
207
208 static struct native_surface *
209 gdi_display_create_window_surface(struct native_display *ndpy,
210 EGLNativeWindowType win,
211 const struct native_config *nconf)
212 {
213 struct gdi_display *gdpy = gdi_display(ndpy);
214 struct gdi_surface *gsurf;
215
216 gsurf = CALLOC_STRUCT(gdi_surface);
217 if (!gsurf)
218 return NULL;
219
220 gsurf->gdpy = gdpy;
221 gsurf->color_format = nconf->color_format;
222 gsurf->hWnd = (HWND) win;
223
224 gsurf->rsurf = resource_surface_create(gdpy->base.screen,
225 gsurf->color_format,
226 PIPE_BIND_RENDER_TARGET |
227 PIPE_BIND_SAMPLER_VIEW |
228 PIPE_BIND_DISPLAY_TARGET |
229 PIPE_BIND_SCANOUT);
230 if (!gsurf->rsurf) {
231 FREE(gsurf);
232 return NULL;
233 }
234
235 /* initialize the geometry */
236 gdi_surface_update_buffers(&gsurf->base, 0x0);
237
238 gsurf->base.destroy = gdi_surface_destroy;
239 gsurf->base.swap_buffers = gdi_surface_swap_buffers;
240 gsurf->base.flush_frontbuffer = gdi_surface_flush_frontbuffer;
241 gsurf->base.validate = gdi_surface_validate;
242 gsurf->base.wait = gdi_surface_wait;
243
244 return &gsurf->base;
245 }
246
247 static int
248 fill_color_formats(struct native_display *ndpy, enum pipe_format formats[8])
249 {
250 struct pipe_screen *screen = ndpy->screen;
251 int i, count = 0;
252
253 enum pipe_format candidates[] = {
254 /* 32-bit */
255 PIPE_FORMAT_B8G8R8A8_UNORM,
256 PIPE_FORMAT_A8R8G8B8_UNORM,
257 /* 24-bit */
258 PIPE_FORMAT_B8G8R8X8_UNORM,
259 PIPE_FORMAT_X8R8G8B8_UNORM,
260 /* 16-bit */
261 PIPE_FORMAT_B5G6R5_UNORM
262 };
263
264 assert(Elements(candidates) <= 8);
265
266 for (i = 0; i < Elements(candidates); i++) {
267 if (screen->is_format_supported(screen, candidates[i],
268 PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET, 0))
269 formats[count++] = candidates[i];
270 }
271
272 return count;
273 }
274
275 static const struct native_config **
276 gdi_display_get_configs(struct native_display *ndpy, int *num_configs)
277 {
278 struct gdi_display *gdpy = gdi_display(ndpy);
279 const struct native_config **configs;
280 int i;
281
282 /* first time */
283 if (!gdpy->configs) {
284 enum pipe_format formats[8];
285 int i, count;
286
287 count = fill_color_formats(&gdpy->base, formats);
288
289 gdpy->configs = CALLOC(count, sizeof(*gdpy->configs));
290 if (!gdpy->configs)
291 return NULL;
292
293 for (i = 0; i < count; i++) {
294 struct native_config *nconf = &gdpy->configs[i];
295
296 nconf->buffer_mask =
297 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
298 (1 << NATIVE_ATTACHMENT_BACK_LEFT);
299 nconf->color_format = formats[i];
300
301 nconf->window_bit = TRUE;
302 nconf->slow_config = TRUE;
303 }
304
305 gdpy->num_configs = count;
306 }
307
308 configs = MALLOC(gdpy->num_configs * sizeof(*configs));
309 if (configs) {
310 for (i = 0; i < gdpy->num_configs; i++)
311 configs[i] = (const struct native_config *) &gdpy->configs[i];
312 if (num_configs)
313 *num_configs = gdpy->num_configs;
314 }
315 return configs;
316 }
317
318 static int
319 gdi_display_get_param(struct native_display *ndpy,
320 enum native_param_type param)
321 {
322 int val;
323
324 switch (param) {
325 case NATIVE_PARAM_USE_NATIVE_BUFFER:
326 /* private buffers are allocated */
327 val = FALSE;
328 break;
329 default:
330 val = 0;
331 break;
332 }
333
334 return val;
335 }
336
337 static void
338 gdi_display_destroy(struct native_display *ndpy)
339 {
340 struct gdi_display *gdpy = gdi_display(ndpy);
341
342 if (gdpy->configs)
343 FREE(gdpy->configs);
344
345 gdpy->base.screen->destroy(gdpy->base.screen);
346
347 FREE(gdpy);
348 }
349
350 static struct native_display *
351 gdi_create_display(HDC hDC, struct pipe_screen *screen,
352 struct native_event_handler *event_handler)
353 {
354 struct gdi_display *gdpy;
355
356 gdpy = CALLOC_STRUCT(gdi_display);
357 if (!gdpy)
358 return NULL;
359
360 gdpy->hDC = hDC;
361 gdpy->event_handler = event_handler;
362
363 gdpy->base.screen = screen;
364
365 gdpy->base.destroy = gdi_display_destroy;
366 gdpy->base.get_param = gdi_display_get_param;
367
368 gdpy->base.get_configs = gdi_display_get_configs;
369 gdpy->base.create_window_surface = gdi_display_create_window_surface;
370
371 return &gdpy->base;
372 }
373
374 static struct pipe_screen *
375 gdi_create_screen(void)
376 {
377 struct sw_winsys *winsys;
378 struct pipe_screen *screen = NULL;
379
380 winsys = gdi_create_sw_winsys();
381 if (!winsys)
382 return NULL;
383
384 #if defined(GALLIUM_LLVMPIPE)
385 if (!screen && !debug_get_bool_option("GALLIUM_NO_LLVM", FALSE))
386 screen = llvmpipe_create_screen(winsys);
387 #endif
388 if (!screen)
389 screen = softpipe_create_screen(winsys);
390
391 if (!screen) {
392 if (winsys->destroy)
393 winsys->destroy(winsys);
394 return NULL;
395 }
396
397 return gallium_wrap_screen(screen);
398 }
399
400 struct native_probe *
401 native_create_probe(EGLNativeDisplayType dpy)
402 {
403 return NULL;
404 }
405
406 enum native_probe_result
407 native_get_probe_result(struct native_probe *nprobe)
408 {
409 return NATIVE_PROBE_UNKNOWN;
410 }
411
412 const char *
413 native_get_name(void)
414 {
415 return "GDI";
416 }
417
418 struct native_display *
419 native_create_display(EGLNativeDisplayType dpy,
420 struct native_event_handler *event_handler)
421 {
422 struct pipe_screen *screen;
423
424 screen = gdi_create_screen();
425 if (!screen)
426 return NULL;
427
428 return gdi_create_display((HDC) dpy, screen, event_handler);
429 }