VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine_new/wined3d/context.c@ 46966

Last change on this file since 46966 was 46783, checked in by vboxsync, 12 years ago

wddm/crOpenGL: more TexPresent impl

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 101.9 KB
Line 
1/*
2 * Context and render target management in wined3d
3 *
4 * Copyright 2007-2011, 2013 Stefan Dösinger for CodeWeavers
5 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include "config.h"
23#include "wine/port.h"
24
25#include <stdio.h>
26#ifdef HAVE_FLOAT_H
27# include <float.h>
28#endif
29
30#include "wined3d_private.h"
31
32WINE_DEFAULT_DEBUG_CHANNEL(d3d);
33WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
34WINE_DECLARE_DEBUG_CHANNEL(d3d_synchronous);
35
36static DWORD wined3d_context_tls_idx;
37
38#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
39# define vboxGetCurrentContext() VBoxTlsRefGetCurrent(struct wined3d_context, wined3d_context_tls_idx)
40# define vboxSetCurrentContext(_ctx) VBoxTlsRefSetCurrent(struct wined3d_context, wined3d_context_tls_idx, (_ctx))
41#endif
42
43/* FBO helper functions */
44
45/* Context activation is done by the caller. */
46static void context_bind_fbo(struct wined3d_context *context, GLenum target, GLuint fbo)
47{
48 const struct wined3d_gl_info *gl_info = context->gl_info;
49
50 switch (target)
51 {
52 case GL_READ_FRAMEBUFFER:
53 if (context->fbo_read_binding == fbo) return;
54 context->fbo_read_binding = fbo;
55 break;
56
57 case GL_DRAW_FRAMEBUFFER:
58 if (context->fbo_draw_binding == fbo) return;
59 context->fbo_draw_binding = fbo;
60 break;
61
62 case GL_FRAMEBUFFER:
63 if (context->fbo_read_binding == fbo
64 && context->fbo_draw_binding == fbo) return;
65 context->fbo_read_binding = fbo;
66 context->fbo_draw_binding = fbo;
67 break;
68
69 default:
70 FIXME("Unhandled target %#x.\n", target);
71 break;
72 }
73
74 gl_info->fbo_ops.glBindFramebuffer(target, fbo);
75 checkGLcall("glBindFramebuffer()");
76}
77
78/* Context activation is done by the caller. */
79static void context_clean_fbo_attachments(const struct wined3d_gl_info *gl_info, GLenum target)
80{
81 unsigned int i;
82
83 for (i = 0; i < gl_info->limits.buffers; ++i)
84 {
85 gl_info->fbo_ops.glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0);
86 checkGLcall("glFramebufferTexture2D()");
87 }
88 gl_info->fbo_ops.glFramebufferTexture2D(target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
89 checkGLcall("glFramebufferTexture2D()");
90
91 gl_info->fbo_ops.glFramebufferTexture2D(target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
92 checkGLcall("glFramebufferTexture2D()");
93}
94
95/* Context activation is done by the caller. */
96static void context_destroy_fbo(struct wined3d_context *context, GLuint fbo)
97{
98 const struct wined3d_gl_info *gl_info = context->gl_info;
99
100 context_bind_fbo(context, GL_FRAMEBUFFER, fbo);
101 context_clean_fbo_attachments(gl_info, GL_FRAMEBUFFER);
102 context_bind_fbo(context, GL_FRAMEBUFFER, 0);
103
104 gl_info->fbo_ops.glDeleteFramebuffers(1, &fbo);
105 checkGLcall("glDeleteFramebuffers()");
106}
107
108static void context_attach_depth_stencil_rb(const struct wined3d_gl_info *gl_info,
109 GLenum fbo_target, DWORD format_flags, GLuint rb)
110{
111 if (format_flags & WINED3DFMT_FLAG_DEPTH)
112 {
113 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb);
114 checkGLcall("glFramebufferRenderbuffer()");
115 }
116
117 if (format_flags & WINED3DFMT_FLAG_STENCIL)
118 {
119 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb);
120 checkGLcall("glFramebufferRenderbuffer()");
121 }
122}
123
124/* Context activation is done by the caller. */
125static void context_attach_depth_stencil_fbo(struct wined3d_context *context,
126 GLenum fbo_target, struct wined3d_surface *depth_stencil, DWORD location)
127{
128 const struct wined3d_gl_info *gl_info = context->gl_info;
129
130 TRACE("Attach depth stencil %p\n", depth_stencil);
131
132 if (depth_stencil)
133 {
134 DWORD format_flags = depth_stencil->resource.format->flags;
135
136 if (depth_stencil->current_renderbuffer)
137 {
138 context_attach_depth_stencil_rb(gl_info, fbo_target,
139 format_flags, depth_stencil->current_renderbuffer->id);
140 }
141 else
142 {
143 switch (location)
144 {
145 case SFLAG_INTEXTURE:
146 case SFLAG_INSRGBTEX:
147 surface_prepare_texture(depth_stencil, context, FALSE);
148
149 if (format_flags & WINED3DFMT_FLAG_DEPTH)
150 {
151 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT,
152 depth_stencil->texture_target, depth_stencil->texture_name,
153 depth_stencil->texture_level);
154 checkGLcall("glFramebufferTexture2D()");
155 }
156
157 if (format_flags & WINED3DFMT_FLAG_STENCIL)
158 {
159 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT,
160 depth_stencil->texture_target, depth_stencil->texture_name,
161 depth_stencil->texture_level);
162 checkGLcall("glFramebufferTexture2D()");
163 }
164 break;
165
166 case SFLAG_INRB_MULTISAMPLE:
167 surface_prepare_rb(depth_stencil, gl_info, TRUE);
168 context_attach_depth_stencil_rb(gl_info, fbo_target,
169 format_flags, depth_stencil->rb_multisample);
170 break;
171
172 case SFLAG_INRB_RESOLVED:
173 surface_prepare_rb(depth_stencil, gl_info, FALSE);
174 context_attach_depth_stencil_rb(gl_info, fbo_target,
175 format_flags, depth_stencil->rb_resolved);
176 break;
177
178 default:
179 ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
180 break;
181 }
182 }
183
184 if (!(format_flags & WINED3DFMT_FLAG_DEPTH))
185 {
186 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
187 checkGLcall("glFramebufferTexture2D()");
188 }
189
190 if (!(format_flags & WINED3DFMT_FLAG_STENCIL))
191 {
192 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
193 checkGLcall("glFramebufferTexture2D()");
194 }
195 }
196 else
197 {
198 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
199 checkGLcall("glFramebufferTexture2D()");
200
201 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
202 checkGLcall("glFramebufferTexture2D()");
203 }
204}
205
206/* Context activation is done by the caller. */
207static void context_attach_surface_fbo(struct wined3d_context *context,
208 GLenum fbo_target, DWORD idx, struct wined3d_surface *surface, DWORD location)
209{
210 const struct wined3d_gl_info *gl_info = context->gl_info;
211
212 TRACE("Attach surface %p to %u\n", surface, idx);
213
214 if (surface && surface->resource.format->id != WINED3DFMT_NULL)
215 {
216 BOOL srgb;
217
218 switch (location)
219 {
220 case SFLAG_INTEXTURE:
221 case SFLAG_INSRGBTEX:
222 srgb = location == SFLAG_INSRGBTEX;
223 surface_prepare_texture(surface, context, srgb);
224 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
225 surface->texture_target, surface_get_texture_name(surface, gl_info, srgb),
226 surface->texture_level);
227 checkGLcall("glFramebufferTexture2D()");
228 break;
229
230 case SFLAG_INRB_MULTISAMPLE:
231 surface_prepare_rb(surface, gl_info, TRUE);
232 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
233 GL_RENDERBUFFER, surface->rb_multisample);
234 checkGLcall("glFramebufferRenderbuffer()");
235 break;
236
237 case SFLAG_INRB_RESOLVED:
238 surface_prepare_rb(surface, gl_info, FALSE);
239 gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
240 GL_RENDERBUFFER, surface->rb_resolved);
241 checkGLcall("glFramebufferRenderbuffer()");
242 break;
243
244 default:
245 ERR("Unsupported location %s (%#x).\n", debug_surflocation(location), location);
246 break;
247 }
248 }
249 else
250 {
251 gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D, 0, 0);
252 checkGLcall("glFramebufferTexture2D()");
253 }
254}
255
256/* Context activation is done by the caller. */
257void context_check_fbo_status(const struct wined3d_context *context, GLenum target)
258{
259 const struct wined3d_gl_info *gl_info = context->gl_info;
260 GLenum status;
261
262 if (!FIXME_ON(d3d)) return;
263
264 status = gl_info->fbo_ops.glCheckFramebufferStatus(target);
265 if (status == GL_FRAMEBUFFER_COMPLETE)
266 {
267 TRACE("FBO complete\n");
268 }
269 else
270 {
271 const struct wined3d_surface *attachment;
272 unsigned int i;
273
274 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
275
276 if (!context->current_fbo)
277 {
278 ERR("FBO 0 is incomplete, driver bug?\n");
279 return;
280 }
281
282 FIXME("\tLocation %s (%#x).\n", debug_surflocation(context->current_fbo->location),
283 context->current_fbo->location);
284
285 /* Dump the FBO attachments */
286 for (i = 0; i < gl_info->limits.buffers; ++i)
287 {
288 attachment = context->current_fbo->render_targets[i];
289 if (attachment)
290 {
291 FIXME("\tColor attachment %d: (%p) %s %ux%u %u samples.\n",
292 i, attachment, debug_d3dformat(attachment->resource.format->id),
293 attachment->pow2Width, attachment->pow2Height, attachment->resource.multisample_type);
294 }
295 }
296 attachment = context->current_fbo->depth_stencil;
297 if (attachment)
298 {
299 FIXME("\tDepth attachment: (%p) %s %ux%u %u samples.\n",
300 attachment, debug_d3dformat(attachment->resource.format->id),
301 attachment->pow2Width, attachment->pow2Height, attachment->resource.multisample_type);
302 }
303 }
304}
305
306static inline DWORD context_generate_rt_mask(GLenum buffer)
307{
308 /* Should take care of all the GL_FRONT/GL_BACK/GL_AUXi/GL_NONE... cases */
309 return buffer ? (1 << 31) | buffer : 0;
310}
311
312static inline DWORD context_generate_rt_mask_from_surface(const struct wined3d_surface *target)
313{
314 return (1 << 31) | surface_get_gl_buffer(target);
315}
316
317static struct fbo_entry *context_create_fbo_entry(const struct wined3d_context *context,
318 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
319{
320 const struct wined3d_gl_info *gl_info = context->gl_info;
321 struct fbo_entry *entry;
322
323 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
324 entry->render_targets = HeapAlloc(GetProcessHeap(), 0, gl_info->limits.buffers * sizeof(*entry->render_targets));
325 memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
326 entry->depth_stencil = depth_stencil;
327 entry->location = location;
328 entry->rt_mask = context_generate_rt_mask(GL_COLOR_ATTACHMENT0);
329 entry->attached = FALSE;
330 gl_info->fbo_ops.glGenFramebuffers(1, &entry->id);
331 checkGLcall("glGenFramebuffers()");
332 TRACE("Created FBO %u.\n", entry->id);
333
334 return entry;
335}
336
337/* Context activation is done by the caller. */
338static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum target,
339 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil,
340 DWORD location, struct fbo_entry *entry)
341{
342 const struct wined3d_gl_info *gl_info = context->gl_info;
343
344 context_bind_fbo(context, target, entry->id);
345 context_clean_fbo_attachments(gl_info, target);
346
347 memcpy(entry->render_targets, render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets));
348 entry->depth_stencil = depth_stencil;
349 entry->location = location;
350 entry->attached = FALSE;
351}
352
353/* Context activation is done by the caller. */
354static void context_destroy_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
355{
356 if (entry->id)
357 {
358 TRACE("Destroy FBO %u.\n", entry->id);
359 context_destroy_fbo(context, entry->id);
360 }
361 --context->fbo_entry_count;
362 list_remove(&entry->entry);
363 HeapFree(GetProcessHeap(), 0, entry->render_targets);
364 HeapFree(GetProcessHeap(), 0, entry);
365}
366
367
368/* Context activation is done by the caller. */
369static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, GLenum target,
370 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
371{
372 const struct wined3d_gl_info *gl_info = context->gl_info;
373 struct fbo_entry *entry;
374
375 if (depth_stencil && render_targets && render_targets[0])
376 {
377 if (depth_stencil->resource.width < render_targets[0]->resource.width ||
378 depth_stencil->resource.height < render_targets[0]->resource.height)
379 {
380 WARN("Depth stencil is smaller than the primary color buffer, disabling\n");
381 depth_stencil = NULL;
382 }
383 }
384
385 LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
386 {
387 if (!memcmp(entry->render_targets,
388 render_targets, gl_info->limits.buffers * sizeof(*entry->render_targets))
389 && entry->depth_stencil == depth_stencil && entry->location == location)
390 {
391 list_remove(&entry->entry);
392 list_add_head(&context->fbo_list, &entry->entry);
393 return entry;
394 }
395 }
396
397 if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES)
398 {
399 entry = context_create_fbo_entry(context, render_targets, depth_stencil, location);
400 list_add_head(&context->fbo_list, &entry->entry);
401 ++context->fbo_entry_count;
402 }
403 else
404 {
405 entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry);
406 context_reuse_fbo_entry(context, target, render_targets, depth_stencil, location, entry);
407 list_remove(&entry->entry);
408 list_add_head(&context->fbo_list, &entry->entry);
409 }
410
411 return entry;
412}
413
414/* Context activation is done by the caller. */
415static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
416{
417 const struct wined3d_gl_info *gl_info = context->gl_info;
418 unsigned int i;
419 GLuint read_binding, draw_binding;
420
421 if (entry->attached)
422 {
423 context_bind_fbo(context, target, entry->id);
424 return;
425 }
426
427 read_binding = context->fbo_read_binding;
428 draw_binding = context->fbo_draw_binding;
429 context_bind_fbo(context, GL_FRAMEBUFFER, entry->id);
430
431 /* Apply render targets */
432 for (i = 0; i < gl_info->limits.buffers; ++i)
433 {
434 context_attach_surface_fbo(context, target, i, entry->render_targets[i], entry->location);
435 }
436
437 /* Apply depth targets */
438 if (entry->depth_stencil)
439 surface_set_compatible_renderbuffer(entry->depth_stencil, entry->render_targets[0]);
440 context_attach_depth_stencil_fbo(context, target, entry->depth_stencil, entry->location);
441
442 /* Set valid read and draw buffer bindings to satisfy pedantic pre-ES2_compatibility
443 * GL contexts requirements. */
444 glReadBuffer(GL_NONE);
445 context_set_draw_buffer(context, GL_NONE);
446 if (target != GL_FRAMEBUFFER)
447 {
448 if (target == GL_READ_FRAMEBUFFER)
449 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, draw_binding);
450 else
451 context_bind_fbo(context, GL_READ_FRAMEBUFFER, read_binding);
452 }
453
454 entry->attached = TRUE;
455}
456
457/* Context activation is done by the caller. */
458static void context_apply_fbo_state(struct wined3d_context *context, GLenum target,
459 struct wined3d_surface **render_targets, struct wined3d_surface *depth_stencil, DWORD location)
460{
461 struct fbo_entry *entry, *entry2;
462
463 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
464 {
465 context_destroy_fbo_entry(context, entry);
466 }
467
468 if (context->rebind_fbo)
469 {
470 context_bind_fbo(context, GL_FRAMEBUFFER, 0);
471 context->rebind_fbo = FALSE;
472 }
473
474 if (location == SFLAG_INDRAWABLE)
475 {
476 context->current_fbo = NULL;
477 context_bind_fbo(context, target, 0);
478 }
479 else
480 {
481 context->current_fbo = context_find_fbo_entry(context, target, render_targets, depth_stencil, location);
482 context_apply_fbo_entry(context, target, context->current_fbo);
483 }
484}
485
486/* Context activation is done by the caller. */
487void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target,
488 struct wined3d_surface *render_target, struct wined3d_surface *depth_stencil, DWORD location)
489{
490 UINT clear_size = (context->gl_info->limits.buffers - 1) * sizeof(*context->blit_targets);
491
492 context->blit_targets[0] = render_target;
493 if (clear_size)
494 memset(&context->blit_targets[1], 0, clear_size);
495 context_apply_fbo_state(context, target, context->blit_targets, depth_stencil, location);
496}
497
498/* Context activation is done by the caller. */
499void context_alloc_occlusion_query(struct wined3d_context *context, struct wined3d_occlusion_query *query)
500{
501 const struct wined3d_gl_info *gl_info = context->gl_info;
502
503 if (context->free_occlusion_query_count)
504 {
505 query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
506 }
507 else
508 {
509 if (gl_info->supported[ARB_OCCLUSION_QUERY])
510 {
511 GL_EXTCALL(glGenQueriesARB(1, &query->id));
512 checkGLcall("glGenQueriesARB");
513
514 TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
515 }
516 else
517 {
518 WARN("Occlusion queries not supported, not allocating query id.\n");
519 query->id = 0;
520 }
521 }
522
523 query->context = context;
524 list_add_head(&context->occlusion_queries, &query->entry);
525}
526
527void context_free_occlusion_query(struct wined3d_occlusion_query *query)
528{
529 struct wined3d_context *context = query->context;
530
531 list_remove(&query->entry);
532 query->context = NULL;
533
534 if (context->free_occlusion_query_count >= context->free_occlusion_query_size - 1)
535 {
536 UINT new_size = context->free_occlusion_query_size << 1;
537 GLuint *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_occlusion_queries,
538 new_size * sizeof(*context->free_occlusion_queries));
539
540 if (!new_data)
541 {
542 ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
543 return;
544 }
545
546 context->free_occlusion_query_size = new_size;
547 context->free_occlusion_queries = new_data;
548 }
549
550 context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
551}
552
553/* Context activation is done by the caller. */
554void context_alloc_event_query(struct wined3d_context *context, struct wined3d_event_query *query)
555{
556 const struct wined3d_gl_info *gl_info = context->gl_info;
557
558 if (context->free_event_query_count)
559 {
560 query->object = context->free_event_queries[--context->free_event_query_count];
561 }
562 else
563 {
564 if (gl_info->supported[ARB_SYNC])
565 {
566 /* Using ARB_sync, not much to do here. */
567 query->object.sync = NULL;
568 TRACE("Allocated event query %p in context %p.\n", query->object.sync, context);
569 }
570 else if (gl_info->supported[APPLE_FENCE])
571 {
572 GL_EXTCALL(glGenFencesAPPLE(1, &query->object.id));
573 checkGLcall("glGenFencesAPPLE");
574
575 TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
576 }
577 else if(gl_info->supported[NV_FENCE])
578 {
579 GL_EXTCALL(glGenFencesNV(1, &query->object.id));
580 checkGLcall("glGenFencesNV");
581
582 TRACE("Allocated event query %u in context %p.\n", query->object.id, context);
583 }
584 else
585 {
586 WARN("Event queries not supported, not allocating query id.\n");
587 query->object.id = 0;
588 }
589 }
590
591 query->context = context;
592 list_add_head(&context->event_queries, &query->entry);
593}
594
595void context_free_event_query(struct wined3d_event_query *query)
596{
597 struct wined3d_context *context = query->context;
598
599 list_remove(&query->entry);
600 query->context = NULL;
601
602 if (context->free_event_query_count >= context->free_event_query_size - 1)
603 {
604 UINT new_size = context->free_event_query_size << 1;
605 union wined3d_gl_query_object *new_data = HeapReAlloc(GetProcessHeap(), 0, context->free_event_queries,
606 new_size * sizeof(*context->free_event_queries));
607
608 if (!new_data)
609 {
610 ERR("Failed to grow free list, leaking query %u in context %p.\n", query->object.id, context);
611 return;
612 }
613
614 context->free_event_query_size = new_size;
615 context->free_event_queries = new_data;
616 }
617
618 context->free_event_queries[context->free_event_query_count++] = query->object;
619}
620
621typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
622
623static void context_enum_surface_fbo_entries(const struct wined3d_device *device,
624 const struct wined3d_surface *surface, context_fbo_entry_func_t *callback)
625{
626 UINT i;
627
628 for (i = 0; i < device->context_count; ++i)
629 {
630 struct wined3d_context *context = device->contexts[i];
631 const struct wined3d_gl_info *gl_info = context->gl_info;
632 struct fbo_entry *entry, *entry2;
633
634 if (context->current_rt == surface) context->current_rt = NULL;
635
636 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
637 {
638 UINT j;
639
640 if (entry->depth_stencil == surface)
641 {
642 callback(context, entry);
643 continue;
644 }
645
646 for (j = 0; j < gl_info->limits.buffers; ++j)
647 {
648 if (entry->render_targets[j] == surface)
649 {
650 callback(context, entry);
651 break;
652 }
653 }
654 }
655 }
656}
657
658static void context_queue_fbo_entry_destruction(struct wined3d_context *context, struct fbo_entry *entry)
659{
660 list_remove(&entry->entry);
661 list_add_head(&context->fbo_destroy_list, &entry->entry);
662}
663
664void context_resource_released(const struct wined3d_device *device,
665 struct wined3d_resource *resource, enum wined3d_resource_type type)
666{
667 if (!device->d3d_initialized) return;
668
669 switch (type)
670 {
671 case WINED3D_RTYPE_SURFACE:
672 context_enum_surface_fbo_entries(device, surface_from_resource(resource),
673 context_queue_fbo_entry_destruction);
674 break;
675
676 default:
677 break;
678 }
679}
680
681static void context_detach_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
682{
683 entry->attached = FALSE;
684}
685
686void context_resource_unloaded(const struct wined3d_device *device,
687 struct wined3d_resource *resource, enum wined3d_resource_type type)
688{
689 switch (type)
690 {
691 case WINED3D_RTYPE_SURFACE:
692 context_enum_surface_fbo_entries(device, surface_from_resource(resource),
693 context_detach_fbo_entry);
694 break;
695
696 default:
697 break;
698 }
699}
700
701void context_surface_update(struct wined3d_context *context, const struct wined3d_surface *surface)
702{
703 const struct wined3d_gl_info *gl_info = context->gl_info;
704 struct fbo_entry *entry = context->current_fbo;
705 unsigned int i;
706
707 if (!entry || context->rebind_fbo) return;
708
709 for (i = 0; i < gl_info->limits.buffers; ++i)
710 {
711 if (surface == entry->render_targets[i])
712 {
713 TRACE("Updated surface %p is bound as color attachment %u to the current FBO.\n", surface, i);
714 context->rebind_fbo = TRUE;
715 return;
716 }
717 }
718
719 if (surface == entry->depth_stencil)
720 {
721 TRACE("Updated surface %p is bound as depth attachment to the current FBO.\n", surface);
722 context->rebind_fbo = TRUE;
723 }
724}
725
726#ifndef VBOX
727static BOOL context_set_pixel_format(const struct wined3d_gl_info *gl_info, HDC dc, int format)
728{
729 int current = GetPixelFormat(dc);
730
731 if (current == format) return TRUE;
732
733 if (!current)
734 {
735 if (!SetPixelFormat(dc, format, NULL))
736 {
737 /* This may also happen if the dc belongs to a destroyed window. */
738 WARN("Failed to set pixel format %d on device context %p, last error %#x.\n",
739 format, dc, GetLastError());
740 return FALSE;
741 }
742 return TRUE;
743 }
744
745 /* By default WGL doesn't allow pixel format adjustments but we need it
746 * here. For this reason there's a Wine specific wglSetPixelFormat()
747 * which allows us to set the pixel format multiple times. Only use it
748 * when really needed. */
749 if (gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
750 {
751 if (!GL_EXTCALL(wglSetPixelFormatWINE(dc, format)))
752 {
753 ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
754 format, dc);
755 return FALSE;
756 }
757 return TRUE;
758 }
759
760 /* OpenGL doesn't allow pixel format adjustments. Print an error and
761 * continue using the old format. There's a big chance that the old
762 * format works although with a performance hit and perhaps rendering
763 * errors. */
764 ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
765 format, dc, current);
766 return TRUE;
767}
768#endif
769
770static BOOL context_set_gl_context(struct wined3d_context *ctx)
771{
772 struct wined3d_swapchain *swapchain = ctx->swapchain;
773#ifndef VBOX
774 BOOL backup = FALSE;
775
776 if (!context_set_pixel_format(ctx->gl_info, ctx->hdc, ctx->pixel_format))
777 {
778 WARN("Failed to set pixel format %d on device context %p.\n",
779 ctx->pixel_format, ctx->hdc);
780 backup = TRUE;
781 }
782
783 if (backup || !wglMakeCurrent(ctx->hdc, ctx->glCtx))
784#else
785 if (!wglMakeCurrent(ctx->swapchain->hDC, ctx->glCtx))
786#endif
787 {
788#ifndef VBOX_WITH_WDDM
789 HDC dc;
790#endif
791
792#ifndef VBOX
793 WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
794 ctx->glCtx, ctx->hdc, GetLastError());
795#else
796 WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
797 ctx->glCtx, ctx->swapchain->hDC, GetLastError());
798#endif
799 ctx->valid = 0;
800 WARN("Trying fallback to the backup window.\n");
801#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
802 /* FIXME: If the context is destroyed it's no longer associated with
803 * a swapchain, so we can't use the swapchain to get a backup dc. To
804 * make this work windowless contexts would need to be handled by the
805 * device. */
806 if (ctx->destroyed)
807 {
808 FIXME("Unable to get backup dc for destroyed context %p.\n", ctx);
809 context_set_current(NULL);
810 return FALSE;
811 }
812#endif
813#ifndef VBOX_WITH_WDDM
814 if (!(dc = swapchain_get_backup_dc(swapchain)))
815 {
816 context_set_current(NULL);
817 return FALSE;
818 }
819#ifndef VBOX
820 if (!context_set_pixel_format(ctx->gl_info, dc, ctx->pixel_format))
821 {
822 ERR("Failed to set pixel format %d on device context %p.\n",
823 ctx->pixel_format, dc);
824 context_set_current(NULL);
825 return FALSE;
826 }
827#endif
828 if (!wglMakeCurrent(dc, ctx->glCtx))
829 {
830 ERR("Fallback to backup window (dc %p) failed too, last error %#x.\n",
831 dc, GetLastError());
832 context_set_current(NULL);
833 return FALSE;
834 }
835#else
836 return FALSE;
837#endif
838 }
839 return TRUE;
840}
841
842static void context_restore_gl_context(const struct wined3d_gl_info *gl_info, HDC dc, HGLRC gl_ctx, int pf)
843{
844#ifndef VBOX
845 if (!context_set_pixel_format(gl_info, dc, pf))
846 {
847 ERR("Failed to restore pixel format %d on device context %p.\n", pf, dc);
848 context_set_current(NULL);
849 return;
850 }
851#endif
852 if (!wglMakeCurrent(dc, gl_ctx))
853 {
854 ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
855 gl_ctx, dc, GetLastError());
856 context_set_current(NULL);
857 }
858#ifdef VBOX
859 else
860 {
861 /* success branch */
862 /* sync back our tls with gl settings */
863 const struct wined3d_context *current_context = context_get_current();
864 if (current_context && current_context->glCtx != gl_ctx)
865 {
866 UINT i = 0;
867 struct wined3d_device *device = current_context->swapchain->device;
868 for (; i < device->context_count; ++i)
869 {
870 struct wined3d_context *ctx = device->contexts[i];
871 if (ctx->glCtx == gl_ctx)
872 {
873 context_set_current(ctx);
874 break;
875 }
876 }
877
878 if (i == device->context_count)
879 {
880 context_set_current(NULL);
881 }
882 }
883 }
884#endif
885}
886
887#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
888static BOOL swapchain_validate(const struct wined3d_swapchain *swapchain)
889{
890 if (!swapchain->hDC)
891 {
892 ERR("NULL hDC");
893 return FALSE;
894 }
895
896#if defined(DEBUG) || !defined(VBOX_WITH_WDDM)
897 {
898 HWND hWnd = WindowFromDC(swapchain->hDC);
899 if (hWnd != swapchain->win_handle)
900 {
901# if defined(VBOX_WITH_WDDM)
902 ERR("Unexpected swapchain for dc %p window expected %p, but was %p.\n", swapchain->hDC, swapchain->win_handle, hWnd);
903# else
904 ERR("Swapchain for dc %p window expected %p, but was %p.\n", swapchain->hDC, swapchain->win_handle, hWnd);
905 return FALSE;
906# endif
907 }
908 }
909#endif
910 return TRUE;
911}
912
913static struct wined3d_swapchain* swapchain_find_valid(const struct wined3d_device *device)
914{
915 int i;
916 struct wined3d_context * context = device->contexts[0];
917 struct wined3d_swapchain* swapchain = NULL;
918 if (context)
919 {
920 swapchain = context->swapchain;
921 if (swapchain && swapchain_validate(swapchain))
922 {
923 return swapchain;
924 }
925 }
926 for (i = device->swapchain_count - 1; i >= 0 ; --i)
927 {
928 Assert(device->swapchains[i]);
929 if (swapchain != device->swapchains[i] /* the current context swapchain is known to be invalid */
930 && swapchain_validate(device->swapchains[i]))
931 {
932 return device->swapchains[i];
933 }
934 }
935
936 return NULL;
937}
938
939static struct wined3d_swapchain* swapchain_find_valid_or_any(const struct wined3d_device *device)
940{
941 struct wined3d_swapchain* swapchain = swapchain_find_valid(device);
942 if (swapchain)
943 return swapchain;
944
945 ERR("no valid swapchain found!");
946 swapchain = device->swapchains[0];
947 Assert(swapchain);
948 return swapchain;
949}
950
951struct wined3d_context *context_find_create(struct wined3d_device *device,
952 struct wined3d_swapchain *swapchain,
953 const struct wined3d_format *ds_format)
954{
955 struct wined3d_context *context;
956 struct wined3d_surface *target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
957 if (!device->context_count)
958 {
959 Assert(!device->swapchain_count);
960 context = context_create(swapchain, target, ds_format
961#ifdef VBOX_WITH_WDDM
962 , device->pHgsmi
963#endif
964 );
965 if(!context)
966 {
967 ERR("Failed to create the context.\n");
968 }
969 else
970 {
971 Assert(context->valid);
972 }
973 }
974 else
975 {
976 context = context_acquire(device, target);
977 if(!context)
978 {
979 ERR("Failed to acquire the context.\n");
980 }
981 else
982 {
983 Assert(context->valid);
984 }
985 }
986
987 return context;
988}
989
990#endif
991
992static void context_update_window(struct wined3d_context *context
993#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
994 , struct wined3d_swapchain *swapchain
995#endif
996 )
997{
998#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
999 TRACE("Updating context %p swapchain from %p to %p.\n",
1000 context, context->swapchain, swapchain);
1001
1002 if (context->swapchain == swapchain)
1003 return;
1004
1005 if (!swapchain_validate(swapchain))
1006 {
1007 ERR("invalid swapchain %p\n", swapchain);
1008 goto err;
1009 }
1010 context->swapchain = swapchain;
1011
1012 context->valid = 1;
1013
1014 context_set_gl_context(context);
1015#else
1016 if (context->win_handle == context->swapchain->win_handle)
1017 return;
1018
1019 TRACE("Updating context %p window from %p to %p.\n",
1020 context, context->win_handle, context->swapchain->win_handle);
1021
1022 if (context->valid)
1023 {
1024 /* You'd figure ReleaseDC() would fail if the DC doesn't match the
1025 * window. However, that's not what actually happens, and there are
1026 * user32 tests that confirm ReleaseDC() with the wrong window is
1027 * supposed to succeed. So explicitly check that the DC belongs to
1028 * the window, since we want to avoid releasing a DC that belongs to
1029 * some other window if the original window was already destroyed. */
1030 if (WindowFromDC(context->hdc) != context->win_handle)
1031 {
1032 WARN("DC %p does not belong to window %p.\n",
1033 context->hdc, context->win_handle);
1034 }
1035#ifndef VBOX
1036 else if (!ReleaseDC(context->win_handle, context->hdc))
1037#else
1038 else if (!VBoxExtReleaseDC(context->win_handle, context->hdc))
1039#endif
1040 {
1041 ERR("Failed to release device context %p, last error %#x.\n",
1042 context->hdc, GetLastError());
1043 }
1044 }
1045 else context->valid = 1;
1046
1047 context->win_handle = context->swapchain->win_handle;
1048
1049#ifndef VBOX
1050 if (!(context->hdc = GetDC(context->win_handle)))
1051#else
1052 if (!(context->hdc = VBoxExtGetDC(context->win_handle)))
1053#endif
1054 {
1055 ERR("Failed to get a device context for window %p.\n", context->win_handle);
1056 goto err;
1057 }
1058#ifndef VBOX
1059 if (!context_set_pixel_format(context->gl_info, context->hdc, context->pixel_format))
1060 {
1061 ERR("Failed to set pixel format %d on device context %p.\n",
1062 context->pixel_format, context->hdc);
1063 goto err;
1064 }
1065#endif
1066 context_set_gl_context(context);
1067#endif
1068 return;
1069
1070err:
1071 context->valid = 0;
1072}
1073
1074#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
1075static void context_adjust_any_valid(struct wined3d_context *context)
1076{
1077 struct wined3d_swapchain* swapchain = context->swapchain;
1078
1079 if (context->valid && swapchain && swapchain_validate(swapchain))
1080 return;
1081
1082 swapchain = swapchain_find_valid(context->device);
1083 if (!swapchain)
1084 {
1085 ERR("no valid swapchain found");
1086 Assert(!context->valid);
1087 return;
1088 }
1089
1090 context_update_window(context, swapchain);
1091}
1092#endif
1093
1094/* Do not call while under the GL lock. */
1095static void context_destroy_gl_resources(struct wined3d_context *context)
1096{
1097 const struct wined3d_gl_info *gl_info = context->gl_info;
1098 struct wined3d_occlusion_query *occlusion_query;
1099 struct wined3d_event_query *event_query;
1100 struct fbo_entry *entry, *entry2;
1101 HGLRC restore_ctx;
1102 HDC restore_dc;
1103 unsigned int i;
1104 int restore_pf;
1105
1106 restore_ctx = wglGetCurrentContext();
1107 restore_dc = wglGetCurrentDC();
1108 restore_pf = GetPixelFormat(restore_dc);
1109
1110#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
1111 if (context->valid && restore_ctx != context->glCtx)
1112 context_set_gl_context(context);
1113#else
1114 if (restore_ctx != context->glCtx)
1115 context_adjust_any_valid(context);
1116#endif
1117 else
1118 restore_ctx = NULL;
1119
1120
1121 LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
1122 {
1123 if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY])
1124 GL_EXTCALL(glDeleteQueriesARB(1, &occlusion_query->id));
1125 occlusion_query->context = NULL;
1126 }
1127
1128 LIST_FOR_EACH_ENTRY(event_query, &context->event_queries, struct wined3d_event_query, entry)
1129 {
1130 if (context->valid)
1131 {
1132 if (gl_info->supported[ARB_SYNC])
1133 {
1134 if (event_query->object.sync) GL_EXTCALL(glDeleteSync(event_query->object.sync));
1135 }
1136 else if (gl_info->supported[APPLE_FENCE]) GL_EXTCALL(glDeleteFencesAPPLE(1, &event_query->object.id));
1137 else if (gl_info->supported[NV_FENCE]) GL_EXTCALL(glDeleteFencesNV(1, &event_query->object.id));
1138 }
1139 event_query->context = NULL;
1140 }
1141
1142 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
1143 {
1144 if (!context->valid) entry->id = 0;
1145 context_destroy_fbo_entry(context, entry);
1146 }
1147
1148 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
1149 {
1150 if (!context->valid) entry->id = 0;
1151 context_destroy_fbo_entry(context, entry);
1152 }
1153
1154 if (context->valid)
1155 {
1156 if (context->dummy_arbfp_prog)
1157 {
1158 GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
1159 }
1160
1161 if (gl_info->supported[ARB_OCCLUSION_QUERY])
1162 GL_EXTCALL(glDeleteQueriesARB(context->free_occlusion_query_count, context->free_occlusion_queries));
1163
1164 if (gl_info->supported[ARB_SYNC])
1165 {
1166 for (i = 0; i < context->free_event_query_count; ++i)
1167 {
1168 GL_EXTCALL(glDeleteSync(context->free_event_queries[i].sync));
1169 }
1170 }
1171 else if (gl_info->supported[APPLE_FENCE])
1172 {
1173 for (i = 0; i < context->free_event_query_count; ++i)
1174 {
1175 GL_EXTCALL(glDeleteFencesAPPLE(1, &context->free_event_queries[i].id));
1176 }
1177 }
1178 else if (gl_info->supported[NV_FENCE])
1179 {
1180 for (i = 0; i < context->free_event_query_count; ++i)
1181 {
1182 GL_EXTCALL(glDeleteFencesNV(1, &context->free_event_queries[i].id));
1183 }
1184 }
1185
1186 checkGLcall("context cleanup");
1187 }
1188
1189 HeapFree(GetProcessHeap(), 0, context->free_occlusion_queries);
1190 HeapFree(GetProcessHeap(), 0, context->free_event_queries);
1191
1192 if (restore_ctx)
1193 {
1194 context_restore_gl_context(gl_info, restore_dc, restore_ctx, restore_pf);
1195 }
1196 else if (wglGetCurrentContext() && !wglMakeCurrent(NULL, NULL))
1197 {
1198 ERR("Failed to disable GL context.\n");
1199 }
1200
1201#ifndef VBOX_WITH_WDDM
1202# ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
1203# ifndef VBOX
1204 ReleaseDC(context->win_handle, context->hdc);
1205# else
1206 VBoxExtReleaseDC(context->win_handle, context->hdc);
1207# endif
1208# endif
1209#endif
1210
1211 if (!wglDeleteContext(context->glCtx))
1212 {
1213 DWORD err = GetLastError();
1214 ERR("wglDeleteContext(%p) failed, last error %#x.\n", context->glCtx, err);
1215 }
1216}
1217
1218DWORD context_get_tls_idx(void)
1219{
1220 return wined3d_context_tls_idx;
1221}
1222
1223void context_set_tls_idx(DWORD idx)
1224{
1225 wined3d_context_tls_idx = idx;
1226}
1227
1228#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1229static struct wined3d_context *context_get_current_ex(DWORD adjustTid)
1230{
1231 struct wined3d_context *ctx = vboxGetCurrentContext();
1232 if (ctx && !VBoxTlsRefIsFunctional(ctx))
1233 {
1234 /* this is a destroyed context left in the tls of the current thread */
1235 /* 1. this releases the context and clears the tls */
1236 vboxSetCurrentContext(NULL);
1237 /* return there is no context current */
1238 return NULL;
1239 }
1240 if (!adjustTid)
1241 return ctx;
1242 if (!ctx || ctx->tid == adjustTid)
1243 return ctx;
1244 /* the context may have cleared swapchain (if swapchain was destroyed), ensure it has some valid swapchain set */
1245 if (context_set_current(ctx))
1246 {
1247 Assert(ctx->tid == adjustTid);
1248 return ctx;
1249 }
1250 ERR("context_set_current failed\n");
1251 return NULL;
1252}
1253#endif
1254
1255struct wined3d_context *context_get_current(void)
1256{
1257#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1258 return TlsGetValue(wined3d_context_tls_idx);
1259#else
1260 DWORD tid = GetCurrentThreadId();
1261 return context_get_current_ex(tid);
1262#endif
1263}
1264
1265/* Do not call while under the GL lock. */
1266BOOL context_set_current(struct wined3d_context *ctx)
1267{
1268#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1269 struct wined3d_context *old = context_get_current_ex(0);
1270 DWORD tid = GetCurrentThreadId();
1271#else
1272 struct wined3d_context *old = context_get_current();
1273#endif
1274
1275 if (old == ctx)
1276 {
1277#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1278 if (ctx && ctx->tid != tid)
1279 {
1280 old = NULL;
1281 }
1282 else
1283#endif
1284 {
1285 TRACE("Already using D3D context %p.\n", ctx);
1286 return TRUE;
1287 }
1288 }
1289
1290 if (old)
1291 {
1292#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1293 old->tid = 0;
1294 old->current = 0;
1295#else
1296 if (old->destroyed)
1297 {
1298 TRACE("Switching away from destroyed context %p.\n", old);
1299 context_destroy_gl_resources(old);
1300 HeapFree(GetProcessHeap(), 0, (void *)old->gl_info);
1301 HeapFree(GetProcessHeap(), 0, old);
1302 }
1303 else
1304 {
1305 old->current = 0;
1306 }
1307#endif
1308 }
1309
1310 if (ctx)
1311 {
1312 if (!ctx->valid)
1313 {
1314 ERR("Trying to make invalid context %p current\n", ctx);
1315 return FALSE;
1316 }
1317
1318#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
1319 TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
1320#else
1321 TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->swapchain->hDC);
1322#endif
1323 if (!context_set_gl_context(ctx))
1324 return FALSE;
1325 ctx->current = 1;
1326 }
1327 else if(wglGetCurrentContext())
1328 {
1329 TRACE("Clearing current D3D context.\n");
1330 if (!wglMakeCurrent(NULL, NULL))
1331 {
1332 DWORD err = GetLastError();
1333 ERR("Failed to clear current GL context, last error %#x.\n", err);
1334#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1335 vboxSetCurrentContext(NULL);
1336#else
1337 TlsSetValue(wined3d_context_tls_idx, NULL);
1338#endif
1339 return FALSE;
1340 }
1341 }
1342#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1343 vboxSetCurrentContext(ctx);
1344 if (ctx)
1345 ctx->tid = tid;
1346 return TRUE;
1347#else
1348 return TlsSetValue(wined3d_context_tls_idx, ctx);
1349#endif
1350}
1351
1352#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1353void context_clear_on_thread_detach()
1354{
1355 /* In theory, we should do context_set_current(NULL) here,
1356 * but since it may result in calling a context dtor, it should be done under wined3d lock.
1357 * We can not acquire a wined3d lock here since this routine is called in a DllMain context
1358 * and this would result in a lock order violation, which may result in a deadlock.
1359 * In other words, wined3d may internally call Win32 API functions which result in
1360 * a DLL lock acquisition while holding wined3d lock.
1361 * So lock order should always be "wined3d lock" -> "dll lock".
1362 *
1363 * This is why we do the following:
1364 * */
1365
1366 /* 1. get the current context w/o adjusting its thread id, etc. */
1367 struct wined3d_context *old = context_get_current_ex(0);
1368 if (!old)
1369 return;
1370
1371// /* there is a currently assigned context,
1372// * 2. now increase its ref count to ensure its dtor routine is not called while making set_current(NULL).
1373// * This is needed since dtor can only be run with a wined3d lock held */
1374// VBoxTlsRefAddRef(old);
1375
1376 /* context_tls_dtor now does only memfree, so just call it right away */
1377
1378 /* 3. now we can call context_set_current(NULL) */
1379 context_set_current(NULL);
1380
1381// /* 4. to avoid possible deadlocks we make an asynchronous call to a worker thread to make
1382// * wined3d lock - context release - wined3d unlock from there. */
1383// VBoxExtReleaseContextAsync(old);
1384}
1385#endif
1386
1387void context_release(struct wined3d_context *context)
1388{
1389 TRACE("Releasing context %p, level %u.\n", context, context->level);
1390
1391 if (WARN_ON(d3d))
1392 {
1393 if (!context->level)
1394 WARN("Context %p is not active.\n", context);
1395 else if (context != context_get_current())
1396 WARN("Context %p is not the current context.\n", context);
1397 }
1398
1399 if (!--context->level && context->restore_ctx)
1400 {
1401 TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
1402 context_restore_gl_context(context->gl_info, context->restore_dc, context->restore_ctx, context->restore_pf);
1403 context->restore_ctx = NULL;
1404 context->restore_dc = NULL;
1405 }
1406}
1407
1408static void context_enter(struct wined3d_context *context)
1409{
1410 TRACE("Entering context %p, level %u.\n", context, context->level + 1);
1411
1412 if (!context->level++)
1413 {
1414 const struct wined3d_context *current_context = context_get_current();
1415 HGLRC current_gl = wglGetCurrentContext();
1416
1417 if (current_gl && (!current_context || current_context->glCtx != current_gl))
1418 {
1419 TRACE("Another GL context (%p on device context %p) is already current.\n",
1420 current_gl, wglGetCurrentDC());
1421 context->restore_ctx = current_gl;
1422 context->restore_dc = wglGetCurrentDC();
1423 context->restore_pf = GetPixelFormat(context->restore_dc);
1424 }
1425 }
1426}
1427
1428void context_invalidate_state(struct wined3d_context *context, DWORD state)
1429{
1430 DWORD rep = context->state_table[state].representative;
1431 DWORD idx;
1432 BYTE shift;
1433
1434 if (isStateDirty(context, rep)) return;
1435
1436 context->dirtyArray[context->numDirtyEntries++] = rep;
1437 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
1438 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
1439 context->isStateDirty[idx] |= (1 << shift);
1440}
1441
1442/* This function takes care of wined3d pixel format selection. */
1443static int context_choose_pixel_format(const struct wined3d_device *device, HDC hdc,
1444 const struct wined3d_format *color_format, const struct wined3d_format *ds_format,
1445 BOOL auxBuffers, BOOL findCompatible)
1446{
1447 int iPixelFormat=0;
1448 BYTE redBits, greenBits, blueBits, alphaBits, colorBits;
1449 BYTE depthBits=0, stencilBits=0;
1450 unsigned int current_value;
1451 unsigned int cfg_count = device->adapter->cfg_count;
1452 unsigned int i;
1453
1454 TRACE("device %p, dc %p, color_format %s, ds_format %s, aux_buffers %#x, find_compatible %#x.\n",
1455 device, hdc, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id),
1456 auxBuffers, findCompatible);
1457
1458 if (!getColorBits(color_format, &redBits, &greenBits, &blueBits, &alphaBits, &colorBits))
1459 {
1460 ERR("Unable to get color bits for format %s (%#x)!\n",
1461 debug_d3dformat(color_format->id), color_format->id);
1462 return 0;
1463 }
1464
1465 getDepthStencilBits(ds_format, &depthBits, &stencilBits);
1466
1467 current_value = 0;
1468 for (i = 0; i < cfg_count; ++i)
1469 {
1470 const struct wined3d_pixel_format *cfg = &device->adapter->cfgs[i];
1471 unsigned int value;
1472
1473 /* For now only accept RGBA formats. Perhaps some day we will
1474 * allow floating point formats for pbuffers. */
1475 if (cfg->iPixelType != WGL_TYPE_RGBA_ARB)
1476 continue;
1477 /* In window mode we need a window drawable format and double buffering. */
1478 if (!(cfg->windowDrawable && cfg->doubleBuffer))
1479 continue;
1480 if (cfg->redSize < redBits)
1481 continue;
1482 if (cfg->greenSize < greenBits)
1483 continue;
1484 if (cfg->blueSize < blueBits)
1485 continue;
1486 if (cfg->alphaSize < alphaBits)
1487 continue;
1488 if (cfg->depthSize < depthBits)
1489 continue;
1490 if (stencilBits && cfg->stencilSize != stencilBits)
1491 continue;
1492 /* Check multisampling support. */
1493 if (cfg->numSamples)
1494 continue;
1495
1496 value = 1;
1497 /* We try to locate a format which matches our requirements exactly. In case of
1498 * depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
1499 if (cfg->depthSize == depthBits)
1500 value += 1;
1501 if (cfg->stencilSize == stencilBits)
1502 value += 2;
1503 if (cfg->alphaSize == alphaBits)
1504 value += 4;
1505 /* We like to have aux buffers in backbuffer mode */
1506 if (auxBuffers && cfg->auxBuffers)
1507 value += 8;
1508 if (cfg->redSize == redBits
1509 && cfg->greenSize == greenBits
1510 && cfg->blueSize == blueBits)
1511 value += 16;
1512
1513 if (value > current_value)
1514 {
1515 iPixelFormat = cfg->iPixelFormat;
1516 current_value = value;
1517 }
1518 }
1519
1520 /* When findCompatible is set and no suitable format was found, let ChoosePixelFormat choose a pixel format in order not to crash. */
1521 if(!iPixelFormat && !findCompatible) {
1522 ERR("Can't find a suitable iPixelFormat\n");
1523 return FALSE;
1524 } else if(!iPixelFormat) {
1525 PIXELFORMATDESCRIPTOR pfd;
1526
1527 TRACE("Falling back to ChoosePixelFormat as we weren't able to find an exactly matching pixel format\n");
1528 /* PixelFormat selection */
1529 ZeroMemory(&pfd, sizeof(pfd));
1530 pfd.nSize = sizeof(pfd);
1531 pfd.nVersion = 1;
1532 pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
1533 pfd.iPixelType = PFD_TYPE_RGBA;
1534 pfd.cAlphaBits = alphaBits;
1535 pfd.cColorBits = colorBits;
1536 pfd.cDepthBits = depthBits;
1537 pfd.cStencilBits = stencilBits;
1538 pfd.iLayerType = PFD_MAIN_PLANE;
1539
1540 iPixelFormat = ChoosePixelFormat(hdc, &pfd);
1541 if(!iPixelFormat) {
1542 /* If this happens something is very wrong as ChoosePixelFormat barely fails */
1543 ERR("Can't find a suitable iPixelFormat\n");
1544 return FALSE;
1545 }
1546 }
1547
1548 TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s\n",
1549 iPixelFormat, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id));
1550 return iPixelFormat;
1551}
1552
1553/* Context activation is done by the caller. */
1554static void bind_dummy_textures(const struct wined3d_device *device, const struct wined3d_context *context)
1555{
1556 const struct wined3d_gl_info *gl_info = context->gl_info;
1557 unsigned int i, count = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers);
1558
1559 for (i = 0; i < count; ++i)
1560 {
1561 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1562 checkGLcall("glActiveTextureARB");
1563
1564 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, device->dummy_texture_2d[i]);
1565 checkGLcall("glBindTexture");
1566
1567 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1568 {
1569 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, device->dummy_texture_rect[i]);
1570 checkGLcall("glBindTexture");
1571 }
1572
1573 if (gl_info->supported[EXT_TEXTURE3D])
1574 {
1575 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, device->dummy_texture_3d[i]);
1576 checkGLcall("glBindTexture");
1577 }
1578
1579 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1580 {
1581 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, device->dummy_texture_cube[i]);
1582 checkGLcall("glBindTexture");
1583 }
1584 }
1585}
1586
1587#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1588static DECLCALLBACK(void) context_tls_dtor(void* pvCtx)
1589{
1590 struct wined3d_context * context = (struct wined3d_context *)pvCtx;
1591 HeapFree(GetProcessHeap(), 0, context);
1592}
1593#endif
1594
1595BOOL context_debug_output_enabled(const struct wined3d_gl_info *gl_info)
1596{
1597 return gl_info->supported[ARB_DEBUG_OUTPUT]
1598 && (ERR_ON(d3d) || FIXME_ON(d3d) || WARN_ON(d3d_perf));
1599}
1600
1601static void WINE_GLAPI wined3d_debug_callback(GLenum source, GLenum type, GLuint id,
1602 GLenum severity, GLsizei length, const char *message, void *ctx)
1603{
1604 switch (type)
1605 {
1606 case GL_DEBUG_TYPE_ERROR_ARB:
1607 ERR("%p: %s.\n", ctx, debugstr_an(message, length));
1608 break;
1609
1610 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
1611 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
1612 case GL_DEBUG_TYPE_PORTABILITY_ARB:
1613 FIXME("%p: %s.\n", ctx, debugstr_an(message, length));
1614 break;
1615
1616 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
1617 WARN_(d3d_perf)("%p: %s.\n", ctx, debugstr_an(message, length));
1618 break;
1619
1620 default:
1621 FIXME("ctx %p, type %#x: %s.\n", ctx, type, debugstr_an(message, length));
1622 break;
1623 }
1624}
1625
1626/* Do not call while under the GL lock. */
1627struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
1628 struct wined3d_surface *target, const struct wined3d_format *ds_format
1629#ifdef VBOX_WITH_WDDM
1630 , struct VBOXUHGSMI *pHgsmi
1631#endif
1632 )
1633{
1634 struct wined3d_device *device = swapchain->device;
1635 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1636 const struct wined3d_format *color_format;
1637 struct wined3d_context *ret;
1638 BOOL auxBuffers = FALSE;
1639 HGLRC ctx, share_ctx;
1640 int pixel_format;
1641 unsigned int s;
1642 int swap_interval;
1643 DWORD state;
1644 HDC hdc;
1645
1646 TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
1647
1648#ifdef VBOX_WITH_WDDM
1649 if (!pHgsmi)
1650 {
1651 ERR("HGSMI should be specified!");
1652 return NULL;
1653 }
1654#endif
1655
1656 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
1657 if (!ret)
1658 return NULL;
1659
1660 ret->blit_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1661 gl_info->limits.buffers * sizeof(*ret->blit_targets));
1662 if (!ret->blit_targets)
1663 goto out;
1664
1665 ret->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1666 gl_info->limits.buffers * sizeof(*ret->draw_buffers));
1667 if (!ret->draw_buffers)
1668 goto out;
1669
1670 ret->free_occlusion_query_size = 4;
1671 ret->free_occlusion_queries = HeapAlloc(GetProcessHeap(), 0,
1672 ret->free_occlusion_query_size * sizeof(*ret->free_occlusion_queries));
1673 if (!ret->free_occlusion_queries)
1674 goto out;
1675
1676 list_init(&ret->occlusion_queries);
1677
1678 ret->free_event_query_size = 4;
1679 ret->free_event_queries = HeapAlloc(GetProcessHeap(), 0,
1680 ret->free_event_query_size * sizeof(*ret->free_event_queries));
1681 if (!ret->free_event_queries)
1682 goto out;
1683
1684 list_init(&ret->event_queries);
1685 list_init(&ret->fbo_list);
1686 list_init(&ret->fbo_destroy_list);
1687
1688#if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1689 VBoxTlsRefInit(ret, context_tls_dtor);
1690#endif
1691
1692#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
1693 ret->device = device;
1694 if (!swapchain->hDC)
1695 {
1696 ERR("Swapchain hDC is null");
1697 goto out;
1698 }
1699 hdc = swapchain->hDC;
1700#else
1701 if (!(hdc = GetDC(swapchain->win_handle)))
1702 {
1703 WARN("Failed to retireve device context, trying swapchain backup.\n");
1704 if (!(hdc = swapchain_get_backup_dc(swapchain)))
1705 {
1706 ERR("Failed to retrieve a device context.\n");
1707 goto out;
1708 }
1709 }
1710#endif
1711
1712 color_format = target->resource.format;
1713
1714 /* In case of ORM_BACKBUFFER, make sure to request an alpha component for
1715 * X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
1716 if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
1717 {
1718 auxBuffers = TRUE;
1719
1720 if (color_format->id == WINED3DFMT_B4G4R4X4_UNORM)
1721 color_format = wined3d_get_format(gl_info, WINED3DFMT_B4G4R4A4_UNORM);
1722 else if (color_format->id == WINED3DFMT_B8G8R8X8_UNORM)
1723 color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
1724 }
1725
1726 /* DirectDraw supports 8bit paletted render targets and these are used by
1727 * old games like StarCraft and C&C. Most modern hardware doesn't support
1728 * 8bit natively so we perform some form of 8bit -> 32bit conversion. The
1729 * conversion (ab)uses the alpha component for storing the palette index.
1730 * For this reason we require a format with 8bit alpha, so request
1731 * A8R8G8B8. */
1732 if (color_format->id == WINED3DFMT_P8_UINT)
1733 color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
1734
1735 /* Try to find a pixel format which matches our requirements. */
1736 pixel_format = context_choose_pixel_format(device, hdc, color_format, ds_format, auxBuffers, FALSE);
1737
1738 /* Try to locate a compatible format if we weren't able to find anything. */
1739 if (!pixel_format)
1740 {
1741 TRACE("Trying to locate a compatible pixel format because an exact match failed.\n");
1742 pixel_format = context_choose_pixel_format(device, hdc, color_format, ds_format, auxBuffers, TRUE);
1743 }
1744
1745 /* If we still don't have a pixel format, something is very wrong as ChoosePixelFormat barely fails */
1746 if (!pixel_format)
1747 {
1748 ERR("Can't find a suitable pixel format.\n");
1749 goto out;
1750 }
1751
1752 context_enter(ret);
1753#ifndef VBOX
1754 if (!context_set_pixel_format(gl_info, hdc, pixel_format))
1755 {
1756 ERR("Failed to set pixel format %d on device context %p.\n", pixel_format, hdc);
1757 context_release(ret);
1758 goto out;
1759 }
1760
1761 share_ctx = device->context_count ? device->contexts[0]->glCtx : NULL;
1762 if (gl_info->p_wglCreateContextAttribsARB)
1763 {
1764 unsigned int ctx_attrib_idx = 0;
1765 GLint ctx_attribs[3];
1766
1767 if (context_debug_output_enabled(gl_info))
1768 {
1769 ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_FLAGS_ARB;
1770 ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_DEBUG_BIT_ARB;
1771 }
1772 ctx_attribs[ctx_attrib_idx] = 0;
1773
1774 if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
1775 {
1776 ERR("Failed to create a WGL context.\n");
1777 context_release(ret);
1778 goto out;
1779 }
1780 }
1781 else
1782 {
1783 if (!(ctx = wglCreateContext(hdc)))
1784#else
1785 ctx = pVBoxCreateContext(hdc
1786#ifdef VBOX_WITH_WDDM
1787 , pHgsmi
1788#else
1789 , NULL
1790#endif
1791 );
1792 if (!ctx)
1793#endif
1794 {
1795 ERR("Failed to create a WGL context.\n");
1796 context_release(ret);
1797 goto out;
1798 }
1799
1800#ifndef VBOX
1801 if (share_ctx && !wglShareLists(share_ctx, ctx))
1802 {
1803 ERR("wglShareLists(%p, %p) failed, last error %#x.\n", share_ctx, ctx, GetLastError());
1804 context_release(ret);
1805 if (!wglDeleteContext(ctx))
1806 ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
1807 goto out;
1808 }
1809 }
1810#endif
1811
1812 if (!device_context_add(device, ret))
1813 {
1814 ERR("Failed to add the newly created context to the context list\n");
1815 context_release(ret);
1816 if (!wglDeleteContext(ctx))
1817 ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
1818 goto out;
1819 }
1820
1821 ret->gl_info = gl_info;
1822 ret->d3d_info = &device->adapter->d3d_info;
1823 ret->state_table = device->StateTable;
1824
1825 /* Mark all states dirty to force a proper initialization of the states
1826 * on the first use of the context. */
1827 for (state = 0; state <= STATE_HIGHEST; ++state)
1828 {
1829 if (ret->state_table[state].representative)
1830 context_invalidate_state(ret, state);
1831 }
1832
1833 ret->swapchain = swapchain;
1834 ret->current_rt = target;
1835#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1836 ret->tid = GetCurrentThreadId();
1837#else
1838 ret->tid = 0;
1839#endif
1840
1841 ret->render_offscreen = surface_is_offscreen(target);
1842 ret->draw_buffers_mask = context_generate_rt_mask(GL_BACK);
1843 ret->valid = 1;
1844
1845 ret->glCtx = ctx;
1846#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1847 ret->win_handle = swapchain->win_handle;
1848 ret->hdc = hdc;
1849#endif
1850 ret->pixel_format = pixel_format;
1851
1852 /* Set up the context defaults */
1853 if (!context_set_current(ret))
1854 {
1855 ERR("Cannot activate context to set up defaults.\n");
1856 device_context_remove(device, ret);
1857 context_release(ret);
1858 if (!wglDeleteContext(ctx))
1859 ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
1860 goto out;
1861 }
1862
1863 if (context_debug_output_enabled(gl_info))
1864 {
1865 GL_EXTCALL(glDebugMessageCallbackARB(wined3d_debug_callback, ret));
1866 if (TRACE_ON(d3d_synchronous))
1867 gl_info->gl_ops.gl.p_glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
1868 GL_EXTCALL(glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE));
1869 if (ERR_ON(d3d))
1870 {
1871 GL_EXTCALL(glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR_ARB,
1872 GL_DONT_CARE, 0, NULL, GL_TRUE));
1873 }
1874 if (FIXME_ON(d3d))
1875 {
1876 GL_EXTCALL(glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB,
1877 GL_DONT_CARE, 0, NULL, GL_TRUE));
1878 GL_EXTCALL(glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB,
1879 GL_DONT_CARE, 0, NULL, GL_TRUE));
1880 GL_EXTCALL(glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_PORTABILITY_ARB,
1881 GL_DONT_CARE, 0, NULL, GL_TRUE));
1882 }
1883 if (WARN_ON(d3d_perf))
1884 {
1885 GL_EXTCALL(glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE_ARB,
1886 GL_DONT_CARE, 0, NULL, GL_TRUE));
1887 }
1888 }
1889
1890 switch (swapchain->desc.swap_interval)
1891 {
1892 case WINED3DPRESENT_INTERVAL_IMMEDIATE:
1893 swap_interval = 0;
1894 break;
1895 case WINED3DPRESENT_INTERVAL_DEFAULT:
1896 case WINED3DPRESENT_INTERVAL_ONE:
1897 swap_interval = 1;
1898 break;
1899 case WINED3DPRESENT_INTERVAL_TWO:
1900 swap_interval = 2;
1901 break;
1902 case WINED3DPRESENT_INTERVAL_THREE:
1903 swap_interval = 3;
1904 break;
1905 case WINED3DPRESENT_INTERVAL_FOUR:
1906 swap_interval = 4;
1907 break;
1908 default:
1909 FIXME("Unknown swap interval %#x.\n", swapchain->desc.swap_interval);
1910 swap_interval = 1;
1911 }
1912
1913 if (gl_info->supported[WGL_EXT_SWAP_CONTROL])
1914 {
1915 if (!GL_EXTCALL(wglSwapIntervalEXT(swap_interval)))
1916 ERR("wglSwapIntervalEXT failed to set swap interval %d for context %p, last error %#x\n",
1917 swap_interval, ret, GetLastError());
1918 }
1919
1920#ifdef VBOX
1921 /* for WDDM case this is used for shared resource handling
1922 *
1923 * for XPDM this is needed to at least support texture sharing between device contexts.
1924 * this is a kinda hack, but it is needed since our ogl driver currently does not support ShareLists */
1925 pglChromiumParameteriCR(GL_SHARE_CONTEXT_RESOURCES_CR, GL_TRUE);
1926# if defined(VBOX_WINE_WITH_SINGLE_CONTEXT) || defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
1927 pglChromiumParameteriCR(GL_FLUSH_ON_THREAD_SWITCH_CR, GL_TRUE);
1928# endif
1929# if defined(VBOX_WITH_WDDM)
1930 pglChromiumParameteriCR(GL_HOST_WND_CREATED_HIDDEN_CR, GL_TRUE);
1931# endif
1932#endif
1933
1934 gl_info->gl_ops.gl.p_glGetIntegerv(GL_AUX_BUFFERS, &ret->aux_buffers);
1935
1936 TRACE("Setting up the screen\n");
1937
1938 gl_info->gl_ops.gl.p_glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
1939 checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
1940
1941 gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
1942 checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
1943
1944 gl_info->gl_ops.gl.p_glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
1945 checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
1946
1947 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);
1948 checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
1949 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);
1950 checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, device->surface_alignment);");
1951
1952 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1953 {
1954 /* Most textures will use client storage if supported. Exceptions are
1955 * non-native power of 2 textures and textures in DIB sections. */
1956 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1957 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1958 }
1959 if (gl_info->supported[ARB_VERTEX_BLEND])
1960 {
1961 /* Direct3D always uses n-1 weights for n world matrices and uses
1962 * 1 - sum for the last one this is equal to GL_WEIGHT_SUM_UNITY_ARB.
1963 * Enabling it doesn't do anything unless GL_VERTEX_BLEND_ARB isn't
1964 * enabled as well. */
1965 gl_info->gl_ops.gl.p_glEnable(GL_WEIGHT_SUM_UNITY_ARB);
1966 checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
1967 }
1968 if (gl_info->supported[NV_TEXTURE_SHADER2])
1969 {
1970 /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
1971 * the previous texture where to source the offset from is always unit - 1.
1972 */
1973 for (s = 1; s < gl_info->limits.textures; ++s)
1974 {
1975 context_active_texture(ret, gl_info, s);
1976 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_SHADER_NV,
1977 GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1);
1978 checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
1979 }
1980 }
1981 if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
1982 {
1983 /* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
1984 * enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
1985 * GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
1986 * because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
1987 * is ever assigned.
1988 *
1989 * So make sure a program is assigned to each context. The first real ARBFP use will set a different
1990 * program and the dummy program is destroyed when the context is destroyed.
1991 */
1992 const char *dummy_program =
1993 "!!ARBfp1.0\n"
1994 "MOV result.color, fragment.color.primary;\n"
1995 "END\n";
1996 GL_EXTCALL(glGenProgramsARB(1, &ret->dummy_arbfp_prog));
1997 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret->dummy_arbfp_prog));
1998 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
1999 }
2000
2001 if (gl_info->supported[ARB_POINT_SPRITE])
2002 {
2003 for (s = 0; s < gl_info->limits.textures; ++s)
2004 {
2005 context_active_texture(ret, gl_info, s);
2006 gl_info->gl_ops.gl.p_glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
2007 checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
2008 }
2009 }
2010
2011 if (gl_info->supported[ARB_PROVOKING_VERTEX])
2012 {
2013 GL_EXTCALL(glProvokingVertex(GL_FIRST_VERTEX_CONVENTION));
2014 }
2015 else if (gl_info->supported[EXT_PROVOKING_VERTEX])
2016 {
2017 GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
2018 }
2019 ret->select_shader = 1;
2020
2021 /* If this happens to be the first context for the device, dummy textures
2022 * are not created yet. In that case, they will be created (and bound) by
2023 * create_dummy_textures right after this context is initialized. */
2024 if (device->dummy_texture_2d[0])
2025 bind_dummy_textures(device, ret);
2026
2027 TRACE("Created context %p.\n", ret);
2028
2029 return ret;
2030
2031out:
2032 HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
2033 HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
2034 HeapFree(GetProcessHeap(), 0, ret->draw_buffers);
2035 HeapFree(GetProcessHeap(), 0, ret->blit_targets);
2036 HeapFree(GetProcessHeap(), 0, ret);
2037 return NULL;
2038}
2039
2040/* Do not call while under the GL lock. */
2041void context_destroy(struct wined3d_device *device, struct wined3d_context *context)
2042{
2043#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
2044 BOOL destroy;
2045#endif
2046
2047 TRACE("Destroying ctx %p\n", context);
2048
2049#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
2050 if (context->tid == GetCurrentThreadId() || !context->current)
2051 {
2052 context_destroy_gl_resources(context);
2053 TlsSetValue(wined3d_context_tls_idx, NULL);
2054 destroy = TRUE;
2055 }
2056 else
2057 {
2058 /* Make a copy of gl_info for context_destroy_gl_resources use, the one
2059 in wined3d_adapter may go away in the meantime */
2060 struct wined3d_gl_info *gl_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*gl_info));
2061 *gl_info = *context->gl_info;
2062 context->gl_info = gl_info;
2063 context->destroyed = 1;
2064 destroy = FALSE;
2065 }
2066#else
2067 context_destroy_gl_resources(context);
2068#endif
2069
2070 HeapFree(GetProcessHeap(), 0, context->draw_buffers);
2071 HeapFree(GetProcessHeap(), 0, context->blit_targets);
2072 device_context_remove(device, context);
2073#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
2074 if (destroy) HeapFree(GetProcessHeap(), 0, context);
2075#else
2076 context->swapchain = NULL;
2077
2078 VBoxTlsRefMarkDestroy(context);
2079 VBoxTlsRefRelease(context);
2080#endif
2081}
2082
2083/* Context activation is done by the caller. */
2084static void set_blit_dimension(const struct wined3d_gl_info *gl_info, UINT width, UINT height)
2085{
2086 const GLdouble projection[] =
2087 {
2088 2.0 / width, 0.0, 0.0, 0.0,
2089 0.0, 2.0 / height, 0.0, 0.0,
2090 0.0, 0.0, 2.0, 0.0,
2091 -1.0, -1.0, -1.0, 1.0,
2092 };
2093
2094 gl_info->gl_ops.gl.p_glMatrixMode(GL_PROJECTION);
2095 checkGLcall("glMatrixMode(GL_PROJECTION)");
2096 gl_info->gl_ops.gl.p_glLoadMatrixd(projection);
2097 checkGLcall("glLoadMatrixd");
2098 gl_info->gl_ops.gl.p_glViewport(0, 0, width, height);
2099 checkGLcall("glViewport");
2100}
2101
2102static void context_get_rt_size(const struct wined3d_context *context, SIZE *size)
2103{
2104 const struct wined3d_surface *rt = context->current_rt;
2105
2106 if (rt->swapchain && rt->swapchain->front_buffer == rt)
2107 {
2108 RECT window_size;
2109#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
2110 ERR("not tested!");
2111 GetClientRect(rt->swapchain->win_handle, &window_size);
2112#else
2113 GetClientRect(context->win_handle, &window_size);
2114#endif
2115#ifdef DEBUG_misha
2116 Assert(window_size.right - window_size.left == rt->resource.width);
2117 Assert(window_size.bottom - window_size.top == rt->resource.height);
2118#endif
2119 size->cx = window_size.right - window_size.left;
2120 size->cy = window_size.bottom - window_size.top;
2121
2122 return;
2123 }
2124 size->cx = rt->resource.width;
2125 size->cy = rt->resource.height;
2126}
2127
2128/*****************************************************************************
2129 * SetupForBlit
2130 *
2131 * Sets up a context for DirectDraw blitting.
2132 * All texture units are disabled, texture unit 0 is set as current unit
2133 * fog, lighting, blending, alpha test, z test, scissor test, culling disabled
2134 * color writing enabled for all channels
2135 * register combiners disabled, shaders disabled
2136 * world matrix is set to identity, texture matrix 0 too
2137 * projection matrix is setup for drawing screen coordinates
2138 *
2139 * Params:
2140 * This: Device to activate the context for
2141 * context: Context to setup
2142 *
2143 *****************************************************************************/
2144/* Context activation is done by the caller. */
2145static void SetupForBlit(const struct wined3d_device *device, struct wined3d_context *context)
2146{
2147 int i;
2148 const struct wined3d_gl_info *gl_info = context->gl_info;
2149 DWORD sampler;
2150 SIZE rt_size;
2151
2152 TRACE("Setting up context %p for blitting\n", context);
2153
2154 context_get_rt_size(context, &rt_size);
2155
2156 if (context->last_was_blit)
2157 {
2158 if (context->blit_w != rt_size.cx || context->blit_h != rt_size.cy)
2159 {
2160 set_blit_dimension(gl_info, rt_size.cx, rt_size.cy);
2161 context->blit_w = rt_size.cx;
2162 context->blit_h = rt_size.cy;
2163 /* No need to dirtify here, the states are still dirtified because
2164 * they weren't applied since the last SetupForBlit() call. */
2165 }
2166 TRACE("Context is already set up for blitting, nothing to do\n");
2167 return;
2168 }
2169 context->last_was_blit = TRUE;
2170
2171 /* Disable all textures. The caller can then bind a texture it wants to blit
2172 * from
2173 *
2174 * The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
2175 * function texture unit. No need to care for higher samplers
2176 */
2177 for (i = gl_info->limits.textures - 1; i > 0 ; --i)
2178 {
2179 sampler = device->rev_tex_unit_map[i];
2180 context_active_texture(context, gl_info, i);
2181
2182 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2183 {
2184 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2185 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
2186 }
2187 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_3D);
2188 checkGLcall("glDisable GL_TEXTURE_3D");
2189 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2190 {
2191 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2192 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
2193 }
2194 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2195 checkGLcall("glDisable GL_TEXTURE_2D");
2196
2197 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2198 checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
2199
2200 if (sampler != WINED3D_UNMAPPED_STAGE)
2201 {
2202 if (sampler < MAX_TEXTURES)
2203 context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3D_TSS_COLOR_OP));
2204 context_invalidate_state(context, STATE_SAMPLER(sampler));
2205 }
2206 }
2207 context_active_texture(context, gl_info, 0);
2208
2209 sampler = device->rev_tex_unit_map[0];
2210
2211 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2212 {
2213 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2214 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
2215 }
2216 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_3D);
2217 checkGLcall("glDisable GL_TEXTURE_3D");
2218 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2219 {
2220 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2221 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
2222 }
2223 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2224 checkGLcall("glDisable GL_TEXTURE_2D");
2225
2226 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2227
2228 gl_info->gl_ops.gl.p_glMatrixMode(GL_TEXTURE);
2229 checkGLcall("glMatrixMode(GL_TEXTURE)");
2230 gl_info->gl_ops.gl.p_glLoadIdentity();
2231 checkGLcall("glLoadIdentity()");
2232
2233 if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
2234 {
2235 gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
2236 GL_TEXTURE_LOD_BIAS_EXT, 0.0f);
2237 checkGLcall("glTexEnvf GL_TEXTURE_LOD_BIAS_EXT ...");
2238 }
2239
2240 if (sampler != WINED3D_UNMAPPED_STAGE)
2241 {
2242 if (sampler < MAX_TEXTURES)
2243 {
2244 context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_TEXTURE0 + sampler));
2245 context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3D_TSS_COLOR_OP));
2246 }
2247 context_invalidate_state(context, STATE_SAMPLER(sampler));
2248 }
2249
2250 /* Other misc states */
2251 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2252 checkGLcall("glDisable(GL_ALPHA_TEST)");
2253 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHATESTENABLE));
2254 gl_info->gl_ops.gl.p_glDisable(GL_LIGHTING);
2255 checkGLcall("glDisable GL_LIGHTING");
2256 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_LIGHTING));
2257 gl_info->gl_ops.gl.p_glDisable(GL_DEPTH_TEST);
2258 checkGLcall("glDisable GL_DEPTH_TEST");
2259 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZENABLE));
2260 glDisableWINE(GL_FOG);
2261 checkGLcall("glDisable GL_FOG");
2262 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_FOGENABLE));
2263 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2264 checkGLcall("glDisable GL_BLEND");
2265 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
2266 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2267 checkGLcall("glDisable GL_CULL_FACE");
2268 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CULLMODE));
2269 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2270 checkGLcall("glDisable GL_STENCIL_TEST");
2271 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILENABLE));
2272 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2273 checkGLcall("glDisable GL_SCISSOR_TEST");
2274 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
2275 if (gl_info->supported[ARB_POINT_SPRITE])
2276 {
2277 gl_info->gl_ops.gl.p_glDisable(GL_POINT_SPRITE_ARB);
2278 checkGLcall("glDisable GL_POINT_SPRITE_ARB");
2279 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE));
2280 }
2281 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE);
2282 checkGLcall("glColorMask");
2283 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
2284 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
2285 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
2286 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
2287 if (gl_info->supported[EXT_SECONDARY_COLOR])
2288 {
2289 gl_info->gl_ops.gl.p_glDisable(GL_COLOR_SUM_EXT);
2290 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SPECULARENABLE));
2291 checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
2292 }
2293
2294 /* Setup transforms */
2295 gl_info->gl_ops.gl.p_glMatrixMode(GL_MODELVIEW);
2296 checkGLcall("glMatrixMode(GL_MODELVIEW)");
2297 gl_info->gl_ops.gl.p_glLoadIdentity();
2298 checkGLcall("glLoadIdentity()");
2299 context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(0)));
2300
2301 context->last_was_rhw = TRUE;
2302 context_invalidate_state(context, STATE_VDECL); /* because of last_was_rhw = TRUE */
2303
2304 gl_info->gl_ops.gl.p_glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)");
2305 gl_info->gl_ops.gl.p_glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)");
2306 gl_info->gl_ops.gl.p_glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)");
2307 gl_info->gl_ops.gl.p_glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)");
2308 gl_info->gl_ops.gl.p_glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)");
2309 gl_info->gl_ops.gl.p_glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)");
2310 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CLIPPING));
2311
2312 set_blit_dimension(gl_info, rt_size.cx, rt_size.cy);
2313
2314 /* Disable shaders */
2315 device->shader_backend->shader_disable(device->shader_priv, context);
2316 context->select_shader = 1;
2317 context->load_constants = 1;
2318
2319 context->blit_w = rt_size.cx;
2320 context->blit_h = rt_size.cy;
2321 context_invalidate_state(context, STATE_VIEWPORT);
2322 context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
2323}
2324
2325static inline BOOL is_rt_mask_onscreen(DWORD rt_mask)
2326{
2327 return rt_mask & (1 << 31);
2328}
2329
2330static inline GLenum draw_buffer_from_rt_mask(DWORD rt_mask)
2331{
2332 return rt_mask & ~(1 << 31);
2333}
2334
2335/* Context activation is done by the caller. */
2336static void context_apply_draw_buffers(struct wined3d_context *context, DWORD rt_mask)
2337{
2338 const struct wined3d_gl_info *gl_info = context->gl_info;
2339
2340 if (!rt_mask)
2341 {
2342 gl_info->gl_ops.gl.p_glDrawBuffer(GL_NONE);
2343 checkGLcall("glDrawBuffer()");
2344 }
2345 else if (is_rt_mask_onscreen(rt_mask))
2346 {
2347 gl_info->gl_ops.gl.p_glDrawBuffer(draw_buffer_from_rt_mask(rt_mask));
2348 checkGLcall("glDrawBuffer()");
2349 }
2350 else
2351 {
2352 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2353 {
2354 unsigned int i = 0;
2355
2356 while (rt_mask)
2357 {
2358 if (rt_mask & 1)
2359 context->draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
2360 else
2361 context->draw_buffers[i] = GL_NONE;
2362
2363 rt_mask >>= 1;
2364 ++i;
2365 }
2366
2367 if (gl_info->supported[ARB_DRAW_BUFFERS])
2368 {
2369 GL_EXTCALL(glDrawBuffersARB(i, context->draw_buffers));
2370 checkGLcall("glDrawBuffers()");
2371 }
2372 else
2373 {
2374 gl_info->gl_ops.gl.p_glDrawBuffer(context->draw_buffers[0]);
2375 checkGLcall("glDrawBuffer()");
2376 }
2377 }
2378 else
2379 {
2380 ERR("Unexpected draw buffers mask with backbuffer ORM.\n");
2381 }
2382 }
2383}
2384
2385/* Context activation is done by the caller. */
2386void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer)
2387{
2388 const struct wined3d_gl_info *gl_info = context->gl_info;
2389 DWORD *current_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2390 DWORD new_mask = context_generate_rt_mask(buffer);
2391
2392 if (new_mask == *current_mask)
2393 return;
2394
2395 gl_info->gl_ops.gl.p_glDrawBuffer(buffer);
2396 checkGLcall("glDrawBuffer()");
2397
2398 *current_mask = new_mask;
2399}
2400
2401/* Context activation is done by the caller. */
2402void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info, unsigned int unit)
2403{
2404 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0 + unit));
2405 checkGLcall("glActiveTextureARB");
2406 context->active_texture = unit;
2407}
2408
2409void context_bind_texture(struct wined3d_context *context, GLenum target, GLuint name)
2410{
2411 const struct wined3d_gl_info *gl_info = context->gl_info;
2412 DWORD unit = context->active_texture;
2413 DWORD old_texture_type = context->texture_type[unit];
2414
2415 if (name)
2416 {
2417 gl_info->gl_ops.gl.p_glBindTexture(target, name);
2418 checkGLcall("glBindTexture");
2419 }
2420 else
2421 {
2422 target = GL_NONE;
2423 }
2424
2425 if (old_texture_type != target)
2426 {
2427 const struct wined3d_device *device = context->swapchain->device;
2428
2429 switch (old_texture_type)
2430 {
2431 case GL_NONE:
2432 /* nothing to do */
2433 break;
2434 case GL_TEXTURE_2D:
2435 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, device->dummy_texture_2d[unit]);
2436 checkGLcall("glBindTexture");
2437 break;
2438 case GL_TEXTURE_RECTANGLE_ARB:
2439 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, device->dummy_texture_rect[unit]);
2440 checkGLcall("glBindTexture");
2441 break;
2442 case GL_TEXTURE_CUBE_MAP:
2443 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, device->dummy_texture_cube[unit]);
2444 checkGLcall("glBindTexture");
2445 break;
2446 case GL_TEXTURE_3D:
2447 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, device->dummy_texture_3d[unit]);
2448 checkGLcall("glBindTexture");
2449 break;
2450 default:
2451 ERR("Unexpected texture target %#x\n", old_texture_type);
2452 }
2453
2454 context->texture_type[unit] = target;
2455 }
2456}
2457
2458static void context_set_render_offscreen(struct wined3d_context *context, BOOL offscreen)
2459{
2460 if (context->render_offscreen == offscreen) return;
2461
2462 context_invalidate_state(context, STATE_POINTSPRITECOORDORIGIN);
2463 context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
2464 context_invalidate_state(context, STATE_VIEWPORT);
2465 context_invalidate_state(context, STATE_SCISSORRECT);
2466 context_invalidate_state(context, STATE_FRONTFACE);
2467 context->render_offscreen = offscreen;
2468}
2469
2470static BOOL match_depth_stencil_format(const struct wined3d_format *existing,
2471 const struct wined3d_format *required)
2472{
2473 BYTE existing_depth, existing_stencil, required_depth, required_stencil;
2474
2475 if (existing == required) return TRUE;
2476 if ((existing->flags & WINED3DFMT_FLAG_FLOAT) != (required->flags & WINED3DFMT_FLAG_FLOAT)) return FALSE;
2477
2478 getDepthStencilBits(existing, &existing_depth, &existing_stencil);
2479 getDepthStencilBits(required, &required_depth, &required_stencil);
2480
2481 if(existing_depth < required_depth) return FALSE;
2482 /* If stencil bits are used the exact amount is required - otherwise wrapping
2483 * won't work correctly */
2484 if(required_stencil && required_stencil != existing_stencil) return FALSE;
2485 return TRUE;
2486}
2487
2488/* The caller provides a context */
2489static void context_validate_onscreen_formats(struct wined3d_context *context,
2490 const struct wined3d_surface *depth_stencil)
2491{
2492 /* Onscreen surfaces are always in a swapchain */
2493 struct wined3d_swapchain *swapchain = context->current_rt->swapchain;
2494
2495 if (context->render_offscreen || !depth_stencil) return;
2496 if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->resource.format)) return;
2497
2498 /* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
2499 * or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
2500 * format. */
2501 WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
2502
2503 /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
2504 surface_load_location(context->current_rt, SFLAG_INTEXTURE, NULL);
2505 swapchain->render_to_fbo = TRUE;
2506 swapchain_update_draw_bindings(swapchain);
2507 context_set_render_offscreen(context, TRUE);
2508}
2509
2510static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_device *device, const struct wined3d_surface *rt)
2511{
2512 if (!rt || rt->resource.format->id == WINED3DFMT_NULL)
2513 return 0;
2514 else if (rt->swapchain)
2515 return context_generate_rt_mask_from_surface(rt);
2516 else
2517 return context_generate_rt_mask(device->offscreenBuffer);
2518}
2519
2520/* Context activation is done by the caller. */
2521void context_apply_blit_state(struct wined3d_context *context, const struct wined3d_device *device)
2522{
2523 struct wined3d_surface *rt = context->current_rt;
2524 DWORD rt_mask, *cur_mask;
2525
2526 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2527 {
2528 context_validate_onscreen_formats(context, NULL);
2529
2530 if (context->render_offscreen)
2531 {
2532 surface_internal_preload(rt, SRGB_RGB);
2533
2534 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, rt, NULL, rt->draw_binding);
2535 if (rt->resource.format->id != WINED3DFMT_NULL)
2536 rt_mask = 1;
2537 else
2538 rt_mask = 0;
2539 }
2540 else
2541 {
2542 context->current_fbo = NULL;
2543 context_bind_fbo(context, GL_FRAMEBUFFER, 0);
2544 rt_mask = context_generate_rt_mask_from_surface(rt);
2545 }
2546 }
2547 else
2548 {
2549 rt_mask = context_generate_rt_mask_no_fbo(device, rt);
2550 }
2551
2552 cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2553
2554 if (rt_mask != *cur_mask)
2555 {
2556 context_apply_draw_buffers(context, rt_mask);
2557 *cur_mask = rt_mask;
2558 }
2559
2560 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2561 {
2562 context_check_fbo_status(context, GL_FRAMEBUFFER);
2563 }
2564
2565 SetupForBlit(device, context);
2566 context_invalidate_state(context, STATE_FRAMEBUFFER);
2567}
2568
2569static BOOL context_validate_rt_config(UINT rt_count,
2570 struct wined3d_surface * const *rts, const struct wined3d_surface *ds)
2571{
2572 unsigned int i;
2573
2574 if (ds) return TRUE;
2575
2576 for (i = 0; i < rt_count; ++i)
2577 {
2578 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
2579 return TRUE;
2580 }
2581
2582 WARN("Invalid render target config, need at least one attachment.\n");
2583 return FALSE;
2584}
2585
2586/* Context activation is done by the caller. */
2587BOOL context_apply_clear_state(struct wined3d_context *context, const struct wined3d_device *device,
2588 UINT rt_count, const struct wined3d_fb_state *fb)
2589{
2590 const struct wined3d_gl_info *gl_info = context->gl_info;
2591 DWORD rt_mask = 0, *cur_mask;
2592 UINT i;
2593 struct wined3d_surface **rts = fb->render_targets;
2594
2595 if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != &device->fb
2596 || rt_count != context->gl_info->limits.buffers)
2597 {
2598 if (!context_validate_rt_config(rt_count, rts, fb->depth_stencil))
2599 return FALSE;
2600
2601 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2602 {
2603 context_validate_onscreen_formats(context, fb->depth_stencil);
2604
2605 if (!rt_count || surface_is_offscreen(rts[0]))
2606 {
2607 for (i = 0; i < rt_count; ++i)
2608 {
2609 context->blit_targets[i] = rts[i];
2610 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL)
2611 rt_mask |= (1 << i);
2612 }
2613 while (i < context->gl_info->limits.buffers)
2614 {
2615 context->blit_targets[i] = NULL;
2616 ++i;
2617 }
2618 context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, fb->depth_stencil,
2619 rt_count ? rts[0]->draw_binding : SFLAG_INTEXTURE);
2620 }
2621 else
2622 {
2623 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
2624 rt_mask = context_generate_rt_mask_from_surface(rts[0]);
2625 }
2626
2627 /* If the framebuffer is not the device's fb the device's fb has to be reapplied
2628 * next draw. Otherwise we could mark the framebuffer state clean here, once the
2629 * state management allows this */
2630 context_invalidate_state(context, STATE_FRAMEBUFFER);
2631 }
2632 else
2633 {
2634 rt_mask = context_generate_rt_mask_no_fbo(device, rt_count ? rts[0] : NULL);
2635 }
2636 }
2637 else if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
2638 && (!rt_count || surface_is_offscreen(rts[0])))
2639 {
2640 for (i = 0; i < rt_count; ++i)
2641 {
2642 if (rts[i] && rts[i]->resource.format->id != WINED3DFMT_NULL) rt_mask |= (1 << i);
2643 }
2644 }
2645 else
2646 {
2647 rt_mask = context_generate_rt_mask_no_fbo(device, rt_count ? rts[0] : NULL);
2648 }
2649
2650 cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2651
2652 if (rt_mask != *cur_mask)
2653 {
2654 context_apply_draw_buffers(context, rt_mask);
2655 *cur_mask = rt_mask;
2656 context_invalidate_state(context, STATE_FRAMEBUFFER);
2657 }
2658
2659 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2660 {
2661 context_check_fbo_status(context, GL_FRAMEBUFFER);
2662 }
2663
2664 if (context->last_was_blit)
2665 context->last_was_blit = FALSE;
2666
2667 /* Blending and clearing should be orthogonal, but tests on the nvidia
2668 * driver show that disabling blending when clearing improves the clearing
2669 * performance incredibly. */
2670 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2671 gl_info->gl_ops.gl.p_glEnable(GL_SCISSOR_TEST);
2672 checkGLcall("glEnable GL_SCISSOR_TEST");
2673
2674 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
2675 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
2676 context_invalidate_state(context, STATE_SCISSORRECT);
2677
2678 return TRUE;
2679}
2680
2681static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_device *device)
2682{
2683 const struct wined3d_state *state = &device->stateBlock->state;
2684 struct wined3d_surface **rts = state->fb->render_targets;
2685 struct wined3d_shader *ps = state->pixel_shader;
2686 DWORD rt_mask, rt_mask_bits;
2687 unsigned int i;
2688
2689 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return context_generate_rt_mask_no_fbo(device, rts[0]);
2690 else if (!context->render_offscreen) return context_generate_rt_mask_from_surface(rts[0]);
2691
2692 rt_mask = ps ? ps->reg_maps.rt_mask : 1;
2693 rt_mask &= context->d3d_info->valid_rt_mask;
2694 rt_mask_bits = rt_mask;
2695 i = 0;
2696 while (rt_mask_bits)
2697 {
2698 rt_mask_bits &= ~(1 << i);
2699 if (!rts[i] || rts[i]->resource.format->id == WINED3DFMT_NULL)
2700 rt_mask &= ~(1 << i);
2701
2702 i++;
2703 }
2704
2705 return rt_mask;
2706}
2707
2708/* Context activation is done by the caller. */
2709void context_state_fb(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
2710{
2711 const struct wined3d_device *device = context->swapchain->device;
2712 const struct wined3d_fb_state *fb = state->fb;
2713 DWORD rt_mask = find_draw_buffers_mask(context, device);
2714 DWORD *cur_mask;
2715
2716 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2717 {
2718 if (!context->render_offscreen)
2719 {
2720 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL, SFLAG_INDRAWABLE);
2721 }
2722 else
2723 {
2724 context_apply_fbo_state(context, GL_FRAMEBUFFER, fb->render_targets, fb->depth_stencil,
2725 fb->render_targets[0]->draw_binding);
2726 }
2727 }
2728
2729 cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2730 if (rt_mask != *cur_mask)
2731 {
2732 context_apply_draw_buffers(context, rt_mask);
2733 *cur_mask = rt_mask;
2734 }
2735}
2736
2737/* Context activation is done by the caller. */
2738void context_state_drawbuf(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
2739{
2740 const struct wined3d_device *device = context->swapchain->device;
2741 DWORD rt_mask, *cur_mask;
2742
2743 if (isStateDirty(context, STATE_FRAMEBUFFER)) return;
2744
2745 cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2746 rt_mask = find_draw_buffers_mask(context, device);
2747 if (rt_mask != *cur_mask)
2748 {
2749 context_apply_draw_buffers(context, rt_mask);
2750 *cur_mask = rt_mask;
2751 }
2752}
2753
2754/* Context activation is done by the caller. */
2755BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_device *device)
2756{
2757 const struct wined3d_state *state = &device->stateBlock->state;
2758 const struct StateEntry *state_table = context->state_table;
2759 const struct wined3d_fb_state *fb = state->fb;
2760 unsigned int i;
2761
2762 if (!context_validate_rt_config(context->gl_info->limits.buffers,
2763 fb->render_targets, fb->depth_stencil))
2764 return FALSE;
2765
2766 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && isStateDirty(context, STATE_FRAMEBUFFER))
2767 {
2768 context_validate_onscreen_formats(context, fb->depth_stencil);
2769 }
2770
2771 /* Preload resources before FBO setup. Texture preload in particular may
2772 * result in changes to the current FBO, due to using e.g. FBO blits for
2773 * updating a resource location. */
2774 device_update_tex_unit_map(device);
2775 device_preload_textures(device);
2776 if (isStateDirty(context, STATE_VDECL) || isStateDirty(context, STATE_STREAMSRC))
2777 device_update_stream_info(device, context->gl_info);
2778 if (state->index_buffer)
2779 {
2780 if (device->stream_info.all_vbo)
2781 wined3d_buffer_preload(state->index_buffer);
2782 else
2783 buffer_get_sysmem(state->index_buffer, context->gl_info);
2784 }
2785
2786 for (i = 0; i < context->numDirtyEntries; ++i)
2787 {
2788 DWORD rep = context->dirtyArray[i];
2789 DWORD idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
2790 BYTE shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
2791 context->isStateDirty[idx] &= ~(1 << shift);
2792 state_table[rep].apply(context, state, rep);
2793 }
2794
2795 if (context->select_shader)
2796 {
2797 device->shader_backend->shader_select(device->shader_priv, context, state);
2798 context->select_shader = 0;
2799 }
2800
2801 if (context->load_constants)
2802 {
2803 device->shader_backend->shader_load_constants(device->shader_priv,
2804 context, state);
2805 context->load_constants = 0;
2806 }
2807
2808 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2809 {
2810 context_check_fbo_status(context, GL_FRAMEBUFFER);
2811 }
2812
2813 context->numDirtyEntries = 0; /* This makes the whole list clean */
2814 context->last_was_blit = FALSE;
2815
2816 return TRUE;
2817}
2818
2819static void context_setup_target(struct wined3d_context *context, struct wined3d_surface *target)
2820{
2821 BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
2822
2823 render_offscreen = surface_is_offscreen(target);
2824 if (context->current_rt == target && render_offscreen == old_render_offscreen) return;
2825
2826 /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
2827 * the alpha blend state changes with different render target formats. */
2828 if (!context->current_rt)
2829 {
2830 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
2831 }
2832 else
2833 {
2834 const struct wined3d_format *old = context->current_rt->resource.format;
2835 const struct wined3d_format *new = target->resource.format;
2836
2837 if (old->id != new->id)
2838 {
2839 /* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
2840 if ((old->alpha_size && !new->alpha_size) || (!old->alpha_size && new->alpha_size)
2841 || !(new->flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
2842 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
2843
2844 /* Update sRGB writing when switching between formats that do/do not support sRGB writing */
2845 if ((old->flags & WINED3DFMT_FLAG_SRGB_WRITE) != (new->flags & WINED3DFMT_FLAG_SRGB_WRITE))
2846 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
2847 }
2848
2849 /* When switching away from an offscreen render target, and we're not
2850 * using FBOs, we have to read the drawable into the texture. This is
2851 * done via PreLoad (and SFLAG_INDRAWABLE set on the surface). There
2852 * are some things that need care though. PreLoad needs a GL context,
2853 * and FindContext is called before the context is activated. It also
2854 * has to be called with the old rendertarget active, otherwise a
2855 * wrong drawable is read. */
2856 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
2857 && old_render_offscreen && context->current_rt != target)
2858 {
2859 /* Read the back buffer of the old drawable into the destination texture. */
2860 if (context->current_rt->texture_name_srgb)
2861 surface_internal_preload(context->current_rt, SRGB_SRGB);
2862 surface_internal_preload(context->current_rt, SRGB_RGB);
2863 surface_modify_location(context->current_rt, SFLAG_INDRAWABLE, FALSE);
2864 }
2865 }
2866
2867 context->current_rt = target;
2868 context_set_render_offscreen(context, render_offscreen);
2869}
2870
2871/* Do not call while under the GL lock. */
2872struct wined3d_context *context_acquire(const struct wined3d_device *device, struct wined3d_surface *target)
2873{
2874 struct wined3d_context *current_context = context_get_current();
2875 struct wined3d_context *context;
2876#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
2877 struct wined3d_swapchain *swapchain = NULL;
2878#endif
2879
2880 TRACE("device %p, target %p.\n", device, target);
2881
2882#if !defined(VBOX_WINE_WITH_SINGLE_CONTEXT) && !defined(VBOX_WINE_WITH_SINGLE_SWAPCHAIN_CONTEXT)
2883 if (current_context && current_context->destroyed)
2884 current_context = NULL;
2885#endif
2886
2887 if (!target)
2888 {
2889 if (current_context
2890 && current_context->current_rt
2891#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
2892 && current_context->swapchain->device == device
2893#else
2894 && current_context->device == device
2895#endif
2896 )
2897 {
2898 target = current_context->current_rt;
2899 }
2900 else
2901 {
2902#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
2903 struct wined3d_swapchain *swapchain = device->swapchains[0];
2904#else
2905 swapchain = swapchain_find_valid_or_any(device);
2906 if (!swapchain)
2907 {
2908 ERR("no valid swapchain found!");
2909 swapchain = device->swapchains[0];
2910 Assert(swapchain);
2911 }
2912#endif
2913 if (swapchain->back_buffers)
2914 target = swapchain->back_buffers[0];
2915 else
2916 target = swapchain->front_buffer;
2917 }
2918 }
2919
2920#ifdef VBOX_WITH_WINE_DBG
2921 Assert(target);
2922#endif
2923
2924 if (current_context && current_context->current_rt == target)
2925 {
2926 context = current_context;
2927 }
2928 else if (target->swapchain)
2929 {
2930 TRACE("Rendering onscreen.\n");
2931
2932 context = swapchain_get_context(target->swapchain);
2933#ifdef VBOX_WINE_WITH_SINGLE_CONTEXT
2934 swapchain = target->swapchain;
2935 Assert(swapchain);
2936#endif
2937 }
2938 else
2939 {
2940 TRACE("Rendering offscreen.\n");
2941
2942#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
2943 /* Stay with the current context if possible. Otherwise use the
2944 * context for the primary swapchain. */
2945 if (current_context && current_context->swapchain->device == device)
2946 context = current_context;
2947 else
2948#endif
2949 context = swapchain_get_context(device->swapchains[0]);
2950 }
2951
2952#ifndef VBOX_WINE_WITH_SINGLE_CONTEXT
2953 context_update_window(context);
2954#else
2955 if (!swapchain)
2956 swapchain = swapchain_find_valid_or_any(device);
2957 context_update_window(context, swapchain);
2958#endif
2959 context_setup_target(context, target);
2960 context_enter(context);
2961 if (!context->valid) return context;
2962
2963 if (context != current_context)
2964 {
2965 if (!context_set_current(context))
2966 ERR("Failed to activate the new context.\n");
2967 }
2968 else if (context->restore_ctx)
2969 {
2970 context_set_gl_context(context);
2971 }
2972
2973 return context;
2974}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette