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 "gdi/gdi_sw_winsys.h"
36 
37 #include "common/native_helper.h"
38 #include "common/native.h"
39 
40 struct gdi_display {
41    struct native_display base;
42 
43    HDC hDC;
44    const struct native_event_handler *event_handler;
45 
46    struct native_config *configs;
47    int num_configs;
48 };
49 
50 struct gdi_surface {
51    struct native_surface base;
52 
53    HWND hWnd;
54    enum pipe_format color_format;
55 
56    struct gdi_display *gdpy;
57 
58    unsigned int server_stamp;
59    unsigned int client_stamp;
60 
61    struct resource_surface *rsurf;
62 };
63 
64 static INLINE struct gdi_display *
gdi_display(const struct native_display * ndpy)65 gdi_display(const struct native_display *ndpy)
66 {
67    return (struct gdi_display *) ndpy;
68 }
69 
70 static INLINE struct gdi_surface *
gdi_surface(const struct native_surface * nsurf)71 gdi_surface(const struct native_surface *nsurf)
72 {
73    return (struct gdi_surface *) nsurf;
74 }
75 
76 /**
77  * Update the geometry of the surface.  This is a slow functions.
78  */
79 static void
gdi_surface_update_geometry(struct native_surface * nsurf)80 gdi_surface_update_geometry(struct native_surface *nsurf)
81 {
82    struct gdi_surface *gsurf = gdi_surface(nsurf);
83    RECT rect;
84    uint w, h;
85 
86    GetClientRect(gsurf->hWnd, &rect);
87    w = rect.right - rect.left;
88    h = rect.bottom - rect.top;
89 
90    if (resource_surface_set_size(gsurf->rsurf, w, h))
91       gsurf->server_stamp++;
92 }
93 
94 /**
95  * Update the buffers of the surface.
96  */
97 static boolean
gdi_surface_update_buffers(struct native_surface * nsurf,uint buffer_mask)98 gdi_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
99 {
100    struct gdi_surface *gsurf = gdi_surface(nsurf);
101 
102    if (gsurf->client_stamp != gsurf->server_stamp) {
103       gdi_surface_update_geometry(&gsurf->base);
104       gsurf->client_stamp = gsurf->server_stamp;
105    }
106 
107    return resource_surface_add_resources(gsurf->rsurf, buffer_mask);
108 }
109 
110 /**
111  * Emulate an invalidate event.
112  */
113 static void
gdi_surface_invalidate(struct native_surface * nsurf)114 gdi_surface_invalidate(struct native_surface *nsurf)
115 {
116    struct gdi_surface *gsurf = gdi_surface(nsurf);
117    struct gdi_display *gdpy = gsurf->gdpy;
118 
119    gsurf->server_stamp++;
120    gdpy->event_handler->invalid_surface(&gdpy->base,
121          &gsurf->base, gsurf->server_stamp);
122 }
123 
124 static boolean
gdi_surface_flush_frontbuffer(struct native_surface * nsurf)125 gdi_surface_flush_frontbuffer(struct native_surface *nsurf)
126 {
127    struct gdi_surface *gsurf = gdi_surface(nsurf);
128    HDC hDC;
129    boolean ret;
130 
131    hDC = GetDC(gsurf->hWnd);
132    ret = resource_surface_present(gsurf->rsurf,
133          NATIVE_ATTACHMENT_FRONT_LEFT, (void *) hDC);
134    ReleaseDC(gsurf->hWnd, hDC);
135 
136    /* force buffers to be updated in next validation call */
137    gdi_surface_invalidate(&gsurf->base);
138 
139    return ret;
140 }
141 
142 static boolean
gdi_surface_swap_buffers(struct native_surface * nsurf)143 gdi_surface_swap_buffers(struct native_surface *nsurf)
144 {
145    struct gdi_surface *gsurf = gdi_surface(nsurf);
146    HDC hDC;
147    boolean ret;
148 
149    hDC = GetDC(gsurf->hWnd);
150    ret = resource_surface_present(gsurf->rsurf,
151          NATIVE_ATTACHMENT_BACK_LEFT, (void *) hDC);
152    ReleaseDC(gsurf->hWnd, hDC);
153 
154    resource_surface_swap_buffers(gsurf->rsurf,
155          NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
156    /* the front/back buffers have been swapped */
157    gdi_surface_invalidate(&gsurf->base);
158 
159    return ret;
160 }
161 
162 static boolean
gdi_surface_present(struct native_surface * nsurf,const struct native_present_control * ctrl)163 gdi_surface_present(struct native_surface *nsurf,
164                     const struct native_present_control *ctrl)
165 {
166    boolean ret;
167 
168    if (ctrl->preserve || ctrl->swap_interval)
169       return FALSE;
170 
171    switch (ctrl->natt) {
172    case NATIVE_ATTACHMENT_FRONT_LEFT:
173       ret = gdi_surface_flush_frontbuffer(nsurf);
174       break;
175    case NATIVE_ATTACHMENT_BACK_LEFT:
176       ret = gdi_surface_swap_buffers(nsurf);
177       break;
178    default:
179       ret = FALSE;
180       break;
181    }
182 
183    return ret;
184 }
185 
186 static boolean
gdi_surface_validate(struct native_surface * nsurf,uint attachment_mask,unsigned int * seq_num,struct pipe_resource ** textures,int * width,int * height)187 gdi_surface_validate(struct native_surface *nsurf, uint attachment_mask,
188                         unsigned int *seq_num, struct pipe_resource **textures,
189                         int *width, int *height)
190 {
191    struct gdi_surface *gsurf = gdi_surface(nsurf);
192    uint w, h;
193 
194    if (!gdi_surface_update_buffers(&gsurf->base, attachment_mask))
195       return FALSE;
196 
197    if (seq_num)
198       *seq_num = gsurf->client_stamp;
199 
200    if (textures)
201       resource_surface_get_resources(gsurf->rsurf, textures, attachment_mask);
202 
203    resource_surface_get_size(gsurf->rsurf, &w, &h);
204    if (width)
205       *width = w;
206    if (height)
207       *height = h;
208 
209    return TRUE;
210 }
211 
212 static void
gdi_surface_wait(struct native_surface * nsurf)213 gdi_surface_wait(struct native_surface *nsurf)
214 {
215    /* no-op */
216 }
217 
218 static void
gdi_surface_destroy(struct native_surface * nsurf)219 gdi_surface_destroy(struct native_surface *nsurf)
220 {
221    struct gdi_surface *gsurf = gdi_surface(nsurf);
222 
223    resource_surface_destroy(gsurf->rsurf);
224    FREE(gsurf);
225 }
226 
227 static struct native_surface *
gdi_display_create_window_surface(struct native_display * ndpy,EGLNativeWindowType win,const struct native_config * nconf)228 gdi_display_create_window_surface(struct native_display *ndpy,
229                                   EGLNativeWindowType win,
230                                   const struct native_config *nconf)
231 {
232    struct gdi_display *gdpy = gdi_display(ndpy);
233    struct gdi_surface *gsurf;
234 
235    gsurf = CALLOC_STRUCT(gdi_surface);
236    if (!gsurf)
237       return NULL;
238 
239    gsurf->gdpy = gdpy;
240    gsurf->color_format = nconf->color_format;
241    gsurf->hWnd = (HWND) win;
242 
243    gsurf->rsurf = resource_surface_create(gdpy->base.screen,
244          gsurf->color_format,
245          PIPE_BIND_RENDER_TARGET |
246          PIPE_BIND_SAMPLER_VIEW |
247          PIPE_BIND_DISPLAY_TARGET |
248          PIPE_BIND_SCANOUT);
249    if (!gsurf->rsurf) {
250       FREE(gsurf);
251       return NULL;
252    }
253 
254    /* initialize the geometry */
255    gdi_surface_update_geometry(&gsurf->base);
256 
257    gsurf->base.destroy = gdi_surface_destroy;
258    gsurf->base.present = gdi_surface_present;
259    gsurf->base.validate = gdi_surface_validate;
260    gsurf->base.wait = gdi_surface_wait;
261 
262    return &gsurf->base;
263 }
264 
265 static int
fill_color_formats(struct native_display * ndpy,enum pipe_format formats[8])266 fill_color_formats(struct native_display *ndpy, enum pipe_format formats[8])
267 {
268    struct pipe_screen *screen = ndpy->screen;
269    int i, count = 0;
270 
271    enum pipe_format candidates[] = {
272       /* 32-bit */
273       PIPE_FORMAT_B8G8R8A8_UNORM,
274       PIPE_FORMAT_A8R8G8B8_UNORM,
275       /* 24-bit */
276       PIPE_FORMAT_B8G8R8X8_UNORM,
277       PIPE_FORMAT_X8R8G8B8_UNORM,
278       /* 16-bit */
279       PIPE_FORMAT_B5G6R5_UNORM
280    };
281 
282    assert(Elements(candidates) <= 8);
283 
284    for (i = 0; i < Elements(candidates); i++) {
285       if (screen->is_format_supported(screen, candidates[i],
286                PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET))
287          formats[count++] = candidates[i];
288    }
289 
290    return count;
291 }
292 
293 static const struct native_config **
gdi_display_get_configs(struct native_display * ndpy,int * num_configs)294 gdi_display_get_configs(struct native_display *ndpy, int *num_configs)
295 {
296    struct gdi_display *gdpy = gdi_display(ndpy);
297    const struct native_config **configs;
298    int i;
299 
300    /* first time */
301    if (!gdpy->configs) {
302       enum pipe_format formats[8];
303       int i, count;
304 
305       count = fill_color_formats(&gdpy->base, formats);
306 
307       gdpy->configs = CALLOC(count, sizeof(*gdpy->configs));
308       if (!gdpy->configs)
309          return NULL;
310 
311       for (i = 0; i < count; i++) {
312          struct native_config *nconf = &gdpy->configs[i];
313 
314          nconf->buffer_mask =
315             (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
316             (1 << NATIVE_ATTACHMENT_BACK_LEFT);
317          nconf->color_format = formats[i];
318 
319          nconf->window_bit = TRUE;
320       }
321 
322       gdpy->num_configs = count;
323    }
324 
325    configs = MALLOC(gdpy->num_configs * sizeof(*configs));
326    if (configs) {
327       for (i = 0; i < gdpy->num_configs; i++)
328          configs[i] = (const struct native_config *) &gdpy->configs[i];
329       if (num_configs)
330          *num_configs = gdpy->num_configs;
331    }
332    return configs;
333 }
334 
335 static int
gdi_display_get_param(struct native_display * ndpy,enum native_param_type param)336 gdi_display_get_param(struct native_display *ndpy,
337                          enum native_param_type param)
338 {
339    int val;
340 
341    switch (param) {
342    case NATIVE_PARAM_USE_NATIVE_BUFFER:
343       /* private buffers are allocated */
344       val = FALSE;
345       break;
346    case NATIVE_PARAM_PRESERVE_BUFFER:
347    case NATIVE_PARAM_MAX_SWAP_INTERVAL:
348    default:
349       val = 0;
350       break;
351    }
352 
353    return val;
354 }
355 
356 static void
gdi_display_destroy(struct native_display * ndpy)357 gdi_display_destroy(struct native_display *ndpy)
358 {
359    struct gdi_display *gdpy = gdi_display(ndpy);
360 
361    if (gdpy->configs)
362       FREE(gdpy->configs);
363 
364    ndpy_uninit(ndpy);
365 
366    FREE(gdpy);
367 }
368 
369 static boolean
gdi_display_init_screen(struct native_display * ndpy)370 gdi_display_init_screen(struct native_display *ndpy)
371 {
372    struct gdi_display *gdpy = gdi_display(ndpy);
373    struct sw_winsys *winsys;
374 
375    winsys = gdi_create_sw_winsys();
376    if (!winsys)
377       return FALSE;
378 
379    gdpy->base.screen = gdpy->event_handler->new_sw_screen(&gdpy->base, winsys);
380    if (!gdpy->base.screen) {
381       if (winsys->destroy)
382          winsys->destroy(winsys);
383       return FALSE;
384    }
385 
386    return TRUE;
387 }
388 
389 static struct native_display *
gdi_create_display(HDC hDC,const struct native_event_handler * event_handler)390 gdi_create_display(HDC hDC, const struct native_event_handler *event_handler)
391 {
392    struct gdi_display *gdpy;
393 
394    gdpy = CALLOC_STRUCT(gdi_display);
395    if (!gdpy)
396       return NULL;
397 
398    gdpy->hDC = hDC;
399    gdpy->event_handler = event_handler;
400 
401    gdpy->base.init_screen = gdi_display_init_screen;
402    gdpy->base.destroy = gdi_display_destroy;
403    gdpy->base.get_param = gdi_display_get_param;
404 
405    gdpy->base.get_configs = gdi_display_get_configs;
406    gdpy->base.create_window_surface = gdi_display_create_window_surface;
407 
408    return &gdpy->base;
409 }
410 
411 static const struct native_event_handler *gdi_event_handler;
412 
413 static struct native_display *
native_create_display(void * dpy,boolean use_sw)414 native_create_display(void *dpy, boolean use_sw)
415 {
416    return gdi_create_display((HDC) dpy, gdi_event_handler);
417 }
418 
419 static const struct native_platform gdi_platform = {
420    "GDI", /* name */
421    native_create_display
422 };
423 
424 const struct native_platform *
native_get_gdi_platform(const struct native_event_handler * event_handler)425 native_get_gdi_platform(const struct native_event_handler *event_handler)
426 {
427    gdi_event_handler = event_handler;
428    return &gdi_platform;
429 }
430