1 // Copyright 2014 Emil Velikov
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // - Redistributions of source code must retain the above copyright notice, this
9 //   list of conditions and the following disclaimer.
10 //
11 // - Redistributions in binary form must reproduce the above copyright notice,
12 //   this list of conditions and the following disclaimer in the documentation
13 //   and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <windows.h>
30 
31 #include "wcore_config_attrs.h"
32 #include "wcore_error.h"
33 
34 #include "wgl_config.h"
35 #include "wgl_context.h"
36 #include "wgl_display.h"
37 #include "wgl_error.h"
38 #include "wgl_platform.h"
39 #include "wgl_window.h"
40 
41 bool
wgl_config_destroy(struct wcore_config * wc_self)42 wgl_config_destroy(struct wcore_config *wc_self)
43 {
44     struct wgl_config *self = wgl_config(wc_self);
45     bool ok = true;
46 
47     if (!self)
48         return true;
49 
50     if (self->window)
51         ok &= wgl_window_priv_destroy(&self->window->wcore);
52 
53     ok &= wcore_config_teardown(wc_self);
54     free(self);
55     return ok;
56 }
57 
58 /// @brief Check the values of `attrs->context_*`.
59 static bool
wgl_config_check_context_attrs(struct wgl_display * dpy,const struct wcore_config_attrs * attrs)60 wgl_config_check_context_attrs(struct wgl_display *dpy,
61                                const struct wcore_config_attrs *attrs)
62 {
63     if (!dpy->ARB_create_context &&
64         wgl_context_needs_arb_create_context(attrs)) {
65         const char *gl = "";
66         const char *fwd_compat = "";
67         const char *debug = "";
68         const char *robust = "";
69 
70         // XXX: Keep in sync with glx_context_needs_arb_create_context()
71         if (attrs->context_api != WAFFLE_CONTEXT_OPENGL)
72 	    gl = " - a OpenGL ES* context\n";
73         else if (wcore_config_attrs_version_ge(attrs, 32))
74             gl = " - a OpenGL 3.2+ context\n";
75 
76         if (attrs->context_forward_compatible)
77             fwd_compat = " - a forward-compatible context\n";
78 
79         if (attrs->context_debug)
80             debug = " - a debug context\n";
81 
82         if (attrs->context_robust)
83             robust = " - a robust access context\n";
84 
85         wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
86                      "WGL_ARB_create_context is required to create:\n"
87                      "%s%s%s%s", gl, fwd_compat, debug, robust);
88         return false;
89     }
90 
91     if (attrs->context_robust && !dpy->ARB_create_context_robustness) {
92         wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
93                      "WGL_ARB_create_context_robustness is required in order to "
94                      "request a robust access context");
95         return false;
96     }
97 
98     switch (attrs->context_api) {
99         case WAFFLE_CONTEXT_OPENGL:
100             if (wcore_config_attrs_version_ge(attrs, 32) && !dpy->ARB_create_context_profile) {
101                 wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
102                              "WGL_ARB_create_context_profile is required "
103                              "to create a context with version >= 3.2");
104                 return false;
105             }
106 
107             return true;
108 
109         case WAFFLE_CONTEXT_OPENGL_ES1:
110         case WAFFLE_CONTEXT_OPENGL_ES2:
111         case WAFFLE_CONTEXT_OPENGL_ES3:
112             if (!dpy->EXT_create_context_es_profile &&
113                 !dpy->EXT_create_context_es2_profile) {
114                 wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
115                              "WGL_EXT_create_context_es_profile or "
116                              "WGL_EXT_create_context_es2_profile is required "
117                              "to create an OpenGL ES* context");
118                 return false;
119             }
120 
121             return true;
122 
123         default:
124             assert(false);
125             return false;
126     }
127 }
128 
129 static void
wgl_config_set_pixeldescriptor(struct wgl_config * config,const struct wcore_config_attrs * attrs)130 wgl_config_set_pixeldescriptor(struct wgl_config *config,
131                                const struct wcore_config_attrs *attrs)
132 {
133     PIXELFORMATDESCRIPTOR *pfd = &config->pfd;
134 
135     pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
136     pfd->nVersion = 1;
137 
138     pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
139     if (attrs->double_buffered)
140         pfd->dwFlags |= PFD_DOUBLEBUFFER;
141 
142     pfd->iPixelType = PFD_TYPE_RGBA;
143 
144     pfd->cColorBits        = attrs->rgba_size;
145     pfd->cRedBits          = attrs->red_size;
146     pfd->cGreenBits        = attrs->green_size;
147     pfd->cBlueBits         = attrs->blue_size;
148     pfd->cAlphaBits        = attrs->alpha_size;
149 
150     pfd->cDepthBits        = attrs->depth_size;
151     pfd->cStencilBits      = attrs->stencil_size;
152 
153     // XXX: Double check these
154     pfd->cAccumRedBits     = attrs->accum_buffer;
155     pfd->cAccumGreenBits   = attrs->accum_buffer;
156     pfd->cAccumBlueBits    = attrs->accum_buffer;
157     pfd->cAccumAlphaBits   = attrs->accum_buffer;
158     pfd->cAccumBits        = pfd->cAccumRedBits +
159                              pfd->cAccumGreenBits +
160                              pfd->cAccumBlueBits +
161                              pfd->cAccumAlphaBits;
162 
163     pfd->iLayerType = PFD_MAIN_PLANE;
164 }
165 
166 static bool
wgl_config_choose_native(struct wgl_config * config,struct wgl_display * dpy,const struct wcore_config_attrs * attrs)167 wgl_config_choose_native(struct wgl_config *config,
168                          struct wgl_display *dpy,
169                          const struct wcore_config_attrs *attrs)
170 {
171 
172     // Use wglChoosePixelFormatARB if available.
173     if (dpy->ARB_pixel_format) {
174         float fAttribs[1] = { 0 };
175         int iAttribs[] = {
176             WGL_COLOR_BITS_ARB,         attrs->rgba_size,
177             WGL_RED_BITS_ARB,           attrs->red_size,
178             WGL_GREEN_BITS_ARB,         attrs->green_size,
179             WGL_BLUE_BITS_ARB,          attrs->blue_size,
180             WGL_ALPHA_BITS_ARB,         attrs->alpha_size,
181 
182             WGL_DEPTH_BITS_ARB,         attrs->depth_size,
183             WGL_STENCIL_BITS_ARB,       attrs->stencil_size,
184 
185             WGL_SAMPLE_BUFFERS_ARB,     attrs->sample_buffers,
186             WGL_STEREO_ARB,             attrs->samples,
187 
188             WGL_DOUBLE_BUFFER_ARB,      attrs->double_buffered,
189 
190             WGL_ACCUM_RED_BITS_ARB,     attrs->accum_buffer,
191             WGL_ACCUM_GREEN_BITS_ARB,   attrs->accum_buffer,
192             WGL_ACCUM_BLUE_BITS_ARB,    attrs->accum_buffer,
193             WGL_ACCUM_ALPHA_BITS_ARB,   attrs->accum_buffer,
194 
195             WGL_DRAW_TO_WINDOW_ARB,     GL_TRUE,
196             WGL_ACCELERATION_ARB,       WGL_FULL_ACCELERATION_ARB,
197 
198             0,
199         };
200         unsigned int num_formats;
201         bool ok;
202 
203         // But first we need a current context to use it...
204         ok = wglMakeCurrent(dpy->hDC, dpy->hglrc);
205         if (!ok)
206             return false;
207 
208         ok = dpy->wglChoosePixelFormatARB(dpy->hDC, iAttribs, fAttribs, 1,
209                                           &config->pixel_format, &num_formats);
210 
211         wglMakeCurrent(NULL, NULL);
212 
213         if (!ok || !num_formats) {
214             wcore_errorf(WAFFLE_ERROR_UNKNOWN,
215                          "wglChoosePixelFormatARB failed");
216             return false;
217         }
218 
219     }
220     else {
221         config->pixel_format = ChoosePixelFormat(dpy->hDC, &config->pfd);
222         if (!config->pixel_format) {
223             wcore_errorf(WAFFLE_ERROR_UNKNOWN,
224                          "ChoosePixelFormat failed to find a matching format");
225             return false;
226         }
227     }
228 
229     return true;
230 }
231 
232 
233 struct wcore_config*
wgl_config_choose(struct wcore_platform * wc_plat,struct wcore_display * wc_dpy,const struct wcore_config_attrs * attrs)234 wgl_config_choose(struct wcore_platform *wc_plat,
235                   struct wcore_display *wc_dpy,
236                   const struct wcore_config_attrs *attrs)
237 {
238     struct wgl_config *self;
239     struct wgl_display *dpy = wgl_display(wc_dpy);
240     struct wcore_window *wc_window;
241     bool ok;
242 
243     ok = wgl_config_check_context_attrs(dpy, attrs);
244     if (!ok)
245         return NULL;
246 
247     self = wcore_calloc(sizeof(*self));
248     if (!self)
249         return NULL;
250 
251     ok = wcore_config_init(&self->wcore, wc_dpy, attrs);
252     if (!ok)
253         goto error;
254 
255     wgl_config_set_pixeldescriptor(self, attrs);
256 
257     ok = wgl_config_choose_native(self, dpy, attrs);
258     if (!ok)
259         goto error;
260 
261     // Hurray, we've got the pixel format.
262 
263     wc_window = wgl_window_priv_create(wc_plat, &self->wcore, 10, 10);
264     if (!wc_window)
265         goto error;
266 
267     self->window = wgl_window(wc_window);
268 
269     // Now let's pray that the root window's hDC is compatible with the
270     // new window hDC.
271     ok = SetPixelFormat(self->window->hDC, self->pixel_format, &self->pfd);
272     if (!ok)
273         goto error;
274 
275     return &self->wcore;
276 
277 error:
278     wgl_config_destroy(&self->wcore);
279     return NULL;
280 }
281