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