VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/context.c@ 41481

Last change on this file since 41481 was 41481, checked in by vboxsync, 13 years ago

wddm/3d: a bit more logging

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