ReactOS  0.4.12-dev-90-g2e2e63e
context.c
Go to the documentation of this file.
1 /*
2  * Context and render target management in wined3d
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2002-2004 Raphael Junqueira
6  * Copyright 2004 Christian Costa
7  * Copyright 2005 Oliver Stieber
8  * Copyright 2006, 2008 Henri Verbeet
9  * Copyright 2007-2011, 2013 Stefan Dösinger for CodeWeavers
10  * Copyright 2009-2011 Henri Verbeet for CodeWeavers
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include "config.h"
28 #include "wine/port.h"
29 
30 #include <stdio.h>
31 #ifdef HAVE_FLOAT_H
32 # include <float.h>
33 #endif
34 
35 #include "wined3d_private.h"
36 
37 #ifdef __REACTOS__
38 #include <reactos/undocuser.h>
39 #endif
40 
43 WINE_DECLARE_DEBUG_CHANNEL(d3d_synchronous);
44 
45 #define WINED3D_MAX_FBO_ENTRIES 64
46 #define WINED3D_ALL_LAYERS (~0u)
47 
49 
50 /* FBO helper functions */
51 
52 /* Context activation is done by the caller. */
54 {
55  const struct wined3d_gl_info *gl_info = context->gl_info;
56 
57  switch (target)
58  {
60  if (context->fbo_read_binding == fbo) return;
61  context->fbo_read_binding = fbo;
62  break;
63 
65  if (context->fbo_draw_binding == fbo) return;
66  context->fbo_draw_binding = fbo;
67  break;
68 
69  case GL_FRAMEBUFFER:
70  if (context->fbo_read_binding == fbo
71  && context->fbo_draw_binding == fbo) return;
72  context->fbo_read_binding = fbo;
73  context->fbo_draw_binding = fbo;
74  break;
75 
76  default:
77  FIXME("Unhandled target %#x.\n", target);
78  break;
79  }
80 
81  gl_info->fbo_ops.glBindFramebuffer(target, fbo);
82  checkGLcall("glBindFramebuffer()");
83 }
84 
85 /* Context activation is done by the caller. */
86 static void context_clean_fbo_attachments(const struct wined3d_gl_info *gl_info, GLenum target)
87 {
88  unsigned int i;
89 
90  for (i = 0; i < gl_info->limits.buffers; ++i)
91  {
92  gl_info->fbo_ops.glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0);
93  checkGLcall("glFramebufferTexture2D()");
94  }
95  gl_info->fbo_ops.glFramebufferTexture2D(target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
96  checkGLcall("glFramebufferTexture2D()");
97 
98  gl_info->fbo_ops.glFramebufferTexture2D(target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
99  checkGLcall("glFramebufferTexture2D()");
100 }
101 
102 /* Context activation is done by the caller. */
104 {
105  const struct wined3d_gl_info *gl_info = context->gl_info;
106 
107  context_bind_fbo(context, GL_FRAMEBUFFER, fbo);
109  context_bind_fbo(context, GL_FRAMEBUFFER, 0);
110 
111  gl_info->fbo_ops.glDeleteFramebuffers(1, &fbo);
112  checkGLcall("glDeleteFramebuffers()");
113 }
114 
115 static void context_attach_depth_stencil_rb(const struct wined3d_gl_info *gl_info,
116  GLenum fbo_target, DWORD flags, GLuint rb)
117 {
118  if (flags & WINED3D_FBO_ENTRY_FLAG_DEPTH)
119  {
120  gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb);
121  checkGLcall("glFramebufferRenderbuffer()");
122  }
123 
124  if (flags & WINED3D_FBO_ENTRY_FLAG_STENCIL)
125  {
126  gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb);
127  checkGLcall("glFramebufferRenderbuffer()");
128  }
129 }
130 
132  GLenum fbo_target, GLenum attachment, const struct wined3d_fbo_resource *resource)
133 {
134  const struct wined3d_gl_info *gl_info = context->gl_info;
135 
136  if (!resource)
137  {
138  gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, attachment, GL_TEXTURE_2D, 0, 0);
139  }
140  else if (resource->layer == WINED3D_ALL_LAYERS)
141  {
142  if (!gl_info->fbo_ops.glFramebufferTexture)
143  {
144  FIXME("OpenGL implementation doesn't support glFramebufferTexture().\n");
145  return;
146  }
147 
148  gl_info->fbo_ops.glFramebufferTexture(fbo_target, attachment,
149  resource->object, resource->level);
150  }
151  else if (resource->target == GL_TEXTURE_1D_ARRAY || resource->target == GL_TEXTURE_2D_ARRAY
152  || resource->target == GL_TEXTURE_3D)
153  {
154  if (!gl_info->fbo_ops.glFramebufferTextureLayer)
155  {
156  FIXME("OpenGL implementation doesn't support glFramebufferTextureLayer().\n");
157  return;
158  }
159 
160  gl_info->fbo_ops.glFramebufferTextureLayer(fbo_target, attachment,
161  resource->object, resource->level, resource->layer);
162  }
163  else if (resource->target == GL_TEXTURE_1D)
164  {
165  gl_info->fbo_ops.glFramebufferTexture1D(fbo_target, attachment,
166  resource->target, resource->object, resource->level);
167  }
168  else
169  {
170  gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, attachment,
171  resource->target, resource->object, resource->level);
172  }
173  checkGLcall("attach texture to fbo");
174 }
175 
176 /* Context activation is done by the caller. */
178  GLenum fbo_target, const struct wined3d_fbo_resource *resource, BOOL rb_namespace,
179  DWORD flags)
180 {
181  const struct wined3d_gl_info *gl_info = context->gl_info;
182 
183  if (resource->object)
184  {
185  TRACE("Attach depth stencil %u.\n", resource->object);
186 
187  if (rb_namespace)
188  {
189  context_attach_depth_stencil_rb(gl_info, fbo_target,
190  flags, resource->object);
191  }
192  else
193  {
194  if (flags & WINED3D_FBO_ENTRY_FLAG_DEPTH)
195  context_attach_gl_texture_fbo(context, fbo_target, GL_DEPTH_ATTACHMENT, resource);
196 
197  if (flags & WINED3D_FBO_ENTRY_FLAG_STENCIL)
198  context_attach_gl_texture_fbo(context, fbo_target, GL_STENCIL_ATTACHMENT, resource);
199  }
200 
201  if (!(flags & WINED3D_FBO_ENTRY_FLAG_DEPTH))
203 
204  if (!(flags & WINED3D_FBO_ENTRY_FLAG_STENCIL))
206  }
207  else
208  {
209  TRACE("Attach depth stencil 0.\n");
210 
213  }
214 }
215 
216 /* Context activation is done by the caller. */
218  GLenum fbo_target, DWORD idx, const struct wined3d_fbo_resource *resource, BOOL rb_namespace)
219 {
220  const struct wined3d_gl_info *gl_info = context->gl_info;
221 
222  TRACE("Attach GL object %u to %u.\n", resource->object, idx);
223 
224  if (resource->object)
225  {
226  if (rb_namespace)
227  {
228  gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
229  GL_RENDERBUFFER, resource->object);
230  checkGLcall("glFramebufferRenderbuffer()");
231  }
232  else
233  {
234  context_attach_gl_texture_fbo(context, fbo_target, GL_COLOR_ATTACHMENT0 + idx, resource);
235  }
236  }
237  else
238  {
239  context_attach_gl_texture_fbo(context, fbo_target, GL_COLOR_ATTACHMENT0 + idx, NULL);
240  }
241 }
242 
243 static void context_dump_fbo_attachment(const struct wined3d_gl_info *gl_info, GLenum target,
245 {
246  static const struct
247  {
248  GLenum target;
249  GLenum binding;
250  const char *str;
252  }
253  texture_type[] =
254  {
257  {GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D, "2d", WINED3D_GL_EXT_NONE},
259  {GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BINDING_2D_ARRAY, "2d-array" , EXT_TEXTURE_ARRAY},
262  {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, "2d-array-ms", ARB_TEXTURE_MULTISAMPLE},
263  };
264 
265  GLint type, name, samples, width, height, old_texture, level, face, fmt, tex_target;
266  const char *tex_type_str;
267  unsigned int i;
268 
269  gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
271  gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
273 
274  if (type == GL_RENDERBUFFER)
275  {
276  gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, name);
277  gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
278  gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
279  if (gl_info->limits.samples > 1)
280  gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
281  else
282  samples = 1;
283  gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_INTERNAL_FORMAT, &fmt);
284  FIXME(" %s: renderbuffer %d, %dx%d, %d samples, format %#x.\n",
285  debug_fboattachment(attachment), name, width, height, samples, fmt);
286  }
287  else if (type == GL_TEXTURE)
288  {
289  gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
291  gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
293 
294  if (gl_info->gl_ops.ext.p_glGetTextureParameteriv)
295  {
296  GL_EXTCALL(glGetTextureParameteriv(name, GL_TEXTURE_TARGET, &tex_target));
297 
298  for (i = 0; i < ARRAY_SIZE(texture_type); ++i)
299  {
300  if (texture_type[i].target == tex_target)
301  {
302  tex_type_str = texture_type[i].str;
303  break;
304  }
305  }
306  if (i == ARRAY_SIZE(texture_type))
307  tex_type_str = wine_dbg_sprintf("%#x", tex_target);
308  }
309  else if (face)
310  {
311  gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &old_texture);
312  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, name);
313 
314  tex_target = GL_TEXTURE_CUBE_MAP;
315  tex_type_str = "cube";
316  }
317  else
318  {
319  tex_type_str = NULL;
320 
321  for (i = 0; i < ARRAY_SIZE(texture_type); ++i)
322  {
323  if (!gl_info->supported[texture_type[i].extension])
324  continue;
325 
326  gl_info->gl_ops.gl.p_glGetIntegerv(texture_type[i].binding, &old_texture);
327  while (gl_info->gl_ops.gl.p_glGetError());
328 
329  gl_info->gl_ops.gl.p_glBindTexture(texture_type[i].target, name);
330  if (!gl_info->gl_ops.gl.p_glGetError())
331  {
332  tex_target = texture_type[i].target;
333  tex_type_str = texture_type[i].str;
334  break;
335  }
336  gl_info->gl_ops.gl.p_glBindTexture(texture_type[i].target, old_texture);
337  }
338 
339  if (!tex_type_str)
340  {
341  FIXME("Cannot find type of texture %d.\n", name);
342  return;
343  }
344  }
345 
346  if (gl_info->gl_ops.ext.p_glGetTextureParameteriv)
347  {
348  GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_INTERNAL_FORMAT, &fmt));
349  GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_WIDTH, &width));
350  GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_HEIGHT, &height));
351  GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_SAMPLES, &samples));
352  }
353  else
354  {
355  gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_INTERNAL_FORMAT, &fmt);
356  gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_WIDTH, &width);
357  gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_HEIGHT, &height);
358  if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
359  gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_SAMPLES, &samples);
360  else
361  samples = 1;
362 
363  gl_info->gl_ops.gl.p_glBindTexture(tex_target, old_texture);
364  }
365 
366  FIXME(" %s: %s texture %d, %dx%d, %d samples, format %#x.\n",
367  debug_fboattachment(attachment), tex_type_str, name, width, height, samples, fmt);
368  }
369  else if (type == GL_NONE)
370  {
371  FIXME(" %s: NONE.\n", debug_fboattachment(attachment));
372  }
373  else
374  {
375  ERR(" %s: Unknown attachment %#x.\n", debug_fboattachment(attachment), type);
376  }
377 
378  checkGLcall("dump FBO attachment");
379 }
380 
381 /* Context activation is done by the caller. */
383 {
384  const struct wined3d_gl_info *gl_info = context->gl_info;
385  GLenum status;
386 
387  if (!FIXME_ON(d3d))
388  return;
389 
390  status = gl_info->fbo_ops.glCheckFramebufferStatus(target);
391  if (status == GL_FRAMEBUFFER_COMPLETE)
392  {
393  TRACE("FBO complete.\n");
394  }
395  else
396  {
397  unsigned int i;
398 
399  FIXME("FBO status %s (%#x).\n", debug_fbostatus(status), status);
400 
401  if (!context->current_fbo)
402  {
403  ERR("FBO 0 is incomplete, driver bug?\n");
404  return;
405  }
406 
409 
410  for (i = 0; i < gl_info->limits.buffers; ++i)
412  }
413 }
414 
416 {
417  /* Should take care of all the GL_FRONT/GL_BACK/GL_AUXi/GL_NONE... cases */
418  return buffer ? (1u << 31) | buffer : 0;
419 }
420 
422 {
423  if (resource->type != WINED3D_RTYPE_TEXTURE_2D)
424  {
425  FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
426  return 0;
427  }
428 
429  return (1u << 31) | wined3d_texture_get_gl_buffer(texture_from_resource(resource));
430 }
431 
433  struct wined3d_fbo_entry_key *key, unsigned int idx, const struct wined3d_rendertarget_info *render_target,
434  DWORD location)
435 {
436  unsigned int sub_resource_idx = render_target->sub_resource_idx;
437  struct wined3d_resource *resource = render_target->resource;
438  struct wined3d_texture *texture;
439 
440  if (!resource || resource->format->id == WINED3DFMT_NULL || resource->type == WINED3D_RTYPE_BUFFER)
441  {
442  if (resource && resource->type == WINED3D_RTYPE_BUFFER)
443  FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
444  key->objects[idx].object = 0;
445  key->objects[idx].target = 0;
446  key->objects[idx].level = key->objects[idx].layer = 0;
447  return;
448  }
449 
450  if (render_target->gl_view.name)
451  {
452  key->objects[idx].object = render_target->gl_view.name;
453  key->objects[idx].target = render_target->gl_view.target;
454  key->objects[idx].level = 0;
455  key->objects[idx].layer = WINED3D_ALL_LAYERS;
456  return;
457  }
458 
459  texture = wined3d_texture_from_resource(resource);
460  if (texture->current_renderbuffer)
461  {
462  key->objects[idx].object = texture->current_renderbuffer->id;
463  key->objects[idx].target = 0;
464  key->objects[idx].level = key->objects[idx].layer = 0;
465  key->rb_namespace |= 1 << idx;
466  return;
467  }
468 
469  key->objects[idx].target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx);
470  key->objects[idx].level = sub_resource_idx % texture->level_count;
471  key->objects[idx].layer = sub_resource_idx / texture->level_count;
472 
473  if (render_target->layer_count != 1)
474  key->objects[idx].layer = WINED3D_ALL_LAYERS;
475 
476  switch (location)
477  {
479  key->objects[idx].object = wined3d_texture_get_texture_name(texture, context, FALSE);
480  break;
481 
483  key->objects[idx].object = wined3d_texture_get_texture_name(texture, context, TRUE);
484  break;
485 
487  key->objects[idx].object = texture->rb_multisample;
488  key->objects[idx].target = 0;
489  key->objects[idx].level = key->objects[idx].layer = 0;
490  key->rb_namespace |= 1 << idx;
491  break;
492 
494  key->objects[idx].object = texture->rb_resolved;
495  key->objects[idx].target = 0;
496  key->objects[idx].level = key->objects[idx].layer = 0;
497  key->rb_namespace |= 1 << idx;
498  break;
499  }
500 }
501 
503  struct wined3d_fbo_entry_key *key, const struct wined3d_rendertarget_info *render_targets,
504  const struct wined3d_rendertarget_info *depth_stencil, DWORD color_location, DWORD ds_location)
505 {
506  unsigned int buffers = context->gl_info->limits.buffers;
507  unsigned int i;
508 
509  key->rb_namespace = 0;
510  context_set_fbo_key_for_render_target(context, key, 0, depth_stencil, ds_location);
511 
512  for (i = 0; i < buffers; ++i)
513  context_set_fbo_key_for_render_target(context, key, i + 1, &render_targets[i], color_location);
514 
515  memset(&key->objects[buffers + 1], 0, (ARRAY_SIZE(key->objects) - buffers - 1) * sizeof(*key->objects));
516 }
517 
519  const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
520  DWORD color_location, DWORD ds_location)
521 {
522  const struct wined3d_gl_info *gl_info = context->gl_info;
523  struct fbo_entry *entry;
524 
525  entry = heap_alloc(sizeof(*entry));
526  context_generate_fbo_key(context, &entry->key, render_targets, depth_stencil, color_location, ds_location);
527  entry->flags = 0;
528  if (depth_stencil->resource)
529  {
530  if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_DEPTH)
532  if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_STENCIL)
534  }
536  gl_info->fbo_ops.glGenFramebuffers(1, &entry->id);
537  checkGLcall("glGenFramebuffers()");
538  TRACE("Created FBO %u.\n", entry->id);
539 
540  return entry;
541 }
542 
543 /* Context activation is done by the caller. */
545  const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
546  DWORD color_location, DWORD ds_location, struct fbo_entry *entry)
547 {
548  const struct wined3d_gl_info *gl_info = context->gl_info;
549 
550  context_bind_fbo(context, target, entry->id);
551  context_clean_fbo_attachments(gl_info, target);
552 
553  context_generate_fbo_key(context, &entry->key, render_targets, depth_stencil, color_location, ds_location);
554  entry->flags = 0;
555  if (depth_stencil->resource)
556  {
557  if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_DEPTH)
559  if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_STENCIL)
561  }
562 }
563 
564 /* Context activation is done by the caller. */
566 {
567  if (entry->id)
568  {
569  TRACE("Destroy FBO %u.\n", entry->id);
570  context_destroy_fbo(context, entry->id);
571  }
572  --context->fbo_entry_count;
573  list_remove(&entry->entry);
574  heap_free(entry);
575 }
576 
577 /* Context activation is done by the caller. */
579  const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
580  DWORD color_location, DWORD ds_location)
581 {
582  static const struct wined3d_rendertarget_info ds_null = {{0}};
583  const struct wined3d_gl_info *gl_info = context->gl_info;
584  struct wined3d_texture *rt_texture, *ds_texture;
585  struct wined3d_fbo_entry_key fbo_key;
586  unsigned int i, ds_level, rt_level;
587  struct fbo_entry *entry;
588 
589  if (depth_stencil->resource && depth_stencil->resource->type != WINED3D_RTYPE_BUFFER
590  && render_targets[0].resource && render_targets[0].resource->type != WINED3D_RTYPE_BUFFER)
591  {
592  rt_texture = wined3d_texture_from_resource(render_targets[0].resource);
593  rt_level = render_targets[0].sub_resource_idx % rt_texture->level_count;
594  ds_texture = wined3d_texture_from_resource(depth_stencil->resource);
595  ds_level = depth_stencil->sub_resource_idx % ds_texture->level_count;
596 
597  if (wined3d_texture_get_level_width(ds_texture, ds_level)
598  < wined3d_texture_get_level_width(rt_texture, rt_level)
599  || wined3d_texture_get_level_height(ds_texture, ds_level)
600  < wined3d_texture_get_level_height(rt_texture, rt_level))
601  {
602  WARN("Depth stencil is smaller than the primary color buffer, disabling.\n");
603  depth_stencil = &ds_null;
604  }
605  else if (ds_texture->resource.multisample_type != rt_texture->resource.multisample_type
606  || ds_texture->resource.multisample_quality != rt_texture->resource.multisample_quality)
607  {
608  WARN("Color multisample type %u and quality %u, depth stencil has %u and %u, disabling ds buffer.\n",
609  rt_texture->resource.multisample_type, rt_texture->resource.multisample_quality,
610  ds_texture->resource.multisample_type, ds_texture->resource.multisample_quality);
611  depth_stencil = &ds_null;
612  }
613  else if (depth_stencil->resource->type == WINED3D_RTYPE_TEXTURE_2D)
614  {
615  wined3d_texture_set_compatible_renderbuffer(ds_texture, ds_level, &render_targets[0]);
616  }
617  }
618 
619  context_generate_fbo_key(context, &fbo_key, render_targets, depth_stencil, color_location, ds_location);
620 
621  if (TRACE_ON(d3d))
622  {
623  struct wined3d_resource *resource;
624  unsigned int width, height;
625  const char *resource_type;
626 
627  TRACE("Dumping FBO attachments:\n");
628  for (i = 0; i < gl_info->limits.buffers; ++i)
629  {
630  if ((resource = render_targets[i].resource))
631  {
632  if (resource->type == WINED3D_RTYPE_BUFFER)
633  {
634  width = resource->size;
635  height = 1;
636  resource_type = "buffer";
637  }
638  else
639  {
640  rt_texture = wined3d_texture_from_resource(resource);
641  rt_level = render_targets[i].sub_resource_idx % rt_texture->level_count;
642  width = wined3d_texture_get_level_pow2_width(rt_texture, rt_level);
643  height = wined3d_texture_get_level_pow2_height(rt_texture, rt_level);
644  resource_type = "texture";
645  }
646 
647  TRACE(" Color attachment %u: %p, %u format %s, %s %u, %ux%u, %u samples.\n",
648  i, resource, render_targets[i].sub_resource_idx, debug_d3dformat(resource->format->id),
649  fbo_key.rb_namespace & (1 << (i + 1)) ? "renderbuffer" : resource_type,
650  fbo_key.objects[i + 1].object, width, height, resource->multisample_type);
651  }
652  }
653  if ((resource = depth_stencil->resource))
654  {
655  if (resource->type == WINED3D_RTYPE_BUFFER)
656  {
657  width = resource->size;
658  height = 1;
659  resource_type = "buffer";
660  }
661  else
662  {
663  ds_texture = wined3d_texture_from_resource(resource);
664  ds_level = depth_stencil->sub_resource_idx % ds_texture->level_count;
665  width = wined3d_texture_get_level_pow2_width(ds_texture, ds_level);
666  height = wined3d_texture_get_level_pow2_height(ds_texture, ds_level);
667  resource_type = "texture";
668  }
669 
670  TRACE(" Depth attachment: %p, %u format %s, %s %u, %ux%u, %u samples.\n",
671  resource, depth_stencil->sub_resource_idx, debug_d3dformat(resource->format->id),
672  fbo_key.rb_namespace & (1 << 0) ? "renderbuffer" : resource_type,
673  fbo_key.objects[0].object, width, height, resource->multisample_type);
674  }
675  }
676 
677  LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
678  {
679  if (memcmp(&fbo_key, &entry->key, sizeof(fbo_key)))
680  continue;
681 
682  list_remove(&entry->entry);
683  list_add_head(&context->fbo_list, &entry->entry);
684  return entry;
685  }
686 
688  {
689  entry = context_create_fbo_entry(context, render_targets, depth_stencil, color_location, ds_location);
690  list_add_head(&context->fbo_list, &entry->entry);
691  ++context->fbo_entry_count;
692  }
693  else
694  {
695  entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry);
696  context_reuse_fbo_entry(context, target, render_targets, depth_stencil, color_location, ds_location, entry);
697  list_remove(&entry->entry);
698  list_add_head(&context->fbo_list, &entry->entry);
699  }
700 
701  return entry;
702 }
703 
704 /* Context activation is done by the caller. */
706 {
707  const struct wined3d_gl_info *gl_info = context->gl_info;
708  GLuint read_binding, draw_binding;
709  unsigned int i;
710 
712  {
713  context_bind_fbo(context, target, entry->id);
714  return;
715  }
716 
717  read_binding = context->fbo_read_binding;
718  draw_binding = context->fbo_draw_binding;
719  context_bind_fbo(context, GL_FRAMEBUFFER, entry->id);
720 
722  {
723  GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER,
724  GL_FRAMEBUFFER_DEFAULT_WIDTH, gl_info->limits.framebuffer_width));
725  GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER,
726  GL_FRAMEBUFFER_DEFAULT_HEIGHT, gl_info->limits.framebuffer_height));
727  GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, 1));
728  GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, 1));
729  }
730 
731  /* Apply render targets */
732  for (i = 0; i < gl_info->limits.buffers; ++i)
733  {
734  context_attach_surface_fbo(context, target, i, &entry->key.objects[i + 1],
735  entry->key.rb_namespace & (1 << (i + 1)));
736  }
737 
738  context_attach_depth_stencil_fbo(context, target, &entry->key.objects[0],
739  entry->key.rb_namespace & 0x1, entry->flags);
740 
741  /* Set valid read and draw buffer bindings to satisfy pedantic pre-ES2_compatibility
742  * GL contexts requirements. */
743  gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
745  if (target != GL_FRAMEBUFFER)
746  {
747  if (target == GL_READ_FRAMEBUFFER)
748  context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, draw_binding);
749  else
750  context_bind_fbo(context, GL_READ_FRAMEBUFFER, read_binding);
751  }
752 
754 }
755 
756 /* Context activation is done by the caller. */
758  const struct wined3d_rendertarget_info *render_targets,
759  const struct wined3d_rendertarget_info *depth_stencil, DWORD color_location, DWORD ds_location)
760 {
761  struct fbo_entry *entry, *entry2;
762 
763  LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
764  {
765  context_destroy_fbo_entry(context, entry);
766  }
767 
768  if (context->rebind_fbo)
769  {
770  context_bind_fbo(context, GL_FRAMEBUFFER, 0);
771  context->rebind_fbo = FALSE;
772  }
773 
774  if (color_location == WINED3D_LOCATION_DRAWABLE)
775  {
776  context->current_fbo = NULL;
777  context_bind_fbo(context, target, 0);
778  }
779  else
780  {
781  context->current_fbo = context_find_fbo_entry(context, target,
782  render_targets, depth_stencil, color_location, ds_location);
783  context_apply_fbo_entry(context, target, context->current_fbo);
784  }
785 }
786 
787 /* Context activation is done by the caller. */
789  struct wined3d_resource *rt, unsigned int rt_sub_resource_idx,
790  struct wined3d_resource *ds, unsigned int ds_sub_resource_idx, DWORD location)
791 {
792  struct wined3d_rendertarget_info ds_info = {{0}};
793 
794  memset(context->blit_targets, 0, sizeof(context->blit_targets));
795  if (rt)
796  {
797  context->blit_targets[0].resource = rt;
798  context->blit_targets[0].sub_resource_idx = rt_sub_resource_idx;
799  context->blit_targets[0].layer_count = 1;
800  }
801 
802  if (ds)
803  {
804  ds_info.resource = ds;
805  ds_info.sub_resource_idx = ds_sub_resource_idx;
806  ds_info.layer_count = 1;
807  }
808 
809  context_apply_fbo_state(context, target, context->blit_targets, &ds_info, location, location);
810 }
811 
812 /* Context activation is done by the caller. */
814 {
815  const struct wined3d_gl_info *gl_info = context->gl_info;
816 
817  if (context->free_occlusion_query_count)
818  {
819  query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
820  }
821  else
822  {
823  if (gl_info->supported[ARB_OCCLUSION_QUERY])
824  {
825  GL_EXTCALL(glGenQueries(1, &query->id));
826  checkGLcall("glGenQueries");
827 
828  TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
829  }
830  else
831  {
832  WARN("Occlusion queries not supported, not allocating query id.\n");
833  query->id = 0;
834  }
835  }
836 
837  query->context = context;
838  list_add_head(&context->occlusion_queries, &query->entry);
839 }
840 
842 {
843  struct wined3d_context *context = query->context;
844 
845  list_remove(&query->entry);
846  query->context = NULL;
847 
848  if (!wined3d_array_reserve((void **)&context->free_occlusion_queries,
850  sizeof(*context->free_occlusion_queries)))
851  {
852  ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
853  return;
854  }
855 
856  context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
857 }
858 
859 /* Context activation is done by the caller. */
861 {
862  const struct wined3d_gl_info *gl_info = context->gl_info;
863 
864  if (context->free_fence_count)
865  {
866  fence->object = context->free_fences[--context->free_fence_count];
867  }
868  else
869  {
870  if (gl_info->supported[ARB_SYNC])
871  {
872  /* Using ARB_sync, not much to do here. */
873  fence->object.sync = NULL;
874  TRACE("Allocated sync object in context %p.\n", context);
875  }
876  else if (gl_info->supported[APPLE_FENCE])
877  {
878  GL_EXTCALL(glGenFencesAPPLE(1, &fence->object.id));
879  checkGLcall("glGenFencesAPPLE");
880 
881  TRACE("Allocated fence %u in context %p.\n", fence->object.id, context);
882  }
883  else if(gl_info->supported[NV_FENCE])
884  {
885  GL_EXTCALL(glGenFencesNV(1, &fence->object.id));
886  checkGLcall("glGenFencesNV");
887 
888  TRACE("Allocated fence %u in context %p.\n", fence->object.id, context);
889  }
890  else
891  {
892  WARN("Fences not supported, not allocating fence.\n");
893  fence->object.id = 0;
894  }
895  }
896 
897  fence->context = context;
898  list_add_head(&context->fences, &fence->entry);
899 }
900 
902 {
903  struct wined3d_context *context = fence->context;
904 
905  list_remove(&fence->entry);
906  fence->context = NULL;
907 
908  if (!wined3d_array_reserve((void **)&context->free_fences,
909  &context->free_fence_size, context->free_fence_count + 1,
910  sizeof(*context->free_fences)))
911  {
912  ERR("Failed to grow free list, leaking fence %u in context %p.\n", fence->object.id, context);
913  return;
914  }
915 
916  context->free_fences[context->free_fence_count++] = fence->object;
917 }
918 
919 /* Context activation is done by the caller. */
921 {
922  const struct wined3d_gl_info *gl_info = context->gl_info;
923 
924  if (context->free_timestamp_query_count)
925  {
926  query->id = context->free_timestamp_queries[--context->free_timestamp_query_count];
927  }
928  else
929  {
930  GL_EXTCALL(glGenQueries(1, &query->id));
931  checkGLcall("glGenQueries");
932 
933  TRACE("Allocated timestamp query %u in context %p.\n", query->id, context);
934  }
935 
936  query->context = context;
937  list_add_head(&context->timestamp_queries, &query->entry);
938 }
939 
941 {
942  struct wined3d_context *context = query->context;
943 
944  list_remove(&query->entry);
945  query->context = NULL;
946 
947  if (!wined3d_array_reserve((void **)&context->free_timestamp_queries,
949  sizeof(*context->free_timestamp_queries)))
950  {
951  ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
952  return;
953  }
954 
955  context->free_timestamp_queries[context->free_timestamp_query_count++] = query->id;
956 }
957 
960 {
961  const struct wined3d_gl_info *gl_info = context->gl_info;
962 
963  if (context->free_so_statistics_query_count)
964  {
965  query->u = context->free_so_statistics_queries[--context->free_so_statistics_query_count];
966  }
967  else
968  {
969  GL_EXTCALL(glGenQueries(ARRAY_SIZE(query->u.id), query->u.id));
970  checkGLcall("glGenQueries");
971 
972  TRACE("Allocated SO statistics queries %u, %u in context %p.\n",
973  query->u.id[0], query->u.id[1], context);
974  }
975 
976  query->context = context;
977  list_add_head(&context->so_statistics_queries, &query->entry);
978 }
979 
981 {
982  struct wined3d_context *context = query->context;
983 
984  list_remove(&query->entry);
985  query->context = NULL;
986 
987  if (!wined3d_array_reserve((void **)&context->free_so_statistics_queries,
989  sizeof(*context->free_so_statistics_queries)))
990  {
991  ERR("Failed to grow free list, leaking GL queries %u, %u in context %p.\n",
992  query->u.id[0], query->u.id[1], context);
993  return;
994  }
995 
996  context->free_so_statistics_queries[context->free_so_statistics_query_count++] = query->u;
997 }
998 
1001 {
1002  const struct wined3d_gl_info *gl_info = context->gl_info;
1003 
1005  {
1007  }
1008  else
1009  {
1010  GL_EXTCALL(glGenQueries(ARRAY_SIZE(query->u.id), query->u.id));
1011  checkGLcall("glGenQueries");
1012  }
1013 
1014  query->context = context;
1015  list_add_head(&context->pipeline_statistics_queries, &query->entry);
1016 }
1017 
1019 {
1020  struct wined3d_context *context = query->context;
1021 
1022  list_remove(&query->entry);
1023  query->context = NULL;
1024 
1027  sizeof(*context->free_pipeline_statistics_queries)))
1028  {
1029  ERR("Failed to grow free list, leaking GL queries in context %p.\n", context);
1030  return;
1031  }
1032 
1034 }
1035 
1037 
1040 {
1041  unsigned int i, j;
1042 
1043  for (i = 0; i < device->context_count; ++i)
1044  {
1045  struct wined3d_context *context = device->contexts[i];
1046  const struct wined3d_gl_info *gl_info = context->gl_info;
1047  struct fbo_entry *entry, *entry2;
1048 
1049  LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
1050  {
1051  for (j = 0; j < gl_info->limits.buffers + 1; ++j)
1052  {
1053  if (entry->key.objects[j].object == name
1054  && !(entry->key.rb_namespace & (1 << j)) == !rb_namespace)
1055  {
1056  callback(context, entry);
1057  break;
1058  }
1059  }
1060  }
1061  }
1062 }
1063 
1065 {
1066  list_remove(&entry->entry);
1067  list_add_head(&context->fbo_destroy_list, &entry->entry);
1068 }
1069 
1071 {
1072  unsigned int i;
1073 
1074  if (!device->d3d_initialized)
1075  return;
1076 
1077  for (i = 0; i < device->context_count; ++i)
1078  {
1079  struct wined3d_context *context = device->contexts[i];
1080 
1081  if (&context->current_rt.texture->resource == resource)
1082  {
1083  context->current_rt.texture = NULL;
1084  context->current_rt.sub_resource_idx = 0;
1085  }
1086  }
1087 }
1088 
1090  GLuint name, BOOL rb_namespace)
1091 {
1093 }
1094 
1096 {
1097  const struct wined3d_gl_info *gl_info = context->gl_info;
1098  struct fbo_entry *entry = context->current_fbo;
1099  unsigned int i;
1100 
1101  if (!entry || context->rebind_fbo) return;
1102 
1103  for (i = 0; i < gl_info->limits.buffers + 1; ++i)
1104  {
1105  if (texture->texture_rgb.name == entry->key.objects[i].object
1106  || texture->texture_srgb.name == entry->key.objects[i].object)
1107  {
1108  TRACE("Updated texture %p is bound as attachment %u to the current FBO.\n", texture, i);
1109  context->rebind_fbo = TRUE;
1110  return;
1111  }
1112  }
1113 }
1114 
1116 {
1117  const struct wined3d_gl_info *gl_info = ctx->gl_info;
1118  BOOL ret = FALSE;
1119 
1120  if (ctx->restore_pf && IsWindow(ctx->restore_pf_win))
1121  {
1122  if (ctx->gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
1123  {
1125  if (dc)
1126  {
1127  if (!(ret = GL_EXTCALL(wglSetPixelFormatWINE(dc, ctx->restore_pf))))
1128  {
1129  ERR("wglSetPixelFormatWINE failed to restore pixel format %d on window %p.\n",
1130  ctx->restore_pf, ctx->restore_pf_win);
1131  }
1132  ReleaseDC(ctx->restore_pf_win, dc);
1133  }
1134  }
1135  else
1136  {
1137  ERR("can't restore pixel format %d on window %p\n", ctx->restore_pf, ctx->restore_pf_win);
1138  }
1139  }
1140 
1141  ctx->restore_pf = 0;
1142  ctx->restore_pf_win = NULL;
1143  return ret;
1144 }
1145 
1147 {
1148  const struct wined3d_gl_info *gl_info = context->gl_info;
1149  BOOL private = context->hdc_is_private;
1150  int format = context->pixel_format;
1151  HDC dc = context->hdc;
1152  int current;
1153 
1154  if (private && context->hdc_has_format)
1155  return TRUE;
1156 
1157  if (!private && WindowFromDC(dc) != context->win_handle)
1158  return FALSE;
1159 
1160  current = gl_info->gl_ops.wgl.p_wglGetPixelFormat(dc);
1161  if (current == format) goto success;
1162 
1163  if (!current)
1164  {
1165  if (!SetPixelFormat(dc, format, NULL))
1166  {
1167  /* This may also happen if the dc belongs to a destroyed window. */
1168  WARN("Failed to set pixel format %d on device context %p, last error %#x.\n",
1169  format, dc, GetLastError());
1170  return FALSE;
1171  }
1172 
1173  context->restore_pf = 0;
1174  context->restore_pf_win = private ? NULL : WindowFromDC(dc);
1175  goto success;
1176  }
1177 
1178  /* By default WGL doesn't allow pixel format adjustments but we need it
1179  * here. For this reason there's a Wine specific wglSetPixelFormat()
1180  * which allows us to set the pixel format multiple times. Only use it
1181  * when really needed. */
1183  {
1184  HWND win;
1185 
1186  if (!GL_EXTCALL(wglSetPixelFormatWINE(dc, format)))
1187  {
1188  ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
1189  format, dc);
1190  return FALSE;
1191  }
1192 
1193  win = private ? NULL : WindowFromDC(dc);
1194  if (win != context->restore_pf_win)
1195  {
1197 
1198  context->restore_pf = private ? 0 : current;
1199  context->restore_pf_win = win;
1200  }
1201 
1202  goto success;
1203  }
1204 
1205  /* OpenGL doesn't allow pixel format adjustments. Print an error and
1206  * continue using the old format. There's a big chance that the old
1207  * format works although with a performance hit and perhaps rendering
1208  * errors. */
1209  ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
1210  format, dc, current);
1211  return TRUE;
1212 
1213 success:
1214  if (private)
1215  context->hdc_has_format = TRUE;
1216  return TRUE;
1217 }
1218 
1220 {
1221  struct wined3d_swapchain *swapchain = ctx->swapchain;
1222  BOOL backup = FALSE;
1223 
1224  if (!context_set_pixel_format(ctx))
1225  {
1226  WARN("Failed to set pixel format %d on device context %p.\n",
1227  ctx->pixel_format, ctx->hdc);
1228  backup = TRUE;
1229  }
1230 
1231  if (backup || !wglMakeCurrent(ctx->hdc, ctx->glCtx))
1232  {
1233  WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
1234  ctx->glCtx, ctx->hdc, GetLastError());
1235  ctx->valid = 0;
1236  WARN("Trying fallback to the backup window.\n");
1237 
1238  /* FIXME: If the context is destroyed it's no longer associated with
1239  * a swapchain, so we can't use the swapchain to get a backup dc. To
1240  * make this work windowless contexts would need to be handled by the
1241  * device. */
1242  if (ctx->destroyed || !swapchain)
1243  {
1244  FIXME("Unable to get backup dc for destroyed context %p.\n", ctx);
1246  return FALSE;
1247  }
1248 
1249  if (!(ctx->hdc = swapchain_get_backup_dc(swapchain)))
1250  {
1252  return FALSE;
1253  }
1254 
1255  ctx->hdc_is_private = TRUE;
1256  ctx->hdc_has_format = FALSE;
1257 
1258  if (!context_set_pixel_format(ctx))
1259  {
1260  ERR("Failed to set pixel format %d on device context %p.\n",
1261  ctx->pixel_format, ctx->hdc);
1263  return FALSE;
1264  }
1265 
1266  if (!wglMakeCurrent(ctx->hdc, ctx->glCtx))
1267  {
1268  ERR("Fallback to backup window (dc %p) failed too, last error %#x.\n",
1269  ctx->hdc, GetLastError());
1271  return FALSE;
1272  }
1273 
1274  ctx->valid = 1;
1275  }
1276  ctx->needs_set = 0;
1277  return TRUE;
1278 }
1279 
1280 static void context_restore_gl_context(const struct wined3d_gl_info *gl_info, HDC dc, HGLRC gl_ctx)
1281 {
1282  if (!wglMakeCurrent(dc, gl_ctx))
1283  {
1284  ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
1285  gl_ctx, dc, GetLastError());
1287  }
1288 }
1289 
1290 static void context_update_window(struct wined3d_context *context)
1291 {
1292  if (!context->swapchain)
1293  return;
1294 
1295  if (context->win_handle == context->swapchain->win_handle)
1296  return;
1297 
1298  TRACE("Updating context %p window from %p to %p.\n",
1299  context, context->win_handle, context->swapchain->win_handle);
1300 
1301  if (context->hdc)
1302  wined3d_release_dc(context->win_handle, context->hdc);
1303 
1304  context->win_handle = context->swapchain->win_handle;
1305  context->hdc_is_private = FALSE;
1306  context->hdc_has_format = FALSE;
1307  context->needs_set = 1;
1308  context->valid = 1;
1309 
1310  if (!(context->hdc = GetDCEx(context->win_handle, 0, DCX_USESTYLE | DCX_CACHE)))
1311  {
1312  ERR("Failed to get a device context for window %p.\n", context->win_handle);
1313  context->valid = 0;
1314  }
1315 }
1316 
1317 static void context_destroy_gl_resources(struct wined3d_context *context)
1318 {
1319  struct wined3d_pipeline_statistics_query *pipeline_statistics_query;
1320  const struct wined3d_gl_info *gl_info = context->gl_info;
1321  struct wined3d_so_statistics_query *so_statistics_query;
1322  struct wined3d_timestamp_query *timestamp_query;
1323  struct wined3d_occlusion_query *occlusion_query;
1324  struct fbo_entry *entry, *entry2;
1325  struct wined3d_fence *fence;
1326  HGLRC restore_ctx;
1327  HDC restore_dc;
1328  unsigned int i;
1329 
1330  restore_ctx = wglGetCurrentContext();
1331  restore_dc = wglGetCurrentDC();
1332 
1333  if (restore_ctx == context->glCtx)
1334  restore_ctx = NULL;
1335  else if (context->valid)
1336  context_set_gl_context(context);
1337 
1338  LIST_FOR_EACH_ENTRY(so_statistics_query, &context->so_statistics_queries,
1339  struct wined3d_so_statistics_query, entry)
1340  {
1341  if (context->valid)
1342  GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(so_statistics_query->u.id), so_statistics_query->u.id));
1343  so_statistics_query->context = NULL;
1344  }
1345 
1346  LIST_FOR_EACH_ENTRY(pipeline_statistics_query, &context->pipeline_statistics_queries,
1347  struct wined3d_pipeline_statistics_query, entry)
1348  {
1349  if (context->valid)
1350  GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(pipeline_statistics_query->u.id), pipeline_statistics_query->u.id));
1351  pipeline_statistics_query->context = NULL;
1352  }
1353 
1354  LIST_FOR_EACH_ENTRY(timestamp_query, &context->timestamp_queries, struct wined3d_timestamp_query, entry)
1355  {
1356  if (context->valid)
1357  GL_EXTCALL(glDeleteQueries(1, &timestamp_query->id));
1358  timestamp_query->context = NULL;
1359  }
1360 
1361  LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
1362  {
1363  if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY])
1364  GL_EXTCALL(glDeleteQueries(1, &occlusion_query->id));
1365  occlusion_query->context = NULL;
1366  }
1367 
1368  LIST_FOR_EACH_ENTRY(fence, &context->fences, struct wined3d_fence, entry)
1369  {
1370  if (context->valid)
1371  {
1372  if (gl_info->supported[ARB_SYNC])
1373  {
1374  if (fence->object.sync)
1375  GL_EXTCALL(glDeleteSync(fence->object.sync));
1376  }
1377  else if (gl_info->supported[APPLE_FENCE])
1378  {
1379  GL_EXTCALL(glDeleteFencesAPPLE(1, &fence->object.id));
1380  }
1381  else if (gl_info->supported[NV_FENCE])
1382  {
1383  GL_EXTCALL(glDeleteFencesNV(1, &fence->object.id));
1384  }
1385  }
1386  fence->context = NULL;
1387  }
1388 
1389  LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
1390  {
1391  if (!context->valid) entry->id = 0;
1392  context_destroy_fbo_entry(context, entry);
1393  }
1394 
1395  LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
1396  {
1397  if (!context->valid) entry->id = 0;
1398  context_destroy_fbo_entry(context, entry);
1399  }
1400 
1401  if (context->valid)
1402  {
1403  if (context->dummy_arbfp_prog)
1404  {
1405  GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
1406  }
1407 
1408  if (gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1409  {
1410  for (i = 0; i < context->free_so_statistics_query_count; ++i)
1411  {
1413  GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(q->id), q->id));
1414  }
1415  }
1416 
1418  {
1419  for (i = 0; i < context->free_pipeline_statistics_query_count; ++i)
1420  {
1422  GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(q->id), q->id));
1423  }
1424  }
1425 
1426  if (gl_info->supported[ARB_TIMER_QUERY])
1427  GL_EXTCALL(glDeleteQueries(context->free_timestamp_query_count, context->free_timestamp_queries));
1428 
1429  if (gl_info->supported[ARB_OCCLUSION_QUERY])
1430  GL_EXTCALL(glDeleteQueries(context->free_occlusion_query_count, context->free_occlusion_queries));
1431 
1432  if (gl_info->supported[ARB_SYNC])
1433  {
1434  for (i = 0; i < context->free_fence_count; ++i)
1435  {
1436  GL_EXTCALL(glDeleteSync(context->free_fences[i].sync));
1437  }
1438  }
1439  else if (gl_info->supported[APPLE_FENCE])
1440  {
1441  for (i = 0; i < context->free_fence_count; ++i)
1442  {
1443  GL_EXTCALL(glDeleteFencesAPPLE(1, &context->free_fences[i].id));
1444  }
1445  }
1446  else if (gl_info->supported[NV_FENCE])
1447  {
1448  for (i = 0; i < context->free_fence_count; ++i)
1449  {
1450  GL_EXTCALL(glDeleteFencesNV(1, &context->free_fences[i].id));
1451  }
1452  }
1453 
1454  if (context->blit_vbo)
1455  GL_EXTCALL(glDeleteBuffers(1, &context->blit_vbo));
1456 
1457  checkGLcall("context cleanup");
1458  }
1459 
1464  heap_free(context->free_fences);
1465 
1467  if (restore_ctx)
1468  {
1469  context_restore_gl_context(gl_info, restore_dc, restore_ctx);
1470  }
1471  else if (wglGetCurrentContext() && !wglMakeCurrent(NULL, NULL))
1472  {
1473  ERR("Failed to disable GL context.\n");
1474  }
1475 
1476  wined3d_release_dc(context->win_handle, context->hdc);
1477 
1478  if (!wglDeleteContext(context->glCtx))
1479  {
1480  DWORD err = GetLastError();
1481  ERR("wglDeleteContext(%p) failed, last error %#x.\n", context->glCtx, err);
1482  }
1483 }
1484 
1486 {
1487  return wined3d_context_tls_idx;
1488 }
1489 
1491 {
1493 }
1494 
1496 {
1498 }
1499 
1501 {
1502  struct wined3d_context *old = context_get_current();
1503 
1504  if (old == ctx)
1505  {
1506  TRACE("Already using D3D context %p.\n", ctx);
1507  return TRUE;
1508  }
1509 
1510  if (old)
1511  {
1512  if (old->destroyed)
1513  {
1514  TRACE("Switching away from destroyed context %p.\n", old);
1516  heap_free((void *)old->gl_info);
1517  heap_free(old);
1518  }
1519  else
1520  {
1521  if (wglGetCurrentContext())
1522  {
1523  const struct wined3d_gl_info *gl_info = old->gl_info;
1524  TRACE("Flushing context %p before switching to %p.\n", old, ctx);
1525  gl_info->gl_ops.gl.p_glFlush();
1526  }
1527  old->current = 0;
1528  }
1529  }
1530 
1531  if (ctx)
1532  {
1533  if (!ctx->valid)
1534  {
1535  ERR("Trying to make invalid context %p current\n", ctx);
1536  return FALSE;
1537  }
1538 
1539  TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
1540  if (!context_set_gl_context(ctx))
1541  return FALSE;
1542  ctx->current = 1;
1543  }
1544  else if (wglGetCurrentContext())
1545  {
1546  TRACE("Clearing current D3D context.\n");
1547  if (!wglMakeCurrent(NULL, NULL))
1548  {
1549  DWORD err = GetLastError();
1550  ERR("Failed to clear current GL context, last error %#x.\n", err);
1552  return FALSE;
1553  }
1554  }
1555 
1556  return TlsSetValue(wined3d_context_tls_idx, ctx);
1557 }
1558 
1559 void context_release(struct wined3d_context *context)
1560 {
1561  TRACE("Releasing context %p, level %u.\n", context, context->level);
1562 
1563  if (WARN_ON(d3d))
1564  {
1565  if (!context->level)
1566  WARN("Context %p is not active.\n", context);
1567  else if (context != context_get_current())
1568  WARN("Context %p is not the current context.\n", context);
1569  }
1570 
1571  if (!--context->level)
1572  {
1573  if (context_restore_pixel_format(context))
1574  context->needs_set = 1;
1575  if (context->restore_ctx)
1576  {
1577  TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
1578  context_restore_gl_context(context->gl_info, context->restore_dc, context->restore_ctx);
1579  context->restore_ctx = NULL;
1580  context->restore_dc = NULL;
1581  }
1582 
1583  if (context->destroy_delayed)
1584  {
1585  TRACE("Destroying context %p.\n", context);
1586  context_destroy(context->device, context);
1587  }
1588  }
1589 }
1590 
1591 /* This is used when a context for render target A is active, but a separate context is
1592  * needed to access the WGL framebuffer for render target B. Re-acquire a context for rt
1593  * A to avoid breaking caller code. */
1594 void context_restore(struct wined3d_context *context, struct wined3d_texture *texture, unsigned int sub_resource_idx)
1595 {
1596  if (context->current_rt.texture != texture || context->current_rt.sub_resource_idx != sub_resource_idx)
1597  {
1598  context_release(context);
1599  context = context_acquire(texture->resource.device, texture, sub_resource_idx);
1600  }
1601 
1602  context_release(context);
1603 }
1604 
1605 static void context_enter(struct wined3d_context *context)
1606 {
1607  TRACE("Entering context %p, level %u.\n", context, context->level + 1);
1608 
1609  if (!context->level++)
1610  {
1611  const struct wined3d_context *current_context = context_get_current();
1612  HGLRC current_gl = wglGetCurrentContext();
1613 
1614  if (current_gl && (!current_context || current_context->glCtx != current_gl))
1615  {
1616  TRACE("Another GL context (%p on device context %p) is already current.\n",
1617  current_gl, wglGetCurrentDC());
1618  context->restore_ctx = current_gl;
1619  context->restore_dc = wglGetCurrentDC();
1620  context->needs_set = 1;
1621  }
1622  else if (!context->needs_set && !(context->hdc_is_private && context->hdc_has_format)
1623  && context->pixel_format != context->gl_info->gl_ops.wgl.p_wglGetPixelFormat(context->hdc))
1624  context->needs_set = 1;
1625  }
1626 }
1627 
1629 {
1630  DWORD representative = context->state_table[state_id].representative - STATE_COMPUTE_OFFSET;
1631  unsigned int index, shift;
1632 
1633  index = representative / (sizeof(*context->dirty_compute_states) * CHAR_BIT);
1634  shift = representative & (sizeof(*context->dirty_compute_states) * CHAR_BIT - 1);
1635  context->dirty_compute_states[index] |= (1u << shift);
1636 }
1637 
1639 {
1640  DWORD rep = context->state_table[state].representative;
1641  DWORD idx;
1642  BYTE shift;
1643 
1644  if (isStateDirty(context, rep)) return;
1645 
1646  context->dirtyArray[context->numDirtyEntries++] = rep;
1647  idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
1648  shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
1649  context->isStateDirty[idx] |= (1u << shift);
1650 }
1651 
1652 /* This function takes care of wined3d pixel format selection. */
1654  const struct wined3d_format *color_format, const struct wined3d_format *ds_format,
1655  BOOL auxBuffers)
1656 {
1657  unsigned int cfg_count = device->adapter->cfg_count;
1658  unsigned int current_value;
1660  int iPixelFormat = 0;
1661  unsigned int i;
1662 
1663  TRACE("device %p, dc %p, color_format %s, ds_format %s, aux_buffers %#x.\n",
1664  device, hdc, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id),
1665  auxBuffers);
1666 
1667  current_value = 0;
1668  for (i = 0; i < cfg_count; ++i)
1669  {
1670  const struct wined3d_pixel_format *cfg = &device->adapter->cfgs[i];
1671  unsigned int value;
1672 
1673  /* For now only accept RGBA formats. Perhaps some day we will
1674  * allow floating point formats for pbuffers. */
1675  if (cfg->iPixelType != WGL_TYPE_RGBA_ARB)
1676  continue;
1677  /* In window mode we need a window drawable format and double buffering. */
1678  if (!(cfg->windowDrawable && cfg->doubleBuffer))
1679  continue;
1680  if (cfg->redSize < color_format->red_size)
1681  continue;
1682  if (cfg->greenSize < color_format->green_size)
1683  continue;
1684  if (cfg->blueSize < color_format->blue_size)
1685  continue;
1686  if (cfg->alphaSize < color_format->alpha_size)
1687  continue;
1688  if (cfg->depthSize < ds_format->depth_size)
1689  continue;
1690  if (ds_format->stencil_size && cfg->stencilSize != ds_format->stencil_size)
1691  continue;
1692  /* Check multisampling support. */
1693  if (cfg->numSamples)
1694  continue;
1695 
1696  value = 1;
1697  /* We try to locate a format which matches our requirements exactly. In case of
1698  * depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
1699  if (cfg->depthSize == ds_format->depth_size)
1700  value += 1;
1701  if (cfg->stencilSize == ds_format->stencil_size)
1702  value += 2;
1703  if (cfg->alphaSize == color_format->alpha_size)
1704  value += 4;
1705  /* We like to have aux buffers in backbuffer mode */
1706  if (auxBuffers && cfg->auxBuffers)
1707  value += 8;
1708  if (cfg->redSize == color_format->red_size
1709  && cfg->greenSize == color_format->green_size
1710  && cfg->blueSize == color_format->blue_size)
1711  value += 16;
1712 
1713  if (value > current_value)
1714  {
1715  iPixelFormat = cfg->iPixelFormat;
1716  current_value = value;
1717  }
1718  }
1719 
1720  if (!iPixelFormat)
1721  {
1722  ERR("Trying to locate a compatible pixel format because an exact match failed.\n");
1723 
1724  memset(&pfd, 0, sizeof(pfd));
1725  pfd.nSize = sizeof(pfd);
1726  pfd.nVersion = 1;
1727  pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
1728  pfd.iPixelType = PFD_TYPE_RGBA;
1729  pfd.cAlphaBits = color_format->alpha_size;
1730  pfd.cColorBits = color_format->red_size + color_format->green_size
1731  + color_format->blue_size + color_format->alpha_size;
1732  pfd.cDepthBits = ds_format->depth_size;
1733  pfd.cStencilBits = ds_format->stencil_size;
1734  pfd.iLayerType = PFD_MAIN_PLANE;
1735 
1736  if (!(iPixelFormat = ChoosePixelFormat(hdc, &pfd)))
1737  {
1738  /* Something is very wrong as ChoosePixelFormat() barely fails. */
1739  ERR("Can't find a suitable pixel format.\n");
1740  return 0;
1741  }
1742  }
1743 
1744  TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s.\n",
1745  iPixelFormat, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id));
1746  return iPixelFormat;
1747 }
1748 
1749 /* Context activation is done by the caller. */
1750 void context_bind_dummy_textures(const struct wined3d_device *device, const struct wined3d_context *context)
1751 {
1752  const struct wined3d_dummy_textures *textures = &context->device->dummy_textures;
1753  const struct wined3d_gl_info *gl_info = context->gl_info;
1754  unsigned int i;
1755 
1756  for (i = 0; i < gl_info->limits.combined_samplers; ++i)
1757  {
1759 
1760  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, textures->tex_1d);
1761  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, textures->tex_2d);
1762 
1763  if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1764  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textures->tex_rect);
1765 
1766  if (gl_info->supported[EXT_TEXTURE3D])
1767  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, textures->tex_3d);
1768 
1769  if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1770  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, textures->tex_cube);
1771 
1772  if (gl_info->supported[ARB_TEXTURE_CUBE_MAP_ARRAY])
1773  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, textures->tex_cube_array);
1774 
1775  if (gl_info->supported[EXT_TEXTURE_ARRAY])
1776  {
1777  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D_ARRAY, textures->tex_1d_array);
1778  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_ARRAY, textures->tex_2d_array);
1779  }
1780 
1781  if (gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT])
1782  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_BUFFER, textures->tex_buffer);
1783 
1784  if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
1785  {
1786  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textures->tex_2d_ms);
1787  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, textures->tex_2d_ms_array);
1788  }
1789  }
1790 
1791  checkGLcall("bind dummy textures");
1792 }
1793 
1794 void wined3d_check_gl_call(const struct wined3d_gl_info *gl_info,
1795  const char *file, unsigned int line, const char *name)
1796 {
1797  GLint err;
1798 
1799  if (gl_info->supported[ARB_DEBUG_OUTPUT] || (err = gl_info->gl_ops.gl.p_glGetError()) == GL_NO_ERROR)
1800  {
1801  TRACE("%s call ok %s / %u.\n", name, file, line);
1802  return;
1803  }
1804 
1805  do
1806  {
1807  ERR(">>>>>>> %s (%#x) from %s @ %s / %u.\n",
1808  debug_glerror(err), err, name, file,line);
1809  err = gl_info->gl_ops.gl.p_glGetError();
1810  } while (err != GL_NO_ERROR);
1811 }
1812 
1814 {
1815  return gl_info->supported[ARB_DEBUG_OUTPUT]
1816  && (ERR_ON(d3d) || FIXME_ON(d3d) || WARN_ON(d3d_perf));
1817 }
1818 
1820  GLenum severity, GLsizei length, const char *message, void *ctx)
1821 {
1822  switch (type)
1823  {
1825  ERR("%p: %s.\n", ctx, debugstr_an(message, length));
1826  break;
1827 
1831  FIXME("%p: %s.\n", ctx, debugstr_an(message, length));
1832  break;
1833 
1835  WARN_(d3d_perf)("%p: %s.\n", ctx, debugstr_an(message, length));
1836  break;
1837 
1838  default:
1839  FIXME("ctx %p, type %#x: %s.\n", ctx, type, debugstr_an(message, length));
1840  break;
1841  }
1842 }
1843 
1844 HGLRC context_create_wgl_attribs(const struct wined3d_gl_info *gl_info, HDC hdc, HGLRC share_ctx)
1845 {
1846  HGLRC ctx;
1847  unsigned int ctx_attrib_idx = 0;
1848  GLint ctx_attribs[7], ctx_flags = 0;
1849 
1850  if (context_debug_output_enabled(gl_info))
1851  ctx_flags = WGL_CONTEXT_DEBUG_BIT_ARB;
1852  ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
1853  ctx_attribs[ctx_attrib_idx++] = gl_info->selected_gl_version >> 16;
1854  ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MINOR_VERSION_ARB;
1855  ctx_attribs[ctx_attrib_idx++] = gl_info->selected_gl_version & 0xffff;
1856  if (ctx_flags)
1857  {
1858  ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_FLAGS_ARB;
1859  ctx_attribs[ctx_attrib_idx++] = ctx_flags;
1860  }
1861  ctx_attribs[ctx_attrib_idx] = 0;
1862 
1863  if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
1864  {
1865  if (gl_info->selected_gl_version >= MAKEDWORD_VERSION(3, 2))
1866  {
1867  if (ctx_flags)
1868  {
1870  ctx_attribs[ctx_attrib_idx - 1] = ctx_flags;
1871  }
1872  else
1873  {
1875  ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_FLAGS_ARB;
1876  ctx_attribs[ctx_attrib_idx++] = ctx_flags;
1877  ctx_attribs[ctx_attrib_idx] = 0;
1878  }
1879  if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
1880  WARN("Failed to create a WGL context with wglCreateContextAttribsARB, last error %#x.\n",
1881  GetLastError());
1882  }
1883  }
1884  return ctx;
1885 }
1886 
1888  struct wined3d_texture *target, const struct wined3d_format *ds_format)
1889 {
1890  struct wined3d_device *device = swapchain->device;
1891  const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
1892  const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1893  const struct wined3d_format *color_format;
1894  struct wined3d_context *ret;
1895  BOOL auxBuffers = FALSE;
1896  HGLRC ctx, share_ctx;
1897  DWORD target_usage;
1898  unsigned int i;
1899  DWORD state;
1900 
1901  TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
1902 
1903  wined3d_from_cs(device->cs);
1904 
1905  if (!(ret = heap_alloc_zero(sizeof(*ret))))
1906  return NULL;
1907 
1908  ret->free_timestamp_query_size = 4;
1910  sizeof(*ret->free_timestamp_queries))))
1911  goto out;
1913 
1914  ret->free_occlusion_query_size = 4;
1916  sizeof(*ret->free_occlusion_queries))))
1917  goto out;
1919 
1920  ret->free_fence_size = 4;
1921  if (!(ret->free_fences = heap_calloc(ret->free_fence_size, sizeof(*ret->free_fences))))
1922  goto out;
1923  list_init(&ret->fences);
1924 
1926 
1928 
1929  list_init(&ret->fbo_list);
1930  list_init(&ret->fbo_destroy_list);
1931 
1932  if (!device->shader_backend->shader_allocate_context_data(ret))
1933  {
1934  ERR("Failed to allocate shader backend context data.\n");
1935  goto out;
1936  }
1937  if (!device->adapter->fragment_pipe->allocate_context_data(ret))
1938  {
1939  ERR("Failed to allocate fragment pipeline context data.\n");
1940  goto out;
1941  }
1942 
1943  for (i = 0; i < ARRAY_SIZE(ret->tex_unit_map); ++i)
1945  for (i = 0; i < ARRAY_SIZE(ret->rev_tex_unit_map); ++i)
1947  if (gl_info->limits.graphics_samplers >= MAX_COMBINED_SAMPLERS)
1948  {
1949  /* Initialize the texture unit mapping to a 1:1 mapping. */
1950  unsigned int base, count;
1951 
1954  {
1955  ERR("Unexpected texture unit base index %u.\n", base);
1956  goto out;
1957  }
1958  for (i = 0; i < min(count, MAX_FRAGMENT_SAMPLERS); ++i)
1959  {
1960  ret->tex_unit_map[i] = base + i;
1961  ret->rev_tex_unit_map[base + i] = i;
1962  }
1963 
1965  if (base + MAX_VERTEX_SAMPLERS > ARRAY_SIZE(ret->rev_tex_unit_map))
1966  {
1967  ERR("Unexpected texture unit base index %u.\n", base);
1968  goto out;
1969  }
1970  for (i = 0; i < min(count, MAX_VERTEX_SAMPLERS); ++i)
1971  {
1972  ret->tex_unit_map[MAX_FRAGMENT_SAMPLERS + i] = base + i;
1973  ret->rev_tex_unit_map[base + i] = MAX_FRAGMENT_SAMPLERS + i;
1974  }
1975  }
1976 
1977  if (!(ret->texture_type = heap_calloc(gl_info->limits.combined_samplers,
1978  sizeof(*ret->texture_type))))
1979  goto out;
1980 
1981  if (!(ret->hdc = GetDCEx(swapchain->win_handle, 0, DCX_USESTYLE | DCX_CACHE)))
1982  {
1983  WARN("Failed to retrieve device context, trying swapchain backup.\n");
1984 
1985  if ((ret->hdc = swapchain_get_backup_dc(swapchain)))
1986  ret->hdc_is_private = TRUE;
1987  else
1988  {
1989  ERR("Failed to retrieve a device context.\n");
1990  goto out;
1991  }
1992  }
1993 
1994  color_format = target->resource.format;
1995  target_usage = target->resource.usage;
1996 
1997  /* In case of ORM_BACKBUFFER, make sure to request an alpha component for
1998  * X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
2000  {
2001  auxBuffers = TRUE;
2002 
2003  if (color_format->id == WINED3DFMT_B4G4R4X4_UNORM)
2004  color_format = wined3d_get_format(gl_info, WINED3DFMT_B4G4R4A4_UNORM, target_usage);
2005  else if (color_format->id == WINED3DFMT_B8G8R8X8_UNORM)
2006  color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2007  }
2008 
2009  /* DirectDraw supports 8bit paletted render targets and these are used by
2010  * old games like StarCraft and C&C. Most modern hardware doesn't support
2011  * 8bit natively so we perform some form of 8bit -> 32bit conversion. The
2012  * conversion (ab)uses the alpha component for storing the palette index.
2013  * For this reason we require a format with 8bit alpha, so request
2014  * A8R8G8B8. */
2015  if (color_format->id == WINED3DFMT_P8_UINT)
2016  color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2017 
2018  /* When using FBOs for off-screen rendering, we only use the drawable for
2019  * presentation blits, and don't do any rendering to it. That means we
2020  * don't need depth or stencil buffers, and can mostly ignore the render
2021  * target format. This wouldn't necessarily be quite correct for 10bpc
2022  * display modes, but we don't currently support those.
2023  * Using the same format regardless of the color/depth/stencil targets
2024  * makes it much less likely that different wined3d instances will set
2025  * conflicting pixel formats. */
2027  {
2028  color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2030  }
2031 
2032  /* Try to find a pixel format which matches our requirements. */
2033  if (!(ret->pixel_format = context_choose_pixel_format(device, ret->hdc, color_format, ds_format, auxBuffers)))
2034  goto out;
2035 
2036  ret->gl_info = gl_info;
2037  ret->win_handle = swapchain->win_handle;
2038 
2039  context_enter(ret);
2040 
2041  if (!context_set_pixel_format(ret))
2042  {
2043  ERR("Failed to set pixel format %d on device context %p.\n", ret->pixel_format, ret->hdc);
2044  context_release(ret);
2045  goto out;
2046  }
2047 
2048  share_ctx = device->context_count ? device->contexts[0]->glCtx : NULL;
2049  if (gl_info->p_wglCreateContextAttribsARB)
2050  {
2051  if (!(ctx = context_create_wgl_attribs(gl_info, ret->hdc, share_ctx)))
2052  goto out;
2053  }
2054  else
2055  {
2056  if (!(ctx = wglCreateContext(ret->hdc)))
2057  {
2058  ERR("Failed to create a WGL context.\n");
2059  context_release(ret);
2060  goto out;
2061  }
2062 
2063  if (share_ctx && !wglShareLists(share_ctx, ctx))
2064  {
2065  ERR("wglShareLists(%p, %p) failed, last error %#x.\n", share_ctx, ctx, GetLastError());
2066  context_release(ret);
2067  if (!wglDeleteContext(ctx))
2068  ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2069  goto out;
2070  }
2071  }
2072 
2073  if (!device_context_add(device, ret))
2074  {
2075  ERR("Failed to add the newly created context to the context list\n");
2076  context_release(ret);
2077  if (!wglDeleteContext(ctx))
2078  ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2079  goto out;
2080  }
2081 
2082  ret->d3d_info = d3d_info;
2083  ret->state_table = device->StateTable;
2084 
2085  /* Mark all states dirty to force a proper initialization of the states on
2086  * the first use of the context. Compute states do not need initialization. */
2087  for (state = 0; state <= STATE_HIGHEST; ++state)
2088  {
2089  if (ret->state_table[state].representative && !STATE_IS_COMPUTE(state))
2090  context_invalidate_state(ret, state);
2091  }
2092 
2093  ret->device = device;
2094  ret->swapchain = swapchain;
2095  ret->current_rt.texture = target;
2096  ret->current_rt.sub_resource_idx = 0;
2097  ret->tid = GetCurrentThreadId();
2098 
2101  ret->valid = 1;
2102 
2103  ret->glCtx = ctx;
2104  ret->hdc_has_format = TRUE;
2105  ret->needs_set = 1;
2106 
2107  /* Set up the context defaults */
2108  if (!context_set_current(ret))
2109  {
2110  ERR("Cannot activate context to set up defaults.\n");
2111  device_context_remove(device, ret);
2112  context_release(ret);
2113  if (!wglDeleteContext(ctx))
2114  ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2115  goto out;
2116  }
2117 
2118  if (context_debug_output_enabled(gl_info))
2119  {
2120  GL_EXTCALL(glDebugMessageCallback(wined3d_debug_callback, ret));
2121  if (TRACE_ON(d3d_synchronous))
2122  gl_info->gl_ops.gl.p_glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
2123  GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE));
2124  if (ERR_ON(d3d))
2125  {
2126  GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR,
2127  GL_DONT_CARE, 0, NULL, GL_TRUE));
2128  }
2129  if (FIXME_ON(d3d))
2130  {
2132  GL_DONT_CARE, 0, NULL, GL_TRUE));
2134  GL_DONT_CARE, 0, NULL, GL_TRUE));
2135  GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_PORTABILITY,
2136  GL_DONT_CARE, 0, NULL, GL_TRUE));
2137  }
2138  if (WARN_ON(d3d_perf))
2139  {
2140  GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE,
2141  GL_DONT_CARE, 0, NULL, GL_TRUE));
2142  }
2143  }
2144 
2145  if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2146  gl_info->gl_ops.gl.p_glGetIntegerv(GL_AUX_BUFFERS, &ret->aux_buffers);
2147 
2148  TRACE("Setting up the screen\n");
2149 
2150  if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2151  {
2152  gl_info->gl_ops.gl.p_glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
2153  checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
2154 
2155  gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2156  checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
2157 
2158  gl_info->gl_ops.gl.p_glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
2159  checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
2160  }
2161  else
2162  {
2163  GLuint vao;
2164 
2165  GL_EXTCALL(glGenVertexArrays(1, &vao));
2166  GL_EXTCALL(glBindVertexArray(vao));
2167  checkGLcall("creating VAO");
2168  }
2169 
2170  gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);
2171  checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
2172  gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2173  checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, 1);");
2174 
2175  if (gl_info->supported[NV_TEXTURE_SHADER2])
2176  {
2177  /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
2178  * the previous texture where to source the offset from is always unit - 1.
2179  */
2180  for (i = 1; i < gl_info->limits.textures; ++i)
2181  {
2182  context_active_texture(ret, gl_info, i);
2183  gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_SHADER_NV,
2185  checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
2186  }
2187  }
2188  if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
2189  {
2190  /* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
2191  * enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
2192  * GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
2193  * because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
2194  * is ever assigned.
2195  *
2196  * So make sure a program is assigned to each context. The first real ARBFP use will set a different
2197  * program and the dummy program is destroyed when the context is destroyed.
2198  */
2199  static const char dummy_program[] =
2200  "!!ARBfp1.0\n"
2201  "MOV result.color, fragment.color.primary;\n"
2202  "END\n";
2203  GL_EXTCALL(glGenProgramsARB(1, &ret->dummy_arbfp_prog));
2204  GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret->dummy_arbfp_prog));
2205  GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
2206  }
2207 
2208  if (gl_info->supported[ARB_POINT_SPRITE])
2209  {
2210  for (i = 0; i < gl_info->limits.textures; ++i)
2211  {
2212  context_active_texture(ret, gl_info, i);
2213  gl_info->gl_ops.gl.p_glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
2214  checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
2215  }
2216  }
2217 
2218  if (gl_info->supported[ARB_PROVOKING_VERTEX])
2219  {
2220  GL_EXTCALL(glProvokingVertex(GL_FIRST_VERTEX_CONVENTION));
2221  }
2222  else if (gl_info->supported[EXT_PROVOKING_VERTEX])
2223  {
2224  GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
2225  }
2227  {
2228  if (gl_info->supported[ARB_ES3_COMPATIBILITY])
2229  {
2230  gl_info->gl_ops.gl.p_glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2231  checkGLcall("enable GL_PRIMITIVE_RESTART_FIXED_INDEX");
2232  }
2233  else
2234  {
2235  FIXME("OpenGL implementation does not support GL_PRIMITIVE_RESTART_FIXED_INDEX.\n");
2236  }
2237  }
2239  && gl_info->supported[ARB_SEAMLESS_CUBE_MAP])
2240  {
2241  gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
2242  checkGLcall("enable seamless cube map filtering");
2243  }
2244  if (gl_info->supported[ARB_CLIP_CONTROL])
2246  device->shader_backend->shader_init_context_state(ret);
2250  | (1u << WINED3D_SHADER_TYPE_HULL)
2253 
2254  /* If this happens to be the first context for the device, dummy textures
2255  * are not created yet. In that case, they will be created (and bound) by
2256  * create_dummy_textures right after this context is initialized. */
2257  if (device->dummy_textures.tex_2d)
2258  context_bind_dummy_textures(device, ret);
2259 
2260  /* Initialise all rectangles to avoid resetting unused ones later. */
2261  gl_info->gl_ops.gl.p_glScissor(0, 0, 0, 0);
2262  checkGLcall("glScissor");
2263 
2264  TRACE("Created context %p.\n", ret);
2265 
2266  return ret;
2267 
2268 out:
2269  if (ret->hdc)
2270  wined3d_release_dc(swapchain->win_handle, ret->hdc);
2271  device->shader_backend->shader_free_context_data(ret);
2272  device->adapter->fragment_pipe->free_context_data(ret);
2273  heap_free(ret->texture_type);
2274  heap_free(ret->free_fences);
2277  heap_free(ret);
2278  return NULL;
2279 }
2280 
2282 {
2283  BOOL destroy;
2284 
2285  TRACE("Destroying ctx %p\n", context);
2286 
2287  wined3d_from_cs(device->cs);
2288 
2289  /* We delay destroying a context when it is active. The context_release()
2290  * function invokes context_destroy() again while leaving the last level. */
2291  if (context->level)
2292  {
2293  TRACE("Delaying destruction of context %p.\n", context);
2294  context->destroy_delayed = 1;
2295  /* FIXME: Get rid of a pointer to swapchain from wined3d_context. */
2296  context->swapchain = NULL;
2297  return;
2298  }
2299 
2300  if (context->tid == GetCurrentThreadId() || !context->current)
2301  {
2304  destroy = TRUE;
2305  }
2306  else
2307  {
2308  /* Make a copy of gl_info for context_destroy_gl_resources use, the one
2309  in wined3d_adapter may go away in the meantime */
2310  struct wined3d_gl_info *gl_info = heap_alloc(sizeof(*gl_info));
2311  *gl_info = *context->gl_info;
2312  context->gl_info = gl_info;
2313  context->destroyed = 1;
2314  destroy = FALSE;
2315  }
2316 
2317  device->shader_backend->shader_free_context_data(context);
2318  device->adapter->fragment_pipe->free_context_data(context);
2319  heap_free(context->texture_type);
2320  device_context_remove(device, context);
2321  if (destroy)
2322  heap_free(context);
2323 }
2324 
2326  const struct wined3d_shader_version *shader_version, unsigned int *base, unsigned int *count)
2327 {
2328  const struct wined3d_gl_info *gl_info = context->gl_info;
2329 
2330  if (!shader_version)
2331  {
2332  *base = 0;
2333  *count = MAX_TEXTURES;
2334  return context->tex_unit_map;
2335  }
2336 
2337  if (shader_version->major >= 4)
2338  {
2339  wined3d_gl_limits_get_texture_unit_range(&gl_info->limits, shader_version->type, base, count);
2340  return NULL;
2341  }
2342 
2343  switch (shader_version->type)
2344  {
2346  *base = 0;
2347  *count = MAX_FRAGMENT_SAMPLERS;
2348  break;
2350  *base = MAX_FRAGMENT_SAMPLERS;
2351  *count = MAX_VERTEX_SAMPLERS;
2352  break;
2353  default:
2354  ERR("Unhandled shader type %#x.\n", shader_version->type);
2355  *base = 0;
2356  *count = 0;
2357  }
2358 
2359  return context->tex_unit_map;
2360 }
2361 
2362 static void context_get_rt_size(const struct wined3d_context *context, SIZE *size)
2363 {
2364  const struct wined3d_texture *rt = context->current_rt.texture;
2365  unsigned int level;
2366 
2367  if (rt->swapchain)
2368  {
2369  RECT window_size;
2370 
2371  GetClientRect(context->win_handle, &window_size);
2372  size->cx = window_size.right - window_size.left;
2373  size->cy = window_size.bottom - window_size.top;
2374 
2375  return;
2376  }
2377 
2378  level = context->current_rt.sub_resource_idx % rt->level_count;
2379  size->cx = wined3d_texture_get_level_width(rt, level);
2380  size->cy = wined3d_texture_get_level_height(rt, level);
2381 }
2382 
2383 void context_enable_clip_distances(struct wined3d_context *context, unsigned int enable_mask)
2384 {
2385  const struct wined3d_gl_info *gl_info = context->gl_info;
2386  unsigned int clip_distance_count = gl_info->limits.user_clip_distances;
2387  unsigned int i, disable_mask, current_mask;
2388 
2389  disable_mask = ~enable_mask;
2390  enable_mask &= (1u << clip_distance_count) - 1;
2391  disable_mask &= (1u << clip_distance_count) - 1;
2392  current_mask = context->clip_distance_mask;
2393  context->clip_distance_mask = enable_mask;
2394 
2395  enable_mask &= ~current_mask;
2396  while (enable_mask)
2397  {
2398  i = wined3d_bit_scan(&enable_mask);
2399  gl_info->gl_ops.gl.p_glEnable(GL_CLIP_DISTANCE0 + i);
2400  }
2401  disable_mask &= current_mask;
2402  while (disable_mask)
2403  {
2404  i = wined3d_bit_scan(&disable_mask);
2405  gl_info->gl_ops.gl.p_glDisable(GL_CLIP_DISTANCE0 + i);
2406  }
2407  checkGLcall("toggle clip distances");
2408 }
2409 
2410 static inline BOOL is_rt_mask_onscreen(DWORD rt_mask)
2411 {
2412  return rt_mask & (1u << 31);
2413 }
2414 
2415 static inline GLenum draw_buffer_from_rt_mask(DWORD rt_mask)
2416 {
2417  return rt_mask & ~(1u << 31);
2418 }
2419 
2420 /* Context activation is done by the caller. */
2421 static void context_apply_draw_buffers(struct wined3d_context *context, DWORD rt_mask)
2422 {
2423  const struct wined3d_gl_info *gl_info = context->gl_info;
2424  GLenum draw_buffers[MAX_RENDER_TARGET_VIEWS];
2425 
2426  if (!rt_mask)
2427  {
2428  gl_info->gl_ops.gl.p_glDrawBuffer(GL_NONE);
2429  }
2430  else if (is_rt_mask_onscreen(rt_mask))
2431  {
2432  gl_info->gl_ops.gl.p_glDrawBuffer(draw_buffer_from_rt_mask(rt_mask));
2433  }
2434  else
2435  {
2437  {
2438  unsigned int i = 0;
2439 
2440  while (rt_mask)
2441  {
2442  if (rt_mask & 1)
2443  draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
2444  else
2445  draw_buffers[i] = GL_NONE;
2446 
2447  rt_mask >>= 1;
2448  ++i;
2449  }
2450 
2451  if (gl_info->supported[ARB_DRAW_BUFFERS])
2452  {
2453  GL_EXTCALL(glDrawBuffers(i, draw_buffers));
2454  }
2455  else
2456  {
2457  gl_info->gl_ops.gl.p_glDrawBuffer(draw_buffers[0]);
2458  }
2459  }
2460  else
2461  {
2462  ERR("Unexpected draw buffers mask with backbuffer ORM.\n");
2463  }
2464  }
2465 
2466  checkGLcall("apply draw buffers");
2467 }
2468 
2469 /* Context activation is done by the caller. */
2471 {
2472  const struct wined3d_gl_info *gl_info = context->gl_info;
2473  DWORD *current_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2474  DWORD new_mask = context_generate_rt_mask(buffer);
2475 
2476  if (new_mask == *current_mask)
2477  return;
2478 
2479  gl_info->gl_ops.gl.p_glDrawBuffer(buffer);
2480  checkGLcall("glDrawBuffer()");
2481 
2482  *current_mask = new_mask;
2483 }
2484 
2485 /* Context activation is done by the caller. */
2486 void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info, unsigned int unit)
2487 {
2489  checkGLcall("glActiveTexture");
2490  context->active_texture = unit;
2491 }
2492 
2493 void context_bind_bo(struct wined3d_context *context, GLenum binding, GLuint name)
2494 {
2495  const struct wined3d_gl_info *gl_info = context->gl_info;
2496 
2497  if (binding == GL_ELEMENT_ARRAY_BUFFER)
2499 
2500  GL_EXTCALL(glBindBuffer(binding, name));
2501 }
2502 
2504 {
2505  const struct wined3d_dummy_textures *textures = &context->device->dummy_textures;
2506  const struct wined3d_gl_info *gl_info = context->gl_info;
2507  DWORD unit = context->active_texture;
2508  DWORD old_texture_type = context->texture_type[unit];
2509 
2510  if (name)
2511  {
2512  gl_info->gl_ops.gl.p_glBindTexture(target, name);
2513  }
2514  else
2515  {
2516  target = GL_NONE;
2517  }
2518 
2519  if (old_texture_type != target)
2520  {
2521  switch (old_texture_type)
2522  {
2523  case GL_NONE:
2524  /* nothing to do */
2525  break;
2526  case GL_TEXTURE_1D:
2527  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, textures->tex_1d);
2528  break;
2529  case GL_TEXTURE_1D_ARRAY:
2530  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D_ARRAY, textures->tex_1d_array);
2531  break;
2532  case GL_TEXTURE_2D:
2533  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, textures->tex_2d);
2534  break;
2535  case GL_TEXTURE_2D_ARRAY:
2536  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_ARRAY, textures->tex_2d_array);
2537  break;
2539  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textures->tex_rect);
2540  break;
2541  case GL_TEXTURE_CUBE_MAP:
2542  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, textures->tex_cube);
2543  break;
2545  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, textures->tex_cube_array);
2546  break;
2547  case GL_TEXTURE_3D:
2548  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, textures->tex_3d);
2549  break;
2550  case GL_TEXTURE_BUFFER:
2551  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_BUFFER, textures->tex_buffer);
2552  break;
2554  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textures->tex_2d_ms);
2555  break;
2557  gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, textures->tex_2d_ms_array);
2558  break;
2559  default:
2560  ERR("Unexpected texture target %#x.\n", old_texture_type);
2561  }
2562 
2563  context->texture_type[unit] = target;
2564  }
2565 
2566  checkGLcall("bind texture");
2567 }
2568 
2570  const struct wined3d_bo_address *data, size_t size, GLenum binding, DWORD flags)
2571 {
2572  const struct wined3d_gl_info *gl_info;
2573  BYTE *memory;
2574 
2575  if (!data->buffer_object)
2576  return data->addr;
2577 
2578  gl_info = context->gl_info;
2579  context_bind_bo(context, binding, data->buffer_object);
2580 
2581  if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
2582  {
2584  memory = GL_EXTCALL(glMapBufferRange(binding, (INT_PTR)data->addr, size, map_flags));
2585  }
2586  else
2587  {
2588  memory = GL_EXTCALL(glMapBuffer(binding, wined3d_resource_gl_legacy_map_flags(flags)));
2589  memory += (INT_PTR)data->addr;
2590  }
2591 
2592  context_bind_bo(context, binding, 0);
2593  checkGLcall("Map buffer object");
2594 
2595  return memory;
2596 }
2597 
2599  const struct wined3d_bo_address *data, GLenum binding)
2600 {
2601  const struct wined3d_gl_info *gl_info;
2602 
2603  if (!data->buffer_object)
2604  return;
2605 
2606  gl_info = context->gl_info;
2607  context_bind_bo(context, binding, data->buffer_object);
2608  GL_EXTCALL(glUnmapBuffer(binding));
2609  context_bind_bo(context, binding, 0);
2610  checkGLcall("Unmap buffer object");
2611 }
2612 
2614  const struct wined3d_bo_address *dst, GLenum dst_binding,
2615  const struct wined3d_bo_address *src, GLenum src_binding, size_t size)
2616 {
2617  const struct wined3d_gl_info *gl_info;
2618  BYTE *dst_ptr, *src_ptr;
2619 
2620  gl_info = context->gl_info;
2621 
2622  if (dst->buffer_object && src->buffer_object)
2623  {
2624  if (gl_info->supported[ARB_COPY_BUFFER])
2625  {
2626  GL_EXTCALL(glBindBuffer(GL_COPY_READ_BUFFER, src->buffer_object));
2627  GL_EXTCALL(glBindBuffer(GL_COPY_WRITE_BUFFER, dst->buffer_object));
2629  (GLintptr)src->addr, (GLintptr)dst->addr, size));
2630  checkGLcall("direct buffer copy");
2631  }
2632  else
2633  {
2634  src_ptr = context_map_bo_address(context, src, size, src_binding, WINED3D_MAP_READ);
2635  dst_ptr = context_map_bo_address(context, dst, size, dst_binding, WINED3D_MAP_WRITE);
2636 
2637  memcpy(dst_ptr, src_ptr, size);
2638 
2639  context_unmap_bo_address(context, dst, dst_binding);
2640  context_unmap_bo_address(context, src, src_binding);
2641  }
2642  }
2643  else if (!dst->buffer_object && src->buffer_object)
2644  {
2645  context_bind_bo(context, src_binding, src->buffer_object);
2646  GL_EXTCALL(glGetBufferSubData(src_binding, (GLintptr)src->addr, size, dst->addr));
2647  checkGLcall("buffer download");
2648  }
2649  else if (dst->buffer_object && !src->buffer_object)
2650  {
2651  context_bind_bo(context, dst_binding, dst->buffer_object);
2652  GL_EXTCALL(glBufferSubData(dst_binding, (GLintptr)dst->addr, size, src->addr));
2653  checkGLcall("buffer upload");
2654  }
2655  else
2656  {
2657  memcpy(dst->addr, src->addr, size);
2658  }
2659 }
2660 
2661 static void context_set_render_offscreen(struct wined3d_context *context, BOOL offscreen)
2662 {
2663  if (context->render_offscreen == offscreen)
2664  return;
2665 
2668  if (!context->gl_info->supported[ARB_CLIP_CONTROL])
2669  {
2673  }
2675  if (context->gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS])
2677  context->render_offscreen = offscreen;
2678 }
2679 
2680 static BOOL match_depth_stencil_format(const struct wined3d_format *existing,
2681  const struct wined3d_format *required)
2682 {
2683  if (existing == required)
2684  return TRUE;
2686  != (required->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FLOAT))
2687  return FALSE;
2688  if (existing->depth_size < required->depth_size)
2689  return FALSE;
2690  /* If stencil bits are used the exact amount is required - otherwise
2691  * wrapping won't work correctly. */
2692  if (required->stencil_size && required->stencil_size != existing->stencil_size)
2693  return FALSE;
2694  return TRUE;
2695 }
2696 
2697 /* Context activation is done by the caller. */
2699  const struct wined3d_rendertarget_view *depth_stencil)
2700 {
2701  /* Onscreen surfaces are always in a swapchain */
2702  struct wined3d_swapchain *swapchain = context->current_rt.texture->swapchain;
2703 
2704  if (context->render_offscreen || !depth_stencil) return;
2705  if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->format)) return;
2706 
2707  /* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
2708  * or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
2709  * format. */
2710  WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
2711 
2712  /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
2713  if (!(wined3d_texture_load_location(context->current_rt.texture, context->current_rt.sub_resource_idx,
2714  context, WINED3D_LOCATION_TEXTURE_RGB)))
2715  ERR("Failed to load location.\n");
2716  swapchain->render_to_fbo = TRUE;
2717  swapchain_update_draw_bindings(swapchain);
2719 }
2720 
2722 {
2724  {
2725  case ORM_FBO:
2726  return GL_COLOR_ATTACHMENT0;
2727 
2728  case ORM_BACKBUFFER:
2729  return context->aux_buffers > 0 ? GL_AUX0 : GL_BACK;
2730 
2731  default:
2732  FIXME("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
2733  return GL_BACK;
2734  }
2735 }
2736 
2738 {
2739  if (!rt || rt->format->id == WINED3DFMT_NULL)
2740  return 0;
2741  else if (rt->type != WINED3D_RTYPE_BUFFER && texture_from_resource(rt)->swapchain)
2743  else
2745 }
2746 
2747 /* Context activation is done by the caller. */
2749 {
2750  const struct wined3d_gl_info *gl_info = context->gl_info;
2751  struct wined3d_texture *rt = context->current_rt.texture;
2752  DWORD rt_mask, *cur_mask;
2753  unsigned int i, sampler;
2754  SIZE rt_size;
2755 
2756  TRACE("Setting up context %p for blitting.\n", context);
2757 
2759  {
2760  if (context->render_offscreen)
2761  {
2762  wined3d_texture_load(rt, context, FALSE);
2763 
2765  context->current_rt.sub_resource_idx, NULL, 0, rt->resource.draw_binding);
2766  if (rt->resource.format->id != WINED3DFMT_NULL)
2767  rt_mask = 1;
2768  else
2769  rt_mask = 0;
2770  }
2771  else
2772  {
2773  context->current_fbo = NULL;
2774  context_bind_fbo(context, GL_FRAMEBUFFER, 0);
2776  }
2777  }
2778  else
2779  {
2780  rt_mask = context_generate_rt_mask_no_fbo(context, &rt->resource);
2781  }
2782 
2783  cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2784 
2785  if (rt_mask != *cur_mask)
2786  {
2787  context_apply_draw_buffers(context, rt_mask);
2788  *cur_mask = rt_mask;
2789  }
2790 
2792  {
2794  }
2796 
2797  context_get_rt_size(context, &rt_size);
2798 
2799  if (context->last_was_blit)
2800  {
2801  if (context->blit_w != rt_size.cx || context->blit_h != rt_size.cy)
2802  {
2803  gl_info->gl_ops.gl.p_glViewport(0, 0, rt_size.cx, rt_size.cy);
2805  context->blit_w = rt_size.cx;
2806  context->blit_h = rt_size.cy;
2807  /* No need to dirtify here, the states are still dirtified because
2808  * they weren't applied since the last context_apply_blit_state()
2809  * call. */
2810  }
2811  checkGLcall("blit state application");
2812  TRACE("Context is already set up for blitting, nothing to do.\n");
2813  return;
2814  }
2815  context->last_was_blit = TRUE;
2816 
2817  if (gl_info->supported[ARB_SAMPLER_OBJECTS])
2818  GL_EXTCALL(glBindSampler(0, 0));
2819  context_active_texture(context, gl_info, 0);
2820 
2821  sampler = context->rev_tex_unit_map[0];
2822  if (sampler != WINED3D_UNMAPPED_STAGE)
2823  {
2824  if (sampler < MAX_TEXTURES)
2825  {
2828  }
2829  context_invalidate_state(context, STATE_SAMPLER(sampler));
2830  }
2831 
2832  if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2833  {
2834  gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2836  }
2837  gl_info->gl_ops.gl.p_glDisable(GL_DEPTH_TEST);
2839  gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2841  gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2843  gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2845  gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2847  if (gl_info->supported[ARB_POINT_SPRITE])
2848  {
2849  gl_info->gl_ops.gl.p_glDisable(GL_POINT_SPRITE_ARB);
2851  }
2852  if (gl_info->supported[ARB_FRAMEBUFFER_SRGB])
2853  {
2854  gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB);
2856  }
2857  gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2858  for (i = 0; i < MAX_RENDER_TARGETS; ++i)
2860 
2861  context->last_was_rhw = TRUE;
2862  context_invalidate_state(context, STATE_VDECL); /* because of last_was_rhw = TRUE */
2863 
2864  context_enable_clip_distances(context, 0);
2866 
2867  /* FIXME: Make draw_textured_quad() able to work with a upper left origin. */
2868  if (gl_info->supported[ARB_CLIP_CONTROL])
2870  gl_info->gl_ops.gl.p_glViewport(0, 0, rt_size.cx, rt_size.cy);
2873 
2874  device->shader_backend->shader_disable(device->shader_priv, context);
2875 
2876  context->blit_w = rt_size.cx;
2877  context->blit_h = rt_size.cy;
2878 
2879  checkGLcall("blit state application");
2880 }
2881 
2882 static void context_apply_blit_projection(const struct wined3d_context *context, unsigned int w, unsigned int h)
2883 {
2884  const struct wined3d_gl_info *gl_info = context->gl_info;
2885  const GLdouble projection[] =
2886  {
2887  2.0 / w, 0.0, 0.0, 0.0,
2888  0.0, 2.0 / h, 0.0, 0.0,
2889  0.0, 0.0, 2.0, 0.0,
2890  -1.0, -1.0, -1.0, 1.0,
2891  };
2892 
2893  gl_info->gl_ops.gl.p_glMatrixMode(GL_PROJECTION);
2894  gl_info->gl_ops.gl.p_glLoadMatrixd(projection);
2895 }
2896 
2897 /* Setup OpenGL states for fixed-function blitting. */
2898 /* Context activation is done by the caller. */
2900 {
2901  const struct wined3d_gl_info *gl_info = context->gl_info;
2902  unsigned int i, sampler;
2903 
2904  if (!gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2905  ERR("Applying fixed-function state without legacy context support.\n");
2906 
2907  if (context->last_was_ffp_blit)
2908  {
2909  SIZE rt_size;
2910 
2911  context_get_rt_size(context, &rt_size);
2912  if (context->blit_w != rt_size.cx || context->blit_h != rt_size.cy)
2913  context_apply_blit_projection(context, rt_size.cx, rt_size.cy);
2914  context_apply_blit_state(context, device);
2915 
2916  checkGLcall("ffp blit state application");
2917  return;
2918  }
2919  context->last_was_ffp_blit = TRUE;
2920 
2921  context_apply_blit_state(context, device);
2922 
2923  /* Disable all textures. The caller can then bind a texture it wants to blit
2924  * from. */
2925  for (i = gl_info->limits.textures - 1; i > 0 ; --i)
2926  {
2927  context_active_texture(context, gl_info, i);
2928 
2929  if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2930  gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2931  gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_3D);
2932  if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2933  gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2934  gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2935 
2936  gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2937 
2938  sampler = context->rev_tex_unit_map[i];
2939  if (sampler != WINED3D_UNMAPPED_STAGE)
2940  {
2941  if (sampler < MAX_TEXTURES)
2943  context_invalidate_state(context, STATE_SAMPLER(sampler));
2944  }
2945  }
2946 
2947  context_active_texture(context, gl_info, 0);
2948 
2949  if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2950  gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2951  gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_3D);
2952  if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2953  gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2954  gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2955 
2956  gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2957  if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
2958  gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.0f);
2959 
2960  gl_info->gl_ops.gl.p_glMatrixMode(GL_TEXTURE);
2961  gl_info->gl_ops.gl.p_glLoadIdentity();
2962 
2963  /* Setup transforms. */
2964  gl_info->gl_ops.gl.p_glMatrixMode(GL_MODELVIEW);
2965  gl_info->gl_ops.gl.p_glLoadIdentity();
2967  context_apply_blit_projection(context, context->blit_w, context->blit_h);
2969 
2970  /* Other misc states. */
2971  gl_info->gl_ops.gl.p_glDisable(GL_LIGHTING);
2973  glDisableWINE(GL_FOG);
2975 
2976  if (gl_info->supported[EXT_SECONDARY_COLOR])
2977  {
2978  gl_info->gl_ops.gl.p_glDisable(GL_COLOR_SUM_EXT);
2980  }
2981  checkGLcall("ffp blit state application");
2982 }
2983 
2984 static BOOL have_framebuffer_attachment(unsigned int rt_count, struct wined3d_rendertarget_view * const *rts,
2985  const struct wined3d_rendertarget_view *ds)
2986 {
2987  unsigned int i;
2988 
2989  if (ds)
2990  return TRUE;
2991 
2992  for (i = 0; i < rt_count; ++i)
2993  {
2994  if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
2995  return TRUE;
2996  }
2997 
2998  return FALSE;
2999 }
3000 
3001 /* Context activation is done by the caller. */
3003  UINT rt_count, const struct wined3d_fb_state *fb)
3004 {
3005  struct wined3d_rendertarget_view * const *rts = fb->render_targets;
3006  struct wined3d_rendertarget_view *dsv = fb->depth_stencil;
3007  const struct wined3d_gl_info *gl_info = context->gl_info;
3008  DWORD rt_mask = 0, *cur_mask;
3009  unsigned int i;
3010 
3011  if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != state->fb
3012  || rt_count != gl_info->limits.buffers)
3013  {
3014  if (!have_framebuffer_attachment(rt_count, rts, dsv))
3015  {
3016  WARN("Invalid render target config, need at least one attachment.\n");
3017  return FALSE;
3018  }
3019 
3021  {
3022  struct wined3d_rendertarget_info ds_info = {{0}};
3023 
3024  context_validate_onscreen_formats(context, dsv);
3025 
3026  if (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource))
3027  {
3028  memset(context->blit_targets, 0, sizeof(context->blit_targets));
3029  for (i = 0; i < rt_count; ++i)
3030  {
3031  if (rts[i])
3032  {
3033  context->blit_targets[i].gl_view = rts[i]->gl_view;
3034  context->blit_targets[i].resource = rts[i]->resource;
3035  context->blit_targets[i].sub_resource_idx = rts[i]->sub_resource_idx;
3036  context->blit_targets[i].layer_count = rts[i]->layer_count;
3037  }
3038  if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
3039  rt_mask |= (1u << i);
3040  }
3041 
3042  if (dsv)
3043  {
3044  ds_info.gl_view = dsv->gl_view;
3045  ds_info.resource = dsv->resource;
3046  ds_info.sub_resource_idx = dsv->sub_resource_idx;
3047  ds_info.layer_count = dsv->layer_count;
3048  }
3049 
3050  context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, &ds_info,
3051  rt_count ? rts[0]->resource->draw_binding : 0,
3052  dsv ? dsv->resource->draw_binding : 0);
3053  }
3054  else
3055  {
3056  context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, &ds_info,
3059  }
3060 
3061  /* If the framebuffer is not the device's fb the device's fb has to be reapplied
3062  * next draw. Otherwise we could mark the framebuffer state clean here, once the
3063  * state management allows this */
3065  }
3066  else
3067  {
3068  rt_mask = context_generate_rt_mask_no_fbo(context, rt_count ? rts[0]->resource : NULL);
3069  }
3070  }
3072  && (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource)))
3073  {
3074  for (i = 0; i < rt_count; ++i)
3075  {
3076  if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
3077  rt_mask |= (1u << i);
3078  }
3079  }
3080  else
3081  {
3082  rt_mask = context_generate_rt_mask_no_fbo(context, rt_count ? rts[0]->resource : NULL);
3083  }
3084 
3085  cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3086 
3087  if (rt_mask != *cur_mask)
3088  {
3089  context_apply_draw_buffers(context, rt_mask);
3090  *cur_mask = rt_mask;
3092  }
3093 
3095  {
3097  }
3098 
3099  context->last_was_blit = FALSE;
3100  context->last_was_ffp_blit = FALSE;
3101 
3102  /* Blending and clearing should be orthogonal, but tests on the nvidia
3103  * driver show that disabling blending when clearing improves the clearing
3104  * performance incredibly. */
3105  gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
3106  gl_info->gl_ops.gl.p_glEnable(GL_SCISSOR_TEST);
3107  if (rt_count && gl_info->supported[ARB_FRAMEBUFFER_SRGB])
3108  {
3109  if (needs_srgb_write(context, state, fb))
3110  gl_info->gl_ops.gl.p_glEnable(GL_FRAMEBUFFER_SRGB);
3111  else
3112  gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB);
3114  }
3115  checkGLcall("setting up state for clear");
3116 
3120 
3121  return TRUE;
3122 }
3123 
3124 static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_state *state)
3125 {
3126  struct wined3d_rendertarget_view * const *rts = state->fb->render_targets;
3128  DWORD rt_mask, mask;
3129  unsigned int i;
3130 
3132  return context_generate_rt_mask_no_fbo(context, rts[0]->resource);
3133  else if (!context->render_offscreen)
3135 
3136  /* If we attach more buffers than supported in dual blend mode, the NVIDIA
3137  * driver generates the following error:
3138  * GL_INVALID_OPERATION error generated. State(s) are invalid: blend.
3139  * DX11 does not treat this configuration as invalid, so disable the unused ones.
3140  */
3141  rt_mask = ps ? ps->reg_maps.rt_mask : 1;
3142  if (wined3d_dualblend_enabled(state, context->gl_info))
3143  rt_mask &= context->d3d_info->valid_dual_rt_mask;
3144  else
3145  rt_mask &= context->d3d_info->valid_rt_mask;
3146 
3147  mask = rt_mask;
3148  i = 0;
3149  while (mask)
3150  {
3151  i = wined3d_bit_scan(&mask);
3152  if (!rts[i] || rts[i]->format->id == WINED3DFMT_NULL)
3153  rt_mask &= ~(1u << i);
3154  }
3155 
3156  return rt_mask;
3157 }
3158 
3159 /* Context activation is done by the caller. */
3160 void context_state_fb(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
3161 {
3162  DWORD rt_mask = find_draw_buffers_mask(context, state);
3163  const struct wined3d_fb_state *fb = state->fb;
3164  DWORD color_location = 0;
3165  DWORD *cur_mask;
3166 
3168  {
3169  struct wined3d_rendertarget_info ds_info = {{0}};
3170 
3171  if (!context->render_offscreen)
3172  {
3173  context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, &ds_info,
3175  }
3176  else
3177  {
3178  unsigned int i;
3179 
3180  memset(context->blit_targets, 0, sizeof(context->blit_targets));
3181  for (i = 0; i < context->gl_info->limits.buffers; ++i)
3182  {
3183  if (!fb->render_targets[i])
3184  continue;
3185 
3186  context->blit_targets[i].gl_view = fb->render_targets[i]->gl_view;
3187  context->blit_targets[i].resource = fb->render_targets[i]->resource;
3188  context->blit_targets[i].sub_resource_idx = fb->render_targets[i]->sub_resource_idx;
3189  context->blit_targets[i].layer_count = fb->render_targets[i]->layer_count;
3190 
3191  if (!color_location)
3192  color_location = fb->render_targets[i]->resource->draw_binding;
3193  }
3194 
3195  if (fb->depth_stencil)
3196  {
3197  ds_info.gl_view = fb->depth_stencil->gl_view;
3198  ds_info.resource = fb->depth_stencil->resource;
3199  ds_info.sub_resource_idx = fb->depth_stencil->sub_resource_idx;
3200  ds_info.layer_count = fb->depth_stencil->layer_count;
3201  }
3202 
3203  context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets, &ds_info,
3204  color_location, fb->depth_stencil ? fb->depth_stencil->resource->draw_binding : 0);
3205  }
3206  }
3207 
3208  cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3209  if (rt_mask != *cur_mask)
3210  {
3211  context_apply_draw_buffers(context, rt_mask);
3212  *cur_mask = rt_mask;
3213  }
3215 }
3216 
3217 static void context_map_stage(struct wined3d_context *context, DWORD stage, DWORD unit)
3218 {
3219  DWORD i = context->rev_tex_unit_map[unit];
3220  DWORD j = context->tex_unit_map[stage];
3221 
3222  TRACE("Mapping stage %u to unit %u.\n", stage, unit);
3223  context->tex_unit_map[stage] = unit;
3224  if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3226 
3227  context->rev_tex_unit_map[unit] = stage;
3228  if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3230 }
3231 
3232 static void context_invalidate_texture_stage(struct wined3d_context *context, DWORD stage)
3233 {
3234  DWORD i;
3235 
3236  for (i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3237  context_invalidate_state(context, STATE_TEXTURESTAGE(stage, i));
3238 }
3239 
3241  const struct wined3d_state *state)
3242 {
3243  UINT i, start, end;
3244 
3245  context->fixed_function_usage_map = 0;
3246  for (i = 0; i < MAX_TEXTURES; ++i)
3247  {
3248  enum wined3d_texture_op color_op = state->texture_states[i][WINED3D_TSS_COLOR_OP];
3249  enum wined3d_texture_op alpha_op = state->texture_states[i][WINED3D_TSS_ALPHA_OP];
3256 
3257  /* Not used, and disable higher stages. */
3258  if (color_op == WINED3D_TOP_DISABLE)
3259  break;
3260 
3261  if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG2)
3262  || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG1)
3263  || ((color_arg3 == WINED3DTA_TEXTURE)
3264  && (color_op == WINED3D_TOP_MULTIPLY_ADD || color_op == WINED3D_TOP_LERP))
3265  || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG2)
3266  || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG1)
3267  || ((alpha_arg3 == WINED3DTA_TEXTURE)
3268  && (alpha_op == WINED3D_TOP_MULTIPLY_ADD || alpha_op == WINED3D_TOP_LERP)))
3269  context->fixed_function_usage_map |= (1u << i);
3270 
3271  if ((color_op == WINED3D_TOP_BUMPENVMAP || color_op == WINED3D_TOP_BUMPENVMAP_LUMINANCE)
3272  && i < MAX_TEXTURES - 1)
3273  context->fixed_function_usage_map |= (1u << (i + 1));
3274  }
3275 
3276  if (i < context->lowest_disabled_stage)
3277  {
3278  start = i;
3279  end = context->lowest_disabled_stage;
3280  }
3281  else
3282  {
3283  start = context->lowest_disabled_stage;
3284  end = i;
3285  }
3286 
3287  context->lowest_disabled_stage = i;
3288  for (i = start + 1; i < end; ++i)
3289  {
3291  }
3292 }
3293 
3295  const struct wined3d_state *state)
3296 {
3297  const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3298  unsigned int i, tex;
3299  WORD ffu_map;
3300 
3301  ffu_map = context->fixed_function_usage_map;
3302 
3303  if (d3d_info->limits.ffp_textures == d3d_info->limits.ffp_blend_stages
3304  || context->lowest_disabled_stage <= d3d_info->limits.ffp_textures)
3305  {
3306  for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3307  {
3308  if (!(ffu_map & 1))
3309  continue;
3310 
3311  if (context->tex_unit_map[i] != i)
3312  {
3313  context_map_stage(context, i, i);
3316  }
3317  }
3318  return;
3319  }
3320 
3321  /* Now work out the mapping */
3322  tex = 0;
3323  for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3324  {
3325  if (!(ffu_map & 1))
3326  continue;
3327 
3328  if (context->tex_unit_map[i] != tex)
3329  {
3330  context_map_stage(context, i, tex);
3333  }
3334 
3335  ++tex;
3336  }
3337 }
3338 
3339 static void context_map_psamplers(struct wined3d_context *context, const struct wined3d_state *state)
3340 {
3341  const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3342  const struct wined3d_shader_resource_info *resource_info =
3343  state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info;
3344  unsigned int i;
3345 
3346  for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
3347  {
3348  if (resource_info[i].type && context->tex_unit_map[i] != i)
3349  {
3350  context_map_stage(context, i, i);
3352  if (i < d3d_info->limits.ffp_blend_stages)
3354  }
3355  }
3356 }
3357 
3358 static BOOL context_unit_free_for_vs(const struct wined3d_context *context,
3359  const struct wined3d_shader_resource_info *ps_resource_info, DWORD unit)
3360 {
3361  DWORD current_mapping = context->rev_tex_unit_map[unit];
3362 
3363  /* Not currently used */
3364  if (current_mapping == WINED3D_UNMAPPED_STAGE)
3365  return TRUE;
3366 
3367  if (current_mapping < MAX_FRAGMENT_SAMPLERS)
3368  {
3369  /* Used by a fragment sampler */
3370 
3371  if (!ps_resource_info)
3372  {
3373  /* No pixel shader, check fixed function */
3374  return current_mapping >= MAX_TEXTURES || !(context->fixed_function_usage_map & (1u << current_mapping));
3375  }
3376 
3377  /* Pixel shader, check the shader's sampler map */
3378  return !ps_resource_info[current_mapping].type;
3379  }
3380 
3381  return TRUE;
3382 }
3383 
3384 static void context_map_vsamplers(struct wined3d_context *context, BOOL ps, const struct wined3d_state *state)
3385 {
3386  const struct wined3d_shader_resource_info *vs_resource_info =
3387  state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.resource_info;
3388  const struct wined3d_shader_resource_info *ps_resource_info = NULL;
3389  const struct wined3d_gl_info *gl_info = context->gl_info;
3390  int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.graphics_samplers) - 1;
3391  int i;
3392 
3393  /* Note that we only care if a resource is used or not, not the
3394  * resource's specific type. Otherwise we'd need to call
3395  * shader_update_samplers() here for 1.x pixelshaders. */
3396  if (ps)
3397  ps_resource_info = state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info;
3398 
3399  for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
3400  {
3401  DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3402  if (vs_resource_info[i].type)
3403  {
3404  while (start >= 0)
3405  {
3406  if (context_unit_free_for_vs(context, ps_resource_info, start))
3407  {
3408  if (context->tex_unit_map[vsampler_idx] != start)
3409  {
3410  context_map_stage(context, vsampler_idx, start);
3411  context_invalidate_state(context, STATE_SAMPLER(vsampler_idx));
3412  }
3413 
3414  --start;
3415  break;
3416  }
3417 
3418  --start;
3419  }
3420  if (context->tex_unit_map[vsampler_idx] == WINED3D_UNMAPPED_STAGE)
3421  WARN("Couldn't find a free texture unit for vertex sampler %u.\n", i);
3422  }
3423  }
3424 }
3425 
3426 static void context_update_tex_unit_map(struct wined3d_context *context, const struct wined3d_state *state)
3427 {
3428  const struct wined3d_gl_info *gl_info = context->gl_info;
3429  BOOL vs = use_vs(state);
3430  BOOL ps = use_ps(state);
3431 
3432  if (!ps)
3434 
3435  /* Try to go for a 1:1 mapping of the samplers when possible. Pixel shaders
3436  * need a 1:1 map at the moment.
3437  * When the mapping of a stage is changed, sampler and ALL texture stage
3438  * states have to be reset. */
3439 
3440  if (gl_info->limits.graphics_samplers >= MAX_COMBINED_SAMPLERS)
3441  return;
3442 
3443  if (ps)
3444  context_map_psamplers(context, state);
3445  else
3446  context_map_fixed_function_samplers(context, state);
3447 
3448  if (vs)
3449  context_map_vsamplers(context, ps, state);
3450 }
3451 
3452 /* Context activation is done by the caller. */
3453 void context_state_drawbuf(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
3454 {
3455  DWORD rt_mask, *cur_mask;
3456 
3457  if (isStateDirty(context, STATE_FRAMEBUFFER)) return;
3458 
3459  cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3460  rt_mask = find_draw_buffers_mask(context, state);
3461  if (rt_mask != *cur_mask)
3462  {
3463  context_apply_draw_buffers(context, rt_mask);
3464  *cur_mask = rt_mask;
3465  }
3466 }
3467 
3468 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
3469 {
3470  if ((usage == WINED3D_DECL_USAGE_POSITION || usage == WINED3D_DECL_USAGE_POSITIONT) && !usage_idx)
3471  *regnum = WINED3D_FFP_POSITION;
3472  else if (usage == WINED3D_DECL_USAGE_BLEND_WEIGHT && !usage_idx)
3473  *regnum = WINED3D_FFP_BLENDWEIGHT;
3474  else if (usage == WINED3D_DECL_USAGE_BLEND_INDICES && !usage_idx)
3475  *regnum = WINED3D_FFP_BLENDINDICES;
3476  else if (usage == WINED3D_DECL_USAGE_NORMAL && !usage_idx)
3477  *regnum = WINED3D_FFP_NORMAL;
3478  else if (usage == WINED3D_DECL_USAGE_PSIZE && !usage_idx)
3479  *regnum = WINED3D_FFP_PSIZE;
3480  else if (usage == WINED3D_DECL_USAGE_COLOR && !usage_idx)
3481  *regnum = WINED3D_FFP_DIFFUSE;
3482  else if (usage == WINED3D_DECL_USAGE_COLOR && usage_idx == 1)
3483  *regnum = WINED3D_FFP_SPECULAR;
3484  else if (usage == WINED3D_DECL_USAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
3485  *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
3486  else
3487  {
3488  WARN("Unsupported input stream [usage=%s, usage_idx=%u].\n", debug_d3ddeclusage(usage), usage_idx);
3489  *regnum = ~0u;
3490  return FALSE;
3491  }
3492 
3493  return TRUE;
3494 }
3495 
3496 /* Context activation is done by the caller. */
3498  const struct wined3d_state *state, const struct wined3d_gl_info *gl_info,
3499  const struct wined3d_d3d_info *d3d_info)
3500 {
3501  /* We need to deal with frequency data! */
3503  BOOL generic_attributes = d3d_info->ffp_generic_attributes;
3504  BOOL use_vshader = use_vs(state);
3505  unsigned int i;
3506 
3507  stream_info->use_map = 0;
3508  stream_info->swizzle_map = 0;
3509  stream_info->position_transformed = 0;
3510 
3511  if (!declaration)
3512  return;
3513 
3514  stream_info->position_transformed = declaration->position_transformed;
3515 
3516  /* Translate the declaration into strided data. */
3517  for (i = 0; i < declaration->element_count; ++i)
3518  {
3519  const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
3520  const struct wined3d_stream_state *stream = &state->streams[element->input_slot];
3521  BOOL stride_used;
3522  unsigned int idx;
3523 
3524  TRACE("%p Element %p (%u of %u).\n", declaration->elements,
3525  element, i + 1, declaration->element_count);
3526 
3527  if (!stream->buffer)
3528  continue;
3529 
3530  TRACE("offset %u input_slot %u usage_idx %d.\n", element->offset, element->input_slot, element->usage_idx);
3531 
3532  if (use_vshader)
3533  {
3534  if (element->output_slot == WINED3D_OUTPUT_SLOT_UNUSED)
3535  {
3536  stride_used = FALSE;
3537  }
3538  else if (element->output_slot == WINED3D_OUTPUT_SLOT_SEMANTIC)
3539  {
3540  /* TODO: Assuming vertexdeclarations are usually used with the
3541  * same or a similar shader, it might be worth it to store the
3542  * last used output slot and try that one first. */
3543  stride_used = vshader_get_input(state->shader[WINED3D_SHADER_TYPE_VERTEX],
3544  element->usage, element->usage_idx, &idx);
3545  }
3546  else
3547  {
3548  idx = element->output_slot;
3549  stride_used = TRUE;
3550  }
3551  }
3552  else
3553  {
3554  if (!generic_attributes && !element->ffp_valid)
3555  {
3556  WARN("Skipping unsupported fixed function element of format %s and usage %s.\n",
3557  debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
3558  stride_used = FALSE;
3559  }
3560  else
3561  {
3562  stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
3563  }
3564  }
3565 
3566  if (stride_used)
3567  {
3568  TRACE("Load %s array %u [usage %s, usage_idx %u, "
3569  "input_slot %u, offset %u, stride %u, format %s, class %s, step_rate %u].\n",
3570  use_vshader ? "shader": "fixed function", idx,
3571  debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
3572  element->offset, stream->stride, debug_d3dformat(element->format->id),
3574 
3575  stream_info->elements[idx].format = element->format;
3576  stream_info->elements[idx].data.buffer_object = 0;
3577  stream_info->elements[idx].data.addr = (BYTE *)NULL + stream->offset + element->offset;
3578  stream_info->elements[idx].stride = stream->stride;
3579  stream_info->elements[idx].stream_idx = element->input_slot;
3581  {
3582  stream_info->elements[idx].divisor = 1;
3583  }
3585  {
3586  stream_info->elements[idx].divisor = element->instance_data_step_rate;
3587  if (!element->instance_data_step_rate)
3588  FIXME("Instance step rate 0 not implemented.\n");
3589  }
3590  else
3591  {
3592  stream_info->elements[idx].divisor = 0;
3593  }
3594 
3595  if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
3596  && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
3597  {
3598  stream_info->swizzle_map |= 1u << idx;
3599  }
3600  stream_info->use_map |= 1u << idx;
3601  }
3602  }
3603 }
3604 
3605 /* Context activation is done by the caller. */
3606 static void context_update_stream_info(struct wined3d_context *context, const struct wined3d_state *state)
3607 {
3608  struct wined3d_stream_info *stream_info = &context->stream_info;
3609  const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3610  const struct wined3d_gl_info *gl_info = context->gl_info;
3611  DWORD prev_all_vbo = stream_info->all_vbo;
3612  unsigned int i;
3613  WORD map;
3614 
3615  wined3d_stream_info_from_declaration(stream_info, state, gl_info, d3d_info);
3616 
3617  stream_info->all_vbo = 1;
3618  context->buffer_fence_count = 0;
3619  for (i = 0, map = stream_info->use_map; map; map >>= 1, ++i)
3620  {
3622  struct wined3d_bo_address data;
3623  struct wined3d_buffer *buffer;
3624 
3625  if (!(map & 1))
3626  continue;
3627 
3628  element = &stream_info->elements[i];
3629  buffer = state->streams[element->stream_idx].buffer;
3630 
3631  /* We can't use VBOs if the base vertex index is negative. OpenGL
3632  * doesn't accept negative offsets (or rather offsets bigger than the
3633  * VBO, because the pointer is unsigned), so use system memory
3634  * sources. In most sane cases the pointer - offset will still be > 0,
3635  * otherwise it will wrap around to some big value. Hope that with the
3636  * indices the driver wraps it back internally. If not,
3637  * draw_primitive_immediate_mode() is needed, including a vertex buffer
3638  * path. */
3639  if (state->load_base_vertex_index < 0)
3640  {
3641  WARN_(d3d_perf)("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
3642  state->load_base_vertex_index);
3643  element->data.buffer_object = 0;
3644  element->data.addr += (ULONG_PTR)wined3d_buffer_load_sysmem(buffer, context);
3645  if ((UINT_PTR)element->data.addr < -state->load_base_vertex_index * element->stride)
3646  FIXME("System memory vertex data load offset is negative!\n");
3647  }
3648  else
3649  {
3650  wined3d_buffer_load(buffer, context, state);
3651  wined3d_buffer_get_memory(buffer, &data, buffer->locations);
3652  element->data.buffer_object = data.buffer_object;
3653  element->data.addr += (ULONG_PTR)data.addr;
3654  }
3655 
3656  if (!element->data.buffer_object)
3657  stream_info->all_vbo = 0;
3658 
3659  if (buffer->fence)
3660  context->buffer_fences[context->buffer_fence_count++] = buffer->fence;
3661 
3662  TRACE("Load array %u {%#x:%p}.\n", i, element->data.buffer_object, element->data.addr);
3663  }
3664 
3665  if (prev_all_vbo != stream_info->all_vbo)
3667 
3668  context->use_immediate_mode_draw = FALSE;
3669 
3670  if (stream_info->all_vbo)
3671  return;
3672 
3673  if (use_vs(state))
3674  {
3675  if (state->vertex_declaration->half_float_conv_needed)
3676  {
3677  TRACE("Using immediate mode draw with vertex shaders for FLOAT16 conversion.\n");
3678  context->use_immediate_mode_draw = TRUE;
3679  }
3680  }
3681  else
3682  {
3683  WORD slow_mask = -!d3d_info->ffp_generic_attributes & (1u << WINED3D_FFP_PSIZE);
3684  slow_mask |= -(!gl_info->supported[ARB_VERTEX_ARRAY_BGRA] && !d3d_info->ffp_generic_attributes)
3686 
3687  if ((stream_info->position_transformed && !d3d_info->xyzrhw)
3688  || (stream_info->use_map & slow_mask))
3689  context->use_immediate_mode_draw = TRUE;
3690  }
3691 }
3692 
3693 /* Context activation is done by the caller. */
3694 static void context_preload_texture(struct wined3d_context *context,
3695  const struct wined3d_state *state, unsigned int idx)
3696 {
3697  struct wined3d_texture *texture;
3698 
3699  if (!(texture = state->textures[idx]))
3700  return;
3701 
3702  wined3d_texture_load(texture, context, state->sampler_states[idx][WINED3D_SAMP_SRGB_TEXTURE]);
3703 }
3704 
3705 /* Context activation is done by the caller. */
3706 static void context_preload_textures(struct wined3d_context *context, const struct wined3d_state *state)
3707 {
3708  unsigned int i;
3709 
3710  if (use_vs(state))
3711  {
3712  for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
3713  {
3714  if (state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.resource_info[i].type)
3715  context_preload_texture(context, state, MAX_FRAGMENT_SAMPLERS + i);
3716  }
3717  }
3718 
3719  if (use_ps(state))
3720  {
3721  for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
3722  {
3723  if (state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info[i].type)
3724  context_preload_texture(context, state, i);
3725  }
3726  }
3727  else
3728  {
3729  WORD ffu_map = context->fixed_function_usage_map;
3730 
3731  for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3732  {
3733  if (ffu_map & 1)
3734  context_preload_texture(context, state, i);
3735  }
3736  }
3737 }
3738 
3739 static void context_load_shader_resources(struct wined3d_context *context, const struct wined3d_state *state,
3740  unsigned int shader_mask)
3741 {
3744  struct wined3d_shader *shader;
3745  unsigned int i, j;
3746 
3747  for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
3748  {
3749  if (!(shader_mask & (1u << i)))
3750  continue;
3751 
3752  if (!(shader = state->shader[i]))
3753  continue;
3754 
3755  for (j = 0; j < WINED3D_MAX_CBS; ++j)
3756  {
3757  if (state->cb[i][j])
3758  wined3d_buffer_load(state->cb[i][j], context, state);
3759  }
3760 
3761  for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
3762  {
3763  entry = &shader->reg_maps.sampler_map.entries[j];
3764 
3765  if (!(view = state->shader_resource_view[i][entry->resource_idx]))
3766  continue;
3767 
3768  if (view->resource->type == WINED3D_RTYPE_BUFFER)
3769  wined3d_buffer_load(buffer_from_resource(view->resource), context, state);
3770  else
3772  }
3773  }
3774 }
3775 
3777  const struct wined3d_state *state, enum wined3d_shader_type shader_type)
3778 {
3779  unsigned int bind_idx, shader_sampler_count, base, count, i;
3780  const struct wined3d_device *device = context->device;
3783  const struct wined3d_shader *shader;
3784  struct wined3d_sampler *sampler;
3785  const DWORD *tex_unit_map;
3786 
3787  if (!(shader = state->shader[shader_type]))
3788  return;
3789 
3790  tex_unit_map = context_get_tex_unit_mapping(context,
3791  &shader->reg_maps.shader_version, &base, &count);
3792 
3793  shader_sampler_count = shader->reg_maps.sampler_map.count;
3794  if (shader_sampler_count > count)
3795  FIXME("Shader %p needs %u samplers, but only %u are supported.\n",
3796  shader, shader_sampler_count, count);
3797  count = min(shader_sampler_count, count);
3798 
3799  for (i = 0; i < count; ++i)
3800  {
3801  entry = &shader->reg_maps.sampler_map.entries[i];
3802  bind_idx = base + entry->bind_idx;
3803  if (tex_unit_map)
3804  bind_idx = tex_unit_map[bind_idx];
3805 
3806  if (!(view = state->shader_resource_view[shader_type][entry->resource_idx]))
3807  {
3808  WARN("No resource view bound at index %u, %u.\n", shader_type, entry->resource_idx);
3809  continue;
3810  }
3811 
3812  if (entry->sampler_idx == WINED3D_SAMPLER_DEFAULT)
3813  sampler = device->default_sampler;
3814  else if (!(sampler = state->sampler[shader_type][entry->sampler_idx]))
3815  sampler = device->null_sampler;
3816  wined3d_shader_resource_view_bind(view, bind_idx, sampler, context);
3817  }
3818 }
3819 
3821  const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
3822 {
3824  struct wined3d_texture *texture;
3825  struct wined3d_buffer *buffer;
3826  unsigned int i;
3827 
3828  context->uses_uavs = 0;
3829 
3830  if (!shader)
3831  return;
3832 
3833  for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
3834  {
3835  if (!(view = views[i]))
3836  continue;
3837 
3838  if (view->resource->type == WINED3D_RTYPE_BUFFER)
3839  {
3840  buffer = buffer_from_resource(view->resource);
3843  }
3844  else
3845  {
3846  texture = texture_from_resource(view->resource);
3847  wined3d_texture_load(texture, context, FALSE);
3849  }
3850 
3851  context->uses_uavs = 1;
3852  }
3853 }
3854 
3856  const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
3857 {
3858  const struct wined3d_gl_info *gl_info = context->gl_info;
3860  GLuint texture_name;
3861  unsigned int i;
3862  GLint level;
3863 
3864  if (!shader)
3865  return;
3866 
3867  for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
3868  {
3869  if (!(view = views[i]))
3870  {
3871  if (shader->reg_maps.uav_resource_info[i].type)
3872  WARN("No unordered access view bound at index %u.\n", i);
3873  GL_EXTCALL(glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R8));
3874  continue;
3875  }
3876 
3877  if (view->gl_view.name)
3878  {
3879  texture_name = view->gl_view.name;
3880  level = 0;
3881  }
3882  else if (view->resource->type != WINED3D_RTYPE_BUFFER)
3883  {
3885  texture_name = wined3d_texture_get_texture_name(texture, context, FALSE);
3886  level = view->desc.u.texture.level_idx;
3887  }
3888  else
3889  {
3890  FIXME("Unsupported buffer unordered access view.\n");
3891  GL_EXTCALL(glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R8));
3892  continue;
3893  }
3894 
3895  GL_EXTCALL(glBindImageTexture(i, texture_name, level, GL_TRUE, 0, GL_READ_WRITE,
3896  view->format->glInternal));
3897 
3898  if (view->counter_bo)
3899  GL_EXTCALL(glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, view->counter_bo));
3900  }
3901  checkGLcall("Bind unordered access views");
3902 }
3903 
3905  const struct wined3d_state *state)
3906 {
3907  unsigned int i;
3908 
3909  for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
3910  {
3911  struct wined3d_buffer *buffer;
3912  if (!(buffer = state->stream_output[i].buffer))
3913  continue;
3914 
3915  wined3d_buffer_load(buffer, context, state);
3917  }
3918 }
3919 
3920 /* Context activation is done by the caller. */
3922  const struct wined3d_device *device, const struct wined3d_state *state)
3923 {
3924  const struct StateEntry *state_table = context->state_table;
3925  const struct wined3d_gl_info *gl_info = context->gl_info;
3926  const struct wined3d_fb_state *fb = state->fb;
3927  unsigned int i;
3928  WORD map;
3929 
3930  if (!have_framebuffer_attachment(gl_info->limits.buffers, fb->render_targets, fb->depth_stencil))
3931  {
3933  {
3934  FIXME("OpenGL implementation does not support framebuffers with no attachments.\n");
3935  return FALSE;
3936  }
3937 
3939  }
3940 
3942  {
3944  }
3945 
3946  /* Preload resources before FBO setup. Texture preload in particular may
3947  * result in changes to the current FBO, due to using e.g. FBO blits for
3948  * updating a resource location. */
3949  context_update_tex_unit_map(context, state);
3950  context_preload_textures(context, state);
3954  context_load_stream_output_buffers(context, state);
3955  /* TODO: Right now the dependency on the vertex shader is necessary
3956  * since wined3d_stream_info_from_declaration() depends on the reg_maps of
3957  * the current VS but maybe it's possible to relax the coupling in some
3958  * situations at least. */
3959  if (isStateDirty(context, STATE_VDECL) || isStateDirty(context, STATE_STREAMSRC)
3961  {
3962  context_update_stream_info(context, state);
3963  }
3964  else
3965  {
3966  for (i = 0, map = context->stream_info.use_map; map; map >>= 1, ++i)
3967  {
3968  if (map & 1)
3969  wined3d_buffer_load(state->streams[context->stream_info.elements[i].stream_idx].buffer,
3970  context, state);
3971  }
3972  /* Loading the buffers above may have invalidated the stream info. */
3973  if (isStateDirty(context, STATE_STREAMSRC))
3974  context_update_stream_info(context, state);
3975  }
3976  if (state->index_buffer)
3977  {
3978  if (context->stream_info.all_vbo)
3979  wined3d_buffer_load(state->index_buffer, context, state);
3980  else
3981  wined3d_buffer_load_sysmem(state->index_buffer, context);
3982  }
3983 
3984  for (i = 0; i < context->numDirtyEntries; ++i)
3985  {
3986  DWORD rep = context->dirtyArray[i];
3987  DWORD idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
3988  BYTE shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
3989  context->isStateDirty[idx] &= ~(1u << shift);
3990  state_table[rep].apply(context, state, rep);
3991  }
3992 
3993  if (context->shader_update_mask & ~(1u << WINED3D_SHADER_TYPE_COMPUTE))
3994  {
3995  device->shader_backend->shader_select(device->shader_priv, context, state);
3997  }
3998 
3999  if (context->constant_update_mask)
4000  {
4001  device->shader_backend->shader_load_constants(device->shader_priv, context, state);
4002  context->constant_update_mask = 0;
4003  }
4004 
4005  if (context->update_shader_resource_bindings)
4006  {
4007  for (i = 0; i < WINED3D_SHADER_TYPE_GRAPHICS_COUNT; ++i)
4008  context_bind_shader_resources(context, state, i);
4009  context->update_shader_resource_bindings = 0;
4010  if (gl_info->limits.combined_samplers == gl_info->limits.graphics_samplers)
4012  }
4013 
4015  {
4021  }
4022 
4024  {
4026  }
4027 
4028  context->numDirtyEntries = 0; /* This makes the whole list clean */
4029  context->last_was_blit = FALSE;
4030  context->last_was_ffp_blit = FALSE;
4031 
4032  return TRUE;
4033 }
4034 
4035 static void context_apply_compute_state(struct wined3d_context *context,
4036  const struct wined3d_device *device, const struct wined3d_state *state)
4037 {
4038  const struct StateEntry *state_table = context->state_table;
4039  const struct wined3d_gl_info *gl_info = context->gl_info;
4040  unsigned int state_id, i;
4041 
4045 
4046  for (i = 0, state_id = STATE_COMPUTE_OFFSET; i < ARRAY_SIZE(context->dirty_compute_states); ++i)
4047  {
4048  unsigned int dirty_mask = context->dirty_compute_states[i];
4049  while (dirty_mask)
4050  {
4051  unsigned int current_state_id = state_id + wined3d_bit_scan(&dirty_mask);
4052  state_table[current_state_id].apply(context, state, current_state_id);
4053  }
4054  state_id += sizeof(*context->dirty_compute_states) * CHAR_BIT;
4055  }
4056  memset(context->dirty_compute_states, 0, sizeof(*context->dirty_compute_states));
4057 
4058  if (context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_COMPUTE))
4059  {
4060  device->shader_backend->shader_select_compute(device->shader_priv, context, state);
4062  }
4063 
4065  {
4068  if (gl_info->limits.combined_samplers == gl_info->limits.graphics_samplers)
4069  context->update_shader_resource_bindings = 1;
4070  }
4071 
4073  {
4079  }
4080 
4081  /* Updates to currently bound render targets aren't necessarily coherent
4082  * between the graphics and compute pipelines. Unbind any currently bound
4083  * FBO here to ensure preceding updates to its attachments by the graphics
4084  * pipeline are visible to the compute pipeline.
4085  *
4086  * Without this, the bloom effect in Nier:Automata is too bright on the
4087  * Mesa radeonsi driver, and presumably on other Mesa based drivers. */
4088  context_bind_fbo(context, GL_FRAMEBUFFER, 0);
4090 
4091  context->last_was_blit = FALSE;
4092  context->last_was_ffp_blit = FALSE;
4093 }
4094 
4096 {
4097  const struct wined3d_shader *shader;
4098  if (!(shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]))
4099  return FALSE;
4100  return shader->u.gs.so_desc.element_count;
4101 }
4102 
4104 {
4105  const struct wined3d_gl_info *gl_info = context->gl_info;
4106  if (context->transform_feedback_active)
4107  {
4108  GL_EXTCALL(glEndTransformFeedback());
4109  checkGLcall("glEndTransformFeedback");
4110  context->transform_feedback_active = 0;
4111  context->transform_feedback_paused = 0;
4112  }
4113 }
4114 
4115 static void context_pause_transform_feedback(struct wined3d_context *context, BOOL force)
4116 {
4117  const struct wined3d_gl_info *gl_info = context->gl_info;
4118 
4119  if (!context->transform_feedback_active || context->transform_feedback_paused)
4120  return;
4121 
4122  if (gl_info->supported[ARB_TRANSFORM_FEEDBACK2])
4123  {
4124  GL_EXTCALL(glPauseTransformFeedback());
4125  checkGLcall("glPauseTransformFeedback");
4126  context->transform_feedback_paused = 1;
4127  return;
4128  }
4129 
4130  WARN("Cannot pause transform feedback operations.\n");
4131 
4132  if (force)
4134 }
4135 
4136 static void context_setup_target(struct wined3d_context *context,
4137  struct wined3d_texture *texture, unsigned int sub_resource_idx)
4138 {
4139  BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
4140 
4141  render_offscreen = wined3d_resource_is_offscreen(&texture->resource);
4142  if (context->current_rt.texture == texture
4143  && context->current_rt.sub_resource_idx == sub_resource_idx
4144  && render_offscreen == old_render_offscreen)
4145  return;
4146 
4147  /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
4148  * the alpha blend state changes with different render target formats. */
4149  if (!context->current_rt.texture)
4150  {
4152  }
4153  else
4154  {
4155  const struct wined3d_format *old = context->current_rt.texture->resource.format;
4156  const struct wined3d_format *new = texture->resource.format;
4157 
4158  if (old->id != new->id)
4159  {
4160  /* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
4161  if ((old->alpha_size && !new->alpha_size) || (!old->alpha_size && new->alpha_size)
4162  || !(texture->resource.format_flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
4164 
4165  /* Update sRGB writing when switching between formats that do/do not support sRGB writing */
4166  if ((context->current_rt.texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE)
4167  != (texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE))
4169  }
4170 
4171  /* When switching away from an offscreen render target, and we're not
4172  * using FBOs, we have to read the drawable into the texture. This is
4173  * done via PreLoad (and WINED3D_LOCATION_DRAWABLE set on the surface).
4174  * There are some things that need care though. PreLoad needs a GL context,
4175  * and FindContext is called before the context is activated. It also
4176  * has to be called with the old rendertarget active, otherwise a
4177  * wrong drawable is read. */
4179  && old_render_offscreen && (context->current_rt.texture != texture
4180  || context->current_rt.sub_resource_idx != sub_resource_idx))
4181  {
4182  unsigned int prev_sub_resource_idx = context->current_rt.sub_resource_idx;
4183  struct wined3d_texture *prev_texture = context->current_rt.texture;
4184 
4185  /* Read the back buffer of the old drawable into the destination texture. */
4186  if (prev_texture->texture_srgb.name)
4187  wined3d_texture_load(prev_texture, context, TRUE);
4188  wined3d_texture_load(prev_texture, context, FALSE);
4189  wined3d_texture_invalidate_location(prev_texture, prev_sub_resource_idx, WINED3D_LOCATION_DRAWABLE);
4190  }
4191  }
4192 
4193  context->current_rt.texture = texture;
4194  context->current_rt.sub_resource_idx = sub_resource_idx;
4195  context_set_render_offscreen(context, render_offscreen);
4196 }
4197 
4198 static void context_activate(struct wined3d_context *context,
4199  struct wined3d_texture *texture, unsigned int sub_resource_idx)
4200 {
4201  context_enter(context);
4202  context_update_window(context);
4203  context_setup_target(context, texture, sub_resource_idx);
4204  if (!context->valid)
4205  return;
4206 
4207  if (context != context_get_current())
4208  {
4209  if (!context_set_current(context))
4210  ERR("Failed to activate the new context.\n");
4211  }
4212  else if (context->needs_set)
4213  {
4214  context_set_gl_context(context);
4215  }
4216 }
4217 
4219  struct wined3d_texture *texture, unsigned int sub_resource_idx)
4220 {
4221  struct wined3d_context *current_context = context_get_current();
4222  struct wined3d_context *context;
4223  BOOL swapchain_texture;
4224 
4225  TRACE("device %p, texture %p, sub_resource_idx %u.\n", device, texture, sub_resource_idx);
4226 
4227  wined3d_from_cs(device->cs);
4228 
4229  if (current_context && current_context->destroyed)
4230  current_context = NULL;
4231 
4232  swapchain_texture = texture && texture->swapchain;
4233  if (!texture)
4234  {
4235  if (current_context
4236  && current_context->current_rt.texture
4237  && current_context->device == device)
4238  {
4239  texture = current_context->current_rt.texture;
4240  sub_resource_idx = current_context->current_rt.sub_resource_idx;
4241  }
4242  else
4243  {
4244  struct wined3d_swapchain *swapchain = device->swapchains[0];
4245 
4246  if (swapchain->back_buffers)
4247  texture = swapchain->back_buffers[0];
4248  else
4249  texture = swapchain->front_buffer;
4250  sub_resource_idx = 0;
4251  }
4252  }
4253 
4254  if (current_context && current_context->current_rt.texture == texture)
4255  {
4256  context = current_context;
4257  }
4258  else if (swapchain_texture)
4259  {
4260  TRACE("Rendering onscreen.\n");
4261 
4262  context = swapchain_get_context(texture->swapchain);
4263  }
4264  else
4265  {
4266  TRACE("Rendering offscreen.\n");
4267 
4268  /* Stay with the current context if possible. Otherwise use the
4269  * context for the primary swapchain. */
4270  if (current_context && current_context->device == device)
4271  context = current_context;
4272  else
4273  context = swapchain_get_context(device->swapchains[0]);
4274  }
4275 
4276  context_activate(context, texture, sub_resource_idx);
4277 
4278  return context;
4279 }
4280 
4282  struct wined3d_context *context)
4283 {
4284  struct wined3d_context *acquired_context;
4285 
4286  wined3d_from_cs(device->cs);
4287 
4288  if (!context || context->tid != GetCurrentThreadId())
4289  return NULL;
4290 
4291  if (context->current_rt.texture)
4292  {
4293  context_activate(context, context->current_rt.texture, context->current_rt.sub_resource_idx);
4294  return context;
4295  }
4296 
4297  acquired_context = context_acquire(device, NULL, 0);
4298  if (acquired_context != context)
4299  ERR("Acquired context %p instead of %p.\n", acquired_context, context);
4300  return acquired_context;
4301 }
4302 
4304  const struct wined3d_dispatch_parameters *parameters)
4305 {
4306  const struct wined3d_gl_info *gl_info;
4307  struct wined3d_context *context;
4308 
4309  context = context_acquire(device, NULL, 0);
4310  if (!context->valid)
4311  {
4312  context_release(context);
4313  WARN("Invalid context, skipping dispatch.\n");
4314  return;
4315  }
4316  gl_info = context->gl_info;
4317 
4318  if (!gl_info->supported[ARB_COMPUTE_SHADER])
4319  {
4320  context_release(context);
4321  FIXME("OpenGL implementation does not support compute shaders.\n");
4322  return;
4323  }
4324 
4325  if (parameters->indirect)
4326  wined3d_buffer_load(parameters->u.indirect.buffer, context, state);
4327 
4328  context_apply_compute_state(context, device, state);
4329 
4330  if (!state->shader[WINED3D_SHADER_TYPE_COMPUTE])
4331  {
4332  context_release(context);
4333  WARN("No compute shader bound, skipping dispatch.\n");
4334  return;
4335  }
4336 
4337  if (parameters->indirect)
4338  {
4339  const struct wined3d_indirect_dispatch_parameters *indirect = &parameters->u.indirect;
4340  struct wined3d_buffer *buffer = indirect->buffer;
4341 
4342  GL_EXTCALL(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer->buffer_object));
4343  GL_EXTCALL(glDispatchComputeIndirect((GLintptr)indirect->offset));
4344  GL_EXTCALL(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0));
4345  }
4346  else
4347  {
4348  const struct wined3d_direct_dispatch_parameters *direct = &parameters->u.direct;
4349  GL_EXTCALL(glDispatchCompute(direct->group_count_x, direct->group_count_y, direct->group_count_z));
4350  }
4351  checkGLcall("dispatch compute");
4352 
4353  GL_EXTCALL(glMemoryBarrier(GL_ALL_BARRIER_BITS));
4354  checkGLcall("glMemoryBarrier");
4355 
4356  context_release(context);
4357 }
4358 
4359 /* Context activation is done by the caller. */
4360 static void draw_primitive_arrays(struct wined3d_context *context, const struct wined3d_state *state,
4361  const void *idx_data, unsigned int idx_size, int base_vertex_idx, unsigned int start_idx,
4362  unsigned int count, unsigned int start_instance, unsigned int instance_count)
4363 {
4364  const struct wined3d_ffp_attrib_ops *ops = &context->d3d_info->ffp_attrib_ops;
4365  GLenum idx_type = idx_size == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
4366  const struct wined3d_stream_info *si = &context->stream_info;
4367  unsigned int instanced_elements[ARRAY_SIZE(si->elements)];
4368  const struct wined3d_gl_info *gl_info = context->gl_info;
4369  unsigned int instanced_element_count = 0;
4370  GLenum mode = state->gl_primitive_type;
4371  const void *indices;
4372  unsigned int i, j;
4373 
4374  indices = (const char *)idx_data + idx_size * start_idx;
4375 
4376  if (!instance_count)
4377  {
4378  if (!idx_size)
4379  {
4380  gl_info->gl_ops.gl.p_glDrawArrays(mode, start_idx, count);
4381  checkGLcall("glDrawArrays");
4382  return;
4383  }
4384 
4386  {
4387  GL_EXTCALL(glDrawElementsBaseVertex(mode, count, idx_type, indices, base_vertex_idx));