xref: /reactos/dll/directx/wine/wined3d/context.c (revision 81cffd76)
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 
41 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
42 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
43 WINE_DECLARE_DEBUG_CHANNEL(d3d_synchronous);
44 
45 #define WINED3D_MAX_FBO_ENTRIES 64
46 #define WINED3D_ALL_LAYERS (~0u)
47 
48 static DWORD wined3d_context_tls_idx;
49 
50 /* FBO helper functions */
51 
52 /* Context activation is done by the caller. */
context_bind_fbo(struct wined3d_context * context,GLenum target,GLuint fbo)53 static void context_bind_fbo(struct wined3d_context *context, GLenum target, GLuint fbo)
54 {
55     const struct wined3d_gl_info *gl_info = context->gl_info;
56 
57     switch (target)
58     {
59         case GL_READ_FRAMEBUFFER:
60             if (context->fbo_read_binding == fbo) return;
61             context->fbo_read_binding = fbo;
62             break;
63 
64         case GL_DRAW_FRAMEBUFFER:
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. */
context_clean_fbo_attachments(const struct wined3d_gl_info * gl_info,GLenum target)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. */
context_destroy_fbo(struct wined3d_context * context,GLuint fbo)103 static void context_destroy_fbo(struct wined3d_context *context, GLuint fbo)
104 {
105     const struct wined3d_gl_info *gl_info = context->gl_info;
106 
107     context_bind_fbo(context, GL_FRAMEBUFFER, fbo);
108     context_clean_fbo_attachments(gl_info, GL_FRAMEBUFFER);
109     context_bind_fbo(context, GL_FRAMEBUFFER, 0);
110 
111     gl_info->fbo_ops.glDeleteFramebuffers(1, &fbo);
112     checkGLcall("glDeleteFramebuffers()");
113 }
114 
context_attach_depth_stencil_rb(const struct wined3d_gl_info * gl_info,GLenum fbo_target,DWORD flags,GLuint rb)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 
context_attach_gl_texture_fbo(struct wined3d_context * context,GLenum fbo_target,GLenum attachment,const struct wined3d_fbo_resource * resource)131 static void context_attach_gl_texture_fbo(struct wined3d_context *context,
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         checkGLcall("glFramebufferTexture1D()");
168     }
169     else
170     {
171         gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, attachment,
172                 resource->target, resource->object, resource->level);
173     }
174     checkGLcall("attach texture to fbo");
175 }
176 
177 /* Context activation is done by the caller. */
context_attach_depth_stencil_fbo(struct wined3d_context * context,GLenum fbo_target,const struct wined3d_fbo_resource * resource,BOOL rb_namespace,DWORD flags)178 static void context_attach_depth_stencil_fbo(struct wined3d_context *context,
179         GLenum fbo_target, const struct wined3d_fbo_resource *resource, BOOL rb_namespace,
180         DWORD flags)
181 {
182     const struct wined3d_gl_info *gl_info = context->gl_info;
183 
184     if (resource->object)
185     {
186         TRACE("Attach depth stencil %u.\n", resource->object);
187 
188         if (rb_namespace)
189         {
190             context_attach_depth_stencil_rb(gl_info, fbo_target,
191                     flags, resource->object);
192         }
193         else
194         {
195             if (flags & WINED3D_FBO_ENTRY_FLAG_DEPTH)
196                 context_attach_gl_texture_fbo(context, fbo_target, GL_DEPTH_ATTACHMENT, resource);
197 
198             if (flags & WINED3D_FBO_ENTRY_FLAG_STENCIL)
199                 context_attach_gl_texture_fbo(context, fbo_target, GL_STENCIL_ATTACHMENT, resource);
200         }
201 
202         if (!(flags & WINED3D_FBO_ENTRY_FLAG_DEPTH))
203             context_attach_gl_texture_fbo(context, fbo_target, GL_DEPTH_ATTACHMENT, NULL);
204 
205         if (!(flags & WINED3D_FBO_ENTRY_FLAG_STENCIL))
206             context_attach_gl_texture_fbo(context, fbo_target, GL_STENCIL_ATTACHMENT, NULL);
207     }
208     else
209     {
210         TRACE("Attach depth stencil 0.\n");
211 
212         context_attach_gl_texture_fbo(context, fbo_target, GL_DEPTH_ATTACHMENT, NULL);
213         context_attach_gl_texture_fbo(context, fbo_target, GL_STENCIL_ATTACHMENT, NULL);
214     }
215 }
216 
217 /* Context activation is done by the caller. */
context_attach_surface_fbo(struct wined3d_context * context,GLenum fbo_target,DWORD idx,const struct wined3d_fbo_resource * resource,BOOL rb_namespace)218 static void context_attach_surface_fbo(struct wined3d_context *context,
219         GLenum fbo_target, DWORD idx, const struct wined3d_fbo_resource *resource, BOOL rb_namespace)
220 {
221     const struct wined3d_gl_info *gl_info = context->gl_info;
222 
223     TRACE("Attach GL object %u to %u.\n", resource->object, idx);
224 
225     if (resource->object)
226     {
227         if (rb_namespace)
228         {
229             gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
230                     GL_RENDERBUFFER, resource->object);
231             checkGLcall("glFramebufferRenderbuffer()");
232         }
233         else
234         {
235             context_attach_gl_texture_fbo(context, fbo_target, GL_COLOR_ATTACHMENT0 + idx, resource);
236         }
237     }
238     else
239     {
240         context_attach_gl_texture_fbo(context, fbo_target, GL_COLOR_ATTACHMENT0 + idx, NULL);
241     }
242 }
243 
context_dump_fbo_attachment(const struct wined3d_gl_info * gl_info,GLenum target,GLenum attachment)244 static void context_dump_fbo_attachment(const struct wined3d_gl_info *gl_info, GLenum target,
245         GLenum attachment)
246 {
247     static const struct
248     {
249         GLenum target;
250         GLenum binding;
251         const char *str;
252         enum wined3d_gl_extension extension;
253     }
254     texture_type[] =
255     {
256         {GL_TEXTURE_2D,                   GL_TEXTURE_BINDING_2D,                   "2d",          WINED3D_GL_EXT_NONE},
257         {GL_TEXTURE_RECTANGLE_ARB,        GL_TEXTURE_BINDING_RECTANGLE_ARB,        "rectangle",   ARB_TEXTURE_RECTANGLE},
258         {GL_TEXTURE_2D_ARRAY,             GL_TEXTURE_BINDING_2D_ARRAY,             "2d-array" ,   EXT_TEXTURE_ARRAY},
259         {GL_TEXTURE_CUBE_MAP,             GL_TEXTURE_BINDING_CUBE_MAP,             "cube",        ARB_TEXTURE_CUBE_MAP},
260         {GL_TEXTURE_2D_MULTISAMPLE,       GL_TEXTURE_BINDING_2D_MULTISAMPLE,       "2d-ms",       ARB_TEXTURE_MULTISAMPLE},
261         {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, "2d-array-ms", ARB_TEXTURE_MULTISAMPLE},
262     };
263 
264     GLint type, name, samples, width, height, old_texture, level, face, fmt, tex_target;
265     const char *tex_type_str;
266     unsigned int i;
267 
268     gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
269             GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &name);
270     gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
271             GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
272 
273     if (type == GL_RENDERBUFFER)
274     {
275         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, name);
276         gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
277         gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
278         if (gl_info->limits.samples > 1)
279             gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
280         else
281             samples = 1;
282         gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_INTERNAL_FORMAT, &fmt);
283         FIXME("    %s: renderbuffer %d, %dx%d, %d samples, format %#x.\n",
284                 debug_fboattachment(attachment), name, width, height, samples, fmt);
285     }
286     else if (type == GL_TEXTURE)
287     {
288         gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
289                 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &level);
290         gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
291                 GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, &face);
292 
293         if (gl_info->gl_ops.ext.p_glGetTextureParameteriv)
294         {
295             GL_EXTCALL(glGetTextureParameteriv(name, GL_TEXTURE_TARGET, &tex_target));
296 
297             for (i = 0; i < ARRAY_SIZE(texture_type); ++i)
298             {
299                 if (texture_type[i].target == tex_target)
300                 {
301                     tex_type_str = texture_type[i].str;
302                     break;
303                 }
304             }
305             if (i == ARRAY_SIZE(texture_type))
306                 tex_type_str = wine_dbg_sprintf("%#x", tex_target);
307         }
308         else if (face)
309         {
310             gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &old_texture);
311             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, name);
312 
313             tex_target = GL_TEXTURE_CUBE_MAP;
314             tex_type_str = "cube";
315         }
316         else
317         {
318             tex_type_str = NULL;
319 
320             for (i = 0; i < ARRAY_SIZE(texture_type); ++i)
321             {
322                 if (!gl_info->supported[texture_type[i].extension])
323                     continue;
324 
325                 gl_info->gl_ops.gl.p_glGetIntegerv(texture_type[i].binding, &old_texture);
326                 while (gl_info->gl_ops.gl.p_glGetError());
327 
328                 gl_info->gl_ops.gl.p_glBindTexture(texture_type[i].target, name);
329                 if (!gl_info->gl_ops.gl.p_glGetError())
330                 {
331                     tex_target = texture_type[i].target;
332                     tex_type_str = texture_type[i].str;
333                     break;
334                 }
335                 gl_info->gl_ops.gl.p_glBindTexture(texture_type[i].target, old_texture);
336             }
337 
338             if (!tex_type_str)
339             {
340                 FIXME("Cannot find type of texture %d.\n", name);
341                 return;
342             }
343         }
344 
345         if (gl_info->gl_ops.ext.p_glGetTextureParameteriv)
346         {
347             GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_INTERNAL_FORMAT, &fmt));
348             GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_WIDTH, &width));
349             GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_HEIGHT, &height));
350             GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_SAMPLES, &samples));
351         }
352         else
353         {
354             gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_INTERNAL_FORMAT, &fmt);
355             gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_WIDTH, &width);
356             gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_HEIGHT, &height);
357             if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
358                 gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_SAMPLES, &samples);
359             else
360                 samples = 1;
361 
362             gl_info->gl_ops.gl.p_glBindTexture(tex_target, old_texture);
363         }
364 
365         FIXME("    %s: %s texture %d, %dx%d, %d samples, format %#x.\n",
366                 debug_fboattachment(attachment), tex_type_str, name, width, height, samples, fmt);
367     }
368     else if (type == GL_NONE)
369     {
370         FIXME("    %s: NONE.\n", debug_fboattachment(attachment));
371     }
372     else
373     {
374         ERR("    %s: Unknown attachment %#x.\n", debug_fboattachment(attachment), type);
375     }
376 
377     checkGLcall("dump FBO attachment");
378 }
379 
380 /* Context activation is done by the caller. */
context_check_fbo_status(const struct wined3d_context * context,GLenum target)381 void context_check_fbo_status(const struct wined3d_context *context, GLenum target)
382 {
383     const struct wined3d_gl_info *gl_info = context->gl_info;
384     GLenum status;
385 
386     if (!FIXME_ON(d3d))
387         return;
388 
389     status = gl_info->fbo_ops.glCheckFramebufferStatus(target);
390     if (status == GL_FRAMEBUFFER_COMPLETE)
391     {
392         TRACE("FBO complete.\n");
393     }
394     else
395     {
396         unsigned int i;
397 
398         FIXME("FBO status %s (%#x).\n", debug_fbostatus(status), status);
399 
400         if (!context->current_fbo)
401         {
402             ERR("FBO 0 is incomplete, driver bug?\n");
403             return;
404         }
405 
406         context_dump_fbo_attachment(gl_info, target, GL_DEPTH_ATTACHMENT);
407         context_dump_fbo_attachment(gl_info, target, GL_STENCIL_ATTACHMENT);
408 
409         for (i = 0; i < gl_info->limits.buffers; ++i)
410             context_dump_fbo_attachment(gl_info, target, GL_COLOR_ATTACHMENT0 + i);
411     }
412 }
413 
context_generate_rt_mask(GLenum buffer)414 static inline DWORD context_generate_rt_mask(GLenum buffer)
415 {
416     /* Should take care of all the GL_FRONT/GL_BACK/GL_AUXi/GL_NONE... cases */
417     return buffer ? (1u << 31) | buffer : 0;
418 }
419 
context_generate_rt_mask_from_resource(struct wined3d_resource * resource)420 static inline DWORD context_generate_rt_mask_from_resource(struct wined3d_resource *resource)
421 {
422     if (resource->type != WINED3D_RTYPE_TEXTURE_2D)
423     {
424         FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
425         return 0;
426     }
427 
428     return (1u << 31) | wined3d_texture_get_gl_buffer(texture_from_resource(resource));
429 }
430 
context_set_fbo_key_for_render_target(const struct wined3d_context * context,struct wined3d_fbo_entry_key * key,unsigned int idx,const struct wined3d_rendertarget_info * render_target,DWORD location)431 static inline void context_set_fbo_key_for_render_target(const struct wined3d_context *context,
432         struct wined3d_fbo_entry_key *key, unsigned int idx, const struct wined3d_rendertarget_info *render_target,
433         DWORD location)
434 {
435     unsigned int sub_resource_idx = render_target->sub_resource_idx;
436     struct wined3d_resource *resource = render_target->resource;
437     struct wined3d_texture *texture;
438 
439     if (!resource || resource->format->id == WINED3DFMT_NULL || resource->type == WINED3D_RTYPE_BUFFER)
440     {
441         if (resource && resource->type == WINED3D_RTYPE_BUFFER)
442             FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
443         key->objects[idx].object = 0;
444         key->objects[idx].target = 0;
445         key->objects[idx].level = key->objects[idx].layer = 0;
446         return;
447     }
448 
449     if (render_target->gl_view.name)
450     {
451         key->objects[idx].object = render_target->gl_view.name;
452         key->objects[idx].target = render_target->gl_view.target;
453         key->objects[idx].level = 0;
454         key->objects[idx].layer = WINED3D_ALL_LAYERS;
455         return;
456     }
457 
458     texture = wined3d_texture_from_resource(resource);
459     if (resource->type == WINED3D_RTYPE_TEXTURE_2D)
460     {
461         struct wined3d_surface *surface = texture->sub_resources[sub_resource_idx].u.surface;
462 
463         if (surface->current_renderbuffer)
464         {
465             key->objects[idx].object = surface->current_renderbuffer->id;
466             key->objects[idx].target = 0;
467             key->objects[idx].level = key->objects[idx].layer = 0;
468             key->rb_namespace |= 1 << idx;
469             return;
470         }
471     }
472     key->objects[idx].target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx);
473     key->objects[idx].level = sub_resource_idx % texture->level_count;
474     key->objects[idx].layer = sub_resource_idx / texture->level_count;
475 
476     if (render_target->layer_count != 1)
477         key->objects[idx].layer = WINED3D_ALL_LAYERS;
478 
479     switch (location)
480     {
481         case WINED3D_LOCATION_TEXTURE_RGB:
482             key->objects[idx].object = wined3d_texture_get_texture_name(texture, context, FALSE);
483             break;
484 
485         case WINED3D_LOCATION_TEXTURE_SRGB:
486             key->objects[idx].object = wined3d_texture_get_texture_name(texture, context, TRUE);
487             break;
488 
489         case WINED3D_LOCATION_RB_MULTISAMPLE:
490             key->objects[idx].object = texture->rb_multisample;
491             key->objects[idx].target = 0;
492             key->objects[idx].level = key->objects[idx].layer = 0;
493             key->rb_namespace |= 1 << idx;
494             break;
495 
496         case WINED3D_LOCATION_RB_RESOLVED:
497             key->objects[idx].object = texture->rb_resolved;
498             key->objects[idx].target = 0;
499             key->objects[idx].level = key->objects[idx].layer = 0;
500             key->rb_namespace |= 1 << idx;
501             break;
502     }
503 }
504 
context_generate_fbo_key(const struct wined3d_context * context,struct wined3d_fbo_entry_key * key,const struct wined3d_rendertarget_info * render_targets,const struct wined3d_rendertarget_info * depth_stencil,DWORD color_location,DWORD ds_location)505 static void context_generate_fbo_key(const struct wined3d_context *context,
506         struct wined3d_fbo_entry_key *key, const struct wined3d_rendertarget_info *render_targets,
507         const struct wined3d_rendertarget_info *depth_stencil, DWORD color_location, DWORD ds_location)
508 {
509     unsigned int buffers = context->gl_info->limits.buffers;
510     unsigned int i;
511 
512     key->rb_namespace = 0;
513     context_set_fbo_key_for_render_target(context, key, 0, depth_stencil, ds_location);
514 
515     for (i = 0; i < buffers; ++i)
516         context_set_fbo_key_for_render_target(context, key, i + 1, &render_targets[i], color_location);
517 
518     memset(&key->objects[buffers + 1], 0, (ARRAY_SIZE(key->objects) - buffers - 1) * sizeof(*key->objects));
519 }
520 
context_create_fbo_entry(const struct wined3d_context * context,const struct wined3d_rendertarget_info * render_targets,const struct wined3d_rendertarget_info * depth_stencil,DWORD color_location,DWORD ds_location)521 static struct fbo_entry *context_create_fbo_entry(const struct wined3d_context *context,
522         const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
523         DWORD color_location, DWORD ds_location)
524 {
525     const struct wined3d_gl_info *gl_info = context->gl_info;
526     struct fbo_entry *entry;
527 
528     entry = heap_alloc(sizeof(*entry));
529     context_generate_fbo_key(context, &entry->key, render_targets, depth_stencil, color_location, ds_location);
530     entry->flags = 0;
531     if (depth_stencil->resource)
532     {
533         if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_DEPTH)
534             entry->flags |= WINED3D_FBO_ENTRY_FLAG_DEPTH;
535         if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_STENCIL)
536             entry->flags |= WINED3D_FBO_ENTRY_FLAG_STENCIL;
537     }
538     entry->rt_mask = context_generate_rt_mask(GL_COLOR_ATTACHMENT0);
539     gl_info->fbo_ops.glGenFramebuffers(1, &entry->id);
540     checkGLcall("glGenFramebuffers()");
541     TRACE("Created FBO %u.\n", entry->id);
542 
543     return entry;
544 }
545 
546 /* Context activation is done by the caller. */
context_reuse_fbo_entry(struct wined3d_context * context,GLenum target,const struct wined3d_rendertarget_info * render_targets,const struct wined3d_rendertarget_info * depth_stencil,DWORD color_location,DWORD ds_location,struct fbo_entry * entry)547 static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum target,
548         const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
549         DWORD color_location, DWORD ds_location, struct fbo_entry *entry)
550 {
551     const struct wined3d_gl_info *gl_info = context->gl_info;
552 
553     context_bind_fbo(context, target, entry->id);
554     context_clean_fbo_attachments(gl_info, target);
555 
556     context_generate_fbo_key(context, &entry->key, render_targets, depth_stencil, color_location, ds_location);
557     entry->flags = 0;
558     if (depth_stencil->resource)
559     {
560         if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_DEPTH)
561             entry->flags |= WINED3D_FBO_ENTRY_FLAG_DEPTH;
562         if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_STENCIL)
563             entry->flags |= WINED3D_FBO_ENTRY_FLAG_STENCIL;
564     }
565 }
566 
567 /* Context activation is done by the caller. */
context_destroy_fbo_entry(struct wined3d_context * context,struct fbo_entry * entry)568 static void context_destroy_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
569 {
570     if (entry->id)
571     {
572         TRACE("Destroy FBO %u.\n", entry->id);
573         context_destroy_fbo(context, entry->id);
574     }
575     --context->fbo_entry_count;
576     list_remove(&entry->entry);
577     heap_free(entry);
578 }
579 
580 /* Context activation is done by the caller. */
context_find_fbo_entry(struct wined3d_context * context,GLenum target,const struct wined3d_rendertarget_info * render_targets,const struct wined3d_rendertarget_info * depth_stencil,DWORD color_location,DWORD ds_location)581 static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, GLenum target,
582         const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
583         DWORD color_location, DWORD ds_location)
584 {
585     static const struct wined3d_rendertarget_info ds_null = {{0}};
586     const struct wined3d_gl_info *gl_info = context->gl_info;
587     struct wined3d_texture *rt_texture, *ds_texture;
588     struct wined3d_fbo_entry_key fbo_key;
589     unsigned int i, ds_level, rt_level;
590     struct fbo_entry *entry;
591 
592     if (depth_stencil->resource && depth_stencil->resource->type != WINED3D_RTYPE_BUFFER
593             && render_targets[0].resource && render_targets[0].resource->type != WINED3D_RTYPE_BUFFER)
594     {
595         rt_texture = wined3d_texture_from_resource(render_targets[0].resource);
596         rt_level = render_targets[0].sub_resource_idx % rt_texture->level_count;
597         ds_texture = wined3d_texture_from_resource(depth_stencil->resource);
598         ds_level = depth_stencil->sub_resource_idx % ds_texture->level_count;
599 
600         if (wined3d_texture_get_level_width(ds_texture, ds_level)
601                 < wined3d_texture_get_level_width(rt_texture, rt_level)
602                 || wined3d_texture_get_level_height(ds_texture, ds_level)
603                 < wined3d_texture_get_level_height(rt_texture, rt_level))
604         {
605             WARN("Depth stencil is smaller than the primary color buffer, disabling.\n");
606             depth_stencil = &ds_null;
607         }
608         else if (ds_texture->resource.multisample_type != rt_texture->resource.multisample_type
609                 || ds_texture->resource.multisample_quality != rt_texture->resource.multisample_quality)
610         {
611             WARN("Color multisample type %u and quality %u, depth stencil has %u and %u, disabling ds buffer.\n",
612                     rt_texture->resource.multisample_type, rt_texture->resource.multisample_quality,
613                     ds_texture->resource.multisample_type, ds_texture->resource.multisample_quality);
614             depth_stencil = &ds_null;
615         }
616         else if (depth_stencil->resource->type == WINED3D_RTYPE_TEXTURE_2D)
617         {
618             struct wined3d_surface *surface;
619 
620             surface = ds_texture->sub_resources[depth_stencil->sub_resource_idx].u.surface;
621             surface_set_compatible_renderbuffer(surface, &render_targets[0]);
622         }
623     }
624 
625     context_generate_fbo_key(context, &fbo_key, render_targets, depth_stencil, color_location, ds_location);
626 
627     if (TRACE_ON(d3d))
628     {
629         struct wined3d_resource *resource;
630         unsigned int width, height;
631         const char *resource_type;
632 
633         TRACE("Dumping FBO attachments:\n");
634         for (i = 0; i < gl_info->limits.buffers; ++i)
635         {
636             if ((resource = render_targets[i].resource))
637             {
638                 if (resource->type == WINED3D_RTYPE_BUFFER)
639                 {
640                     width = resource->size;
641                     height = 1;
642                     resource_type = "buffer";
643                 }
644                 else
645                 {
646                     rt_texture = wined3d_texture_from_resource(resource);
647                     rt_level = render_targets[i].sub_resource_idx % rt_texture->level_count;
648                     width = wined3d_texture_get_level_pow2_width(rt_texture, rt_level);
649                     height = wined3d_texture_get_level_pow2_height(rt_texture, rt_level);
650                     resource_type = "texture";
651                 }
652 
653                 TRACE("    Color attachment %u: %p, %u format %s, %s %u, %ux%u, %u samples.\n",
654                         i, resource, render_targets[i].sub_resource_idx, debug_d3dformat(resource->format->id),
655                         fbo_key.rb_namespace & (1 << (i + 1)) ? "renderbuffer" : resource_type,
656                         fbo_key.objects[i + 1].object, width, height, resource->multisample_type);
657             }
658         }
659         if ((resource = depth_stencil->resource))
660         {
661             if (resource->type == WINED3D_RTYPE_BUFFER)
662             {
663                 width = resource->size;
664                 height = 1;
665                 resource_type = "buffer";
666             }
667             else
668             {
669                 ds_texture = wined3d_texture_from_resource(resource);
670                 ds_level = depth_stencil->sub_resource_idx % ds_texture->level_count;
671                 width = wined3d_texture_get_level_pow2_width(ds_texture, ds_level);
672                 height = wined3d_texture_get_level_pow2_height(ds_texture, ds_level);
673                 resource_type = "texture";
674             }
675 
676             TRACE("    Depth attachment: %p, %u format %s, %s %u, %ux%u, %u samples.\n",
677                     resource, depth_stencil->sub_resource_idx, debug_d3dformat(resource->format->id),
678                     fbo_key.rb_namespace & (1 << 0) ? "renderbuffer" : resource_type,
679                     fbo_key.objects[0].object, width, height, resource->multisample_type);
680         }
681     }
682 
683     LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
684     {
685         if (memcmp(&fbo_key, &entry->key, sizeof(fbo_key)))
686             continue;
687 
688         list_remove(&entry->entry);
689         list_add_head(&context->fbo_list, &entry->entry);
690         return entry;
691     }
692 
693     if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES)
694     {
695         entry = context_create_fbo_entry(context, render_targets, depth_stencil, color_location, ds_location);
696         list_add_head(&context->fbo_list, &entry->entry);
697         ++context->fbo_entry_count;
698     }
699     else
700     {
701         entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry);
702         context_reuse_fbo_entry(context, target, render_targets, depth_stencil, color_location, ds_location, entry);
703         list_remove(&entry->entry);
704         list_add_head(&context->fbo_list, &entry->entry);
705     }
706 
707     return entry;
708 }
709 
710 /* Context activation is done by the caller. */
context_apply_fbo_entry(struct wined3d_context * context,GLenum target,struct fbo_entry * entry)711 static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
712 {
713     const struct wined3d_gl_info *gl_info = context->gl_info;
714     GLuint read_binding, draw_binding;
715     unsigned int i;
716 
717     if (entry->flags & WINED3D_FBO_ENTRY_FLAG_ATTACHED)
718     {
719         context_bind_fbo(context, target, entry->id);
720         return;
721     }
722 
723     read_binding = context->fbo_read_binding;
724     draw_binding = context->fbo_draw_binding;
725     context_bind_fbo(context, GL_FRAMEBUFFER, entry->id);
726 
727     if (gl_info->supported[ARB_FRAMEBUFFER_NO_ATTACHMENTS])
728     {
729         GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER,
730                 GL_FRAMEBUFFER_DEFAULT_WIDTH, gl_info->limits.framebuffer_width));
731         GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER,
732                 GL_FRAMEBUFFER_DEFAULT_HEIGHT, gl_info->limits.framebuffer_height));
733         GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, 1));
734         GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, 1));
735     }
736 
737     /* Apply render targets */
738     for (i = 0; i < gl_info->limits.buffers; ++i)
739     {
740         context_attach_surface_fbo(context, target, i, &entry->key.objects[i + 1],
741                 entry->key.rb_namespace & (1 << (i + 1)));
742     }
743 
744     context_attach_depth_stencil_fbo(context, target, &entry->key.objects[0],
745             entry->key.rb_namespace & 0x1, entry->flags);
746 
747     /* Set valid read and draw buffer bindings to satisfy pedantic pre-ES2_compatibility
748      * GL contexts requirements. */
749     gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
750     context_set_draw_buffer(context, GL_NONE);
751     if (target != GL_FRAMEBUFFER)
752     {
753         if (target == GL_READ_FRAMEBUFFER)
754             context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, draw_binding);
755         else
756             context_bind_fbo(context, GL_READ_FRAMEBUFFER, read_binding);
757     }
758 
759     entry->flags |= WINED3D_FBO_ENTRY_FLAG_ATTACHED;
760 }
761 
762 /* Context activation is done by the caller. */
context_apply_fbo_state(struct wined3d_context * context,GLenum target,struct wined3d_rendertarget_info * render_targets,struct wined3d_surface * depth_stencil,DWORD color_location,DWORD ds_location)763 static void context_apply_fbo_state(struct wined3d_context *context, GLenum target,
764         struct wined3d_rendertarget_info *render_targets, struct wined3d_surface *depth_stencil,
765         DWORD color_location, DWORD ds_location)
766 {
767     struct fbo_entry *entry, *entry2;
768 
769     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
770     {
771         context_destroy_fbo_entry(context, entry);
772     }
773 
774     if (context->rebind_fbo)
775     {
776         context_bind_fbo(context, GL_FRAMEBUFFER, 0);
777         context->rebind_fbo = FALSE;
778     }
779 
780     if (color_location == WINED3D_LOCATION_DRAWABLE)
781     {
782         context->current_fbo = NULL;
783         context_bind_fbo(context, target, 0);
784     }
785     else
786     {
787         struct wined3d_rendertarget_info ds = {{0}};
788 
789         if (depth_stencil)
790         {
791             ds.resource = &depth_stencil->container->resource;
792             ds.sub_resource_idx = surface_get_sub_resource_idx(depth_stencil);
793             ds.layer_count = 1;
794         }
795         context->current_fbo = context_find_fbo_entry(context, target,
796                 render_targets, &ds, color_location, ds_location);
797         context_apply_fbo_entry(context, target, context->current_fbo);
798     }
799 }
800 
801 /* Context activation is done by the caller. */
context_apply_fbo_state_blit(struct wined3d_context * context,GLenum target,struct wined3d_surface * render_target,struct wined3d_surface * depth_stencil,DWORD location)802 void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target,
803         struct wined3d_surface *render_target, struct wined3d_surface *depth_stencil, DWORD location)
804 {
805     memset(context->blit_targets, 0, sizeof(context->blit_targets));
806     if (render_target)
807     {
808         context->blit_targets[0].resource = &render_target->container->resource;
809         context->blit_targets[0].sub_resource_idx = surface_get_sub_resource_idx(render_target);
810         context->blit_targets[0].layer_count = 1;
811     }
812     context_apply_fbo_state(context, target, context->blit_targets, depth_stencil, location, location);
813 }
814 
815 /* Context activation is done by the caller. */
context_alloc_occlusion_query(struct wined3d_context * context,struct wined3d_occlusion_query * query)816 void context_alloc_occlusion_query(struct wined3d_context *context, struct wined3d_occlusion_query *query)
817 {
818     const struct wined3d_gl_info *gl_info = context->gl_info;
819 
820     if (context->free_occlusion_query_count)
821     {
822         query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
823     }
824     else
825     {
826         if (gl_info->supported[ARB_OCCLUSION_QUERY])
827         {
828             GL_EXTCALL(glGenQueries(1, &query->id));
829             checkGLcall("glGenQueries");
830 
831             TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
832         }
833         else
834         {
835             WARN("Occlusion queries not supported, not allocating query id.\n");
836             query->id = 0;
837         }
838     }
839 
840     query->context = context;
841     list_add_head(&context->occlusion_queries, &query->entry);
842 }
843 
context_free_occlusion_query(struct wined3d_occlusion_query * query)844 void context_free_occlusion_query(struct wined3d_occlusion_query *query)
845 {
846     struct wined3d_context *context = query->context;
847 
848     list_remove(&query->entry);
849     query->context = NULL;
850 
851     if (!wined3d_array_reserve((void **)&context->free_occlusion_queries,
852             &context->free_occlusion_query_size, context->free_occlusion_query_count + 1,
853             sizeof(*context->free_occlusion_queries)))
854     {
855         ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
856         return;
857     }
858 
859     context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
860 }
861 
862 /* Context activation is done by the caller. */
context_alloc_fence(struct wined3d_context * context,struct wined3d_fence * fence)863 void context_alloc_fence(struct wined3d_context *context, struct wined3d_fence *fence)
864 {
865     const struct wined3d_gl_info *gl_info = context->gl_info;
866 
867     if (context->free_fence_count)
868     {
869         fence->object = context->free_fences[--context->free_fence_count];
870     }
871     else
872     {
873         if (gl_info->supported[ARB_SYNC])
874         {
875             /* Using ARB_sync, not much to do here. */
876             fence->object.sync = NULL;
877             TRACE("Allocated sync object in context %p.\n", context);
878         }
879         else if (gl_info->supported[APPLE_FENCE])
880         {
881             GL_EXTCALL(glGenFencesAPPLE(1, &fence->object.id));
882             checkGLcall("glGenFencesAPPLE");
883 
884             TRACE("Allocated fence %u in context %p.\n", fence->object.id, context);
885         }
886         else if(gl_info->supported[NV_FENCE])
887         {
888             GL_EXTCALL(glGenFencesNV(1, &fence->object.id));
889             checkGLcall("glGenFencesNV");
890 
891             TRACE("Allocated fence %u in context %p.\n", fence->object.id, context);
892         }
893         else
894         {
895             WARN("Fences not supported, not allocating fence.\n");
896             fence->object.id = 0;
897         }
898     }
899 
900     fence->context = context;
901     list_add_head(&context->fences, &fence->entry);
902 }
903 
context_free_fence(struct wined3d_fence * fence)904 void context_free_fence(struct wined3d_fence *fence)
905 {
906     struct wined3d_context *context = fence->context;
907 
908     list_remove(&fence->entry);
909     fence->context = NULL;
910 
911     if (!wined3d_array_reserve((void **)&context->free_fences,
912             &context->free_fence_size, context->free_fence_count + 1,
913             sizeof(*context->free_fences)))
914     {
915         ERR("Failed to grow free list, leaking fence %u in context %p.\n", fence->object.id, context);
916         return;
917     }
918 
919     context->free_fences[context->free_fence_count++] = fence->object;
920 }
921 
922 /* Context activation is done by the caller. */
context_alloc_timestamp_query(struct wined3d_context * context,struct wined3d_timestamp_query * query)923 void context_alloc_timestamp_query(struct wined3d_context *context, struct wined3d_timestamp_query *query)
924 {
925     const struct wined3d_gl_info *gl_info = context->gl_info;
926 
927     if (context->free_timestamp_query_count)
928     {
929         query->id = context->free_timestamp_queries[--context->free_timestamp_query_count];
930     }
931     else
932     {
933         GL_EXTCALL(glGenQueries(1, &query->id));
934         checkGLcall("glGenQueries");
935 
936         TRACE("Allocated timestamp query %u in context %p.\n", query->id, context);
937     }
938 
939     query->context = context;
940     list_add_head(&context->timestamp_queries, &query->entry);
941 }
942 
context_free_timestamp_query(struct wined3d_timestamp_query * query)943 void context_free_timestamp_query(struct wined3d_timestamp_query *query)
944 {
945     struct wined3d_context *context = query->context;
946 
947     list_remove(&query->entry);
948     query->context = NULL;
949 
950     if (!wined3d_array_reserve((void **)&context->free_timestamp_queries,
951             &context->free_timestamp_query_size, context->free_timestamp_query_count + 1,
952             sizeof(*context->free_timestamp_queries)))
953     {
954         ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
955         return;
956     }
957 
958     context->free_timestamp_queries[context->free_timestamp_query_count++] = query->id;
959 }
960 
context_alloc_so_statistics_query(struct wined3d_context * context,struct wined3d_so_statistics_query * query)961 void context_alloc_so_statistics_query(struct wined3d_context *context,
962         struct wined3d_so_statistics_query *query)
963 {
964     const struct wined3d_gl_info *gl_info = context->gl_info;
965 
966     if (context->free_so_statistics_query_count)
967     {
968         query->u = context->free_so_statistics_queries[--context->free_so_statistics_query_count];
969     }
970     else
971     {
972         GL_EXTCALL(glGenQueries(ARRAY_SIZE(query->u.id), query->u.id));
973         checkGLcall("glGenQueries");
974 
975         TRACE("Allocated SO statistics queries %u, %u in context %p.\n",
976                 query->u.id[0], query->u.id[1], context);
977     }
978 
979     query->context = context;
980     list_add_head(&context->so_statistics_queries, &query->entry);
981 }
982 
context_free_so_statistics_query(struct wined3d_so_statistics_query * query)983 void context_free_so_statistics_query(struct wined3d_so_statistics_query *query)
984 {
985     struct wined3d_context *context = query->context;
986 
987     list_remove(&query->entry);
988     query->context = NULL;
989 
990     if (!wined3d_array_reserve((void **)&context->free_so_statistics_queries,
991             &context->free_so_statistics_query_size, context->free_so_statistics_query_count + 1,
992             sizeof(*context->free_so_statistics_queries)))
993     {
994         ERR("Failed to grow free list, leaking GL queries %u, %u in context %p.\n",
995                 query->u.id[0], query->u.id[1], context);
996         return;
997     }
998 
999     context->free_so_statistics_queries[context->free_so_statistics_query_count++] = query->u;
1000 }
1001 
context_alloc_pipeline_statistics_query(struct wined3d_context * context,struct wined3d_pipeline_statistics_query * query)1002 void context_alloc_pipeline_statistics_query(struct wined3d_context *context,
1003         struct wined3d_pipeline_statistics_query *query)
1004 {
1005     const struct wined3d_gl_info *gl_info = context->gl_info;
1006 
1007     if (context->free_pipeline_statistics_query_count)
1008     {
1009         query->u = context->free_pipeline_statistics_queries[--context->free_pipeline_statistics_query_count];
1010     }
1011     else
1012     {
1013         GL_EXTCALL(glGenQueries(ARRAY_SIZE(query->u.id), query->u.id));
1014         checkGLcall("glGenQueries");
1015     }
1016 
1017     query->context = context;
1018     list_add_head(&context->pipeline_statistics_queries, &query->entry);
1019 }
1020 
context_free_pipeline_statistics_query(struct wined3d_pipeline_statistics_query * query)1021 void context_free_pipeline_statistics_query(struct wined3d_pipeline_statistics_query *query)
1022 {
1023     struct wined3d_context *context = query->context;
1024 
1025     list_remove(&query->entry);
1026     query->context = NULL;
1027 
1028     if (!wined3d_array_reserve((void **)&context->free_pipeline_statistics_queries,
1029             &context->free_pipeline_statistics_query_size, context->free_pipeline_statistics_query_count + 1,
1030             sizeof(*context->free_pipeline_statistics_queries)))
1031     {
1032         ERR("Failed to grow free list, leaking GL queries in context %p.\n", context);
1033         return;
1034     }
1035 
1036     context->free_pipeline_statistics_queries[context->free_pipeline_statistics_query_count++] = query->u;
1037 }
1038 
1039 typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
1040 
context_enum_fbo_entries(const struct wined3d_device * device,GLuint name,BOOL rb_namespace,context_fbo_entry_func_t * callback)1041 static void context_enum_fbo_entries(const struct wined3d_device *device,
1042         GLuint name, BOOL rb_namespace, context_fbo_entry_func_t *callback)
1043 {
1044     unsigned int i, j;
1045 
1046     for (i = 0; i < device->context_count; ++i)
1047     {
1048         struct wined3d_context *context = device->contexts[i];
1049         const struct wined3d_gl_info *gl_info = context->gl_info;
1050         struct fbo_entry *entry, *entry2;
1051 
1052         LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
1053         {
1054             for (j = 0; j < gl_info->limits.buffers + 1; ++j)
1055             {
1056                 if (entry->key.objects[j].object == name
1057                         && !(entry->key.rb_namespace & (1 << j)) == !rb_namespace)
1058                 {
1059                     callback(context, entry);
1060                     break;
1061                 }
1062             }
1063         }
1064     }
1065 }
1066 
context_queue_fbo_entry_destruction(struct wined3d_context * context,struct fbo_entry * entry)1067 static void context_queue_fbo_entry_destruction(struct wined3d_context *context, struct fbo_entry *entry)
1068 {
1069     list_remove(&entry->entry);
1070     list_add_head(&context->fbo_destroy_list, &entry->entry);
1071 }
1072 
context_resource_released(const struct wined3d_device * device,struct wined3d_resource * resource,enum wined3d_resource_type type)1073 void context_resource_released(const struct wined3d_device *device,
1074         struct wined3d_resource *resource, enum wined3d_resource_type type)
1075 {
1076     struct wined3d_texture *texture;
1077     UINT i;
1078 
1079     if (!device->d3d_initialized)
1080         return;
1081 
1082     switch (type)
1083     {
1084         case WINED3D_RTYPE_TEXTURE_2D:
1085         case WINED3D_RTYPE_TEXTURE_3D:
1086             texture = texture_from_resource(resource);
1087 
1088             for (i = 0; i < device->context_count; ++i)
1089             {
1090                 struct wined3d_context *context = device->contexts[i];
1091                 if (context->current_rt.texture == texture)
1092                 {
1093                     context->current_rt.texture = NULL;
1094                     context->current_rt.sub_resource_idx = 0;
1095                 }
1096             }
1097             break;
1098 
1099         default:
1100             break;
1101     }
1102 }
1103 
context_gl_resource_released(struct wined3d_device * device,GLuint name,BOOL rb_namespace)1104 void context_gl_resource_released(struct wined3d_device *device,
1105         GLuint name, BOOL rb_namespace)
1106 {
1107     context_enum_fbo_entries(device, name, rb_namespace, context_queue_fbo_entry_destruction);
1108 }
1109 
context_surface_update(struct wined3d_context * context,const struct wined3d_surface * surface)1110 void context_surface_update(struct wined3d_context *context, const struct wined3d_surface *surface)
1111 {
1112     const struct wined3d_gl_info *gl_info = context->gl_info;
1113     struct fbo_entry *entry = context->current_fbo;
1114     unsigned int i;
1115 
1116     if (!entry || context->rebind_fbo) return;
1117 
1118     for (i = 0; i < gl_info->limits.buffers + 1; ++i)
1119     {
1120         if (surface->container->texture_rgb.name == entry->key.objects[i].object
1121                 || surface->container->texture_srgb.name == entry->key.objects[i].object)
1122         {
1123             TRACE("Updated surface %p is bound as attachment %u to the current FBO.\n", surface, i);
1124             context->rebind_fbo = TRUE;
1125             return;
1126         }
1127     }
1128 }
1129 
context_restore_pixel_format(struct wined3d_context * ctx)1130 static BOOL context_restore_pixel_format(struct wined3d_context *ctx)
1131 {
1132     const struct wined3d_gl_info *gl_info = ctx->gl_info;
1133     BOOL ret = FALSE;
1134 
1135     if (ctx->restore_pf && IsWindow(ctx->restore_pf_win))
1136     {
1137         if (ctx->gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
1138         {
1139             HDC dc = GetDCEx(ctx->restore_pf_win, 0, DCX_USESTYLE | DCX_CACHE);
1140             if (dc)
1141             {
1142                 if (!(ret = GL_EXTCALL(wglSetPixelFormatWINE(dc, ctx->restore_pf))))
1143                 {
1144                     ERR("wglSetPixelFormatWINE failed to restore pixel format %d on window %p.\n",
1145                             ctx->restore_pf, ctx->restore_pf_win);
1146                 }
1147                 ReleaseDC(ctx->restore_pf_win, dc);
1148             }
1149         }
1150         else
1151         {
1152             ERR("can't restore pixel format %d on window %p\n", ctx->restore_pf, ctx->restore_pf_win);
1153         }
1154     }
1155 
1156     ctx->restore_pf = 0;
1157     ctx->restore_pf_win = NULL;
1158     return ret;
1159 }
1160 
context_set_pixel_format(struct wined3d_context * context)1161 static BOOL context_set_pixel_format(struct wined3d_context *context)
1162 {
1163     const struct wined3d_gl_info *gl_info = context->gl_info;
1164     BOOL private = context->hdc_is_private;
1165     int format = context->pixel_format;
1166     HDC dc = context->hdc;
1167     int current;
1168 
1169     if (private && context->hdc_has_format)
1170         return TRUE;
1171 
1172     if (!private && WindowFromDC(dc) != context->win_handle)
1173         return FALSE;
1174 
1175     current = gl_info->gl_ops.wgl.p_wglGetPixelFormat(dc);
1176     if (current == format) goto success;
1177 
1178     if (!current)
1179     {
1180         if (!SetPixelFormat(dc, format, NULL))
1181         {
1182             /* This may also happen if the dc belongs to a destroyed window. */
1183             WARN("Failed to set pixel format %d on device context %p, last error %#x.\n",
1184                     format, dc, GetLastError());
1185             return FALSE;
1186         }
1187 
1188         context->restore_pf = 0;
1189         context->restore_pf_win = private ? NULL : WindowFromDC(dc);
1190         goto success;
1191     }
1192 
1193     /* By default WGL doesn't allow pixel format adjustments but we need it
1194      * here. For this reason there's a Wine specific wglSetPixelFormat()
1195      * which allows us to set the pixel format multiple times. Only use it
1196      * when really needed. */
1197     if (gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
1198     {
1199         HWND win;
1200 
1201         if (!GL_EXTCALL(wglSetPixelFormatWINE(dc, format)))
1202         {
1203             ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
1204                     format, dc);
1205             return FALSE;
1206         }
1207 
1208         win = private ? NULL : WindowFromDC(dc);
1209         if (win != context->restore_pf_win)
1210         {
1211             context_restore_pixel_format(context);
1212 
1213             context->restore_pf = private ? 0 : current;
1214             context->restore_pf_win = win;
1215         }
1216 
1217         goto success;
1218     }
1219 
1220     /* OpenGL doesn't allow pixel format adjustments. Print an error and
1221      * continue using the old format. There's a big chance that the old
1222      * format works although with a performance hit and perhaps rendering
1223      * errors. */
1224     ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
1225             format, dc, current);
1226     return TRUE;
1227 
1228 success:
1229     if (private)
1230         context->hdc_has_format = TRUE;
1231     return TRUE;
1232 }
1233 
context_set_gl_context(struct wined3d_context * ctx)1234 static BOOL context_set_gl_context(struct wined3d_context *ctx)
1235 {
1236     struct wined3d_swapchain *swapchain = ctx->swapchain;
1237     BOOL backup = FALSE;
1238 
1239     if (!context_set_pixel_format(ctx))
1240     {
1241         WARN("Failed to set pixel format %d on device context %p.\n",
1242                 ctx->pixel_format, ctx->hdc);
1243         backup = TRUE;
1244     }
1245 
1246     if (backup || !wglMakeCurrent(ctx->hdc, ctx->glCtx))
1247     {
1248         WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
1249                 ctx->glCtx, ctx->hdc, GetLastError());
1250         ctx->valid = 0;
1251         WARN("Trying fallback to the backup window.\n");
1252 
1253         /* FIXME: If the context is destroyed it's no longer associated with
1254          * a swapchain, so we can't use the swapchain to get a backup dc. To
1255          * make this work windowless contexts would need to be handled by the
1256          * device. */
1257         if (ctx->destroyed || !swapchain)
1258         {
1259             FIXME("Unable to get backup dc for destroyed context %p.\n", ctx);
1260             context_set_current(NULL);
1261             return FALSE;
1262         }
1263 
1264         if (!(ctx->hdc = swapchain_get_backup_dc(swapchain)))
1265         {
1266             context_set_current(NULL);
1267             return FALSE;
1268         }
1269 
1270         ctx->hdc_is_private = TRUE;
1271         ctx->hdc_has_format = FALSE;
1272 
1273         if (!context_set_pixel_format(ctx))
1274         {
1275             ERR("Failed to set pixel format %d on device context %p.\n",
1276                     ctx->pixel_format, ctx->hdc);
1277             context_set_current(NULL);
1278             return FALSE;
1279         }
1280 
1281         if (!wglMakeCurrent(ctx->hdc, ctx->glCtx))
1282         {
1283             ERR("Fallback to backup window (dc %p) failed too, last error %#x.\n",
1284                     ctx->hdc, GetLastError());
1285             context_set_current(NULL);
1286             return FALSE;
1287         }
1288 
1289         ctx->valid = 1;
1290     }
1291     ctx->needs_set = 0;
1292     return TRUE;
1293 }
1294 
context_restore_gl_context(const struct wined3d_gl_info * gl_info,HDC dc,HGLRC gl_ctx)1295 static void context_restore_gl_context(const struct wined3d_gl_info *gl_info, HDC dc, HGLRC gl_ctx)
1296 {
1297     if (!wglMakeCurrent(dc, gl_ctx))
1298     {
1299         ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
1300                 gl_ctx, dc, GetLastError());
1301         context_set_current(NULL);
1302     }
1303 }
1304 
context_update_window(struct wined3d_context * context)1305 static void context_update_window(struct wined3d_context *context)
1306 {
1307     if (!context->swapchain)
1308         return;
1309 
1310     if (context->win_handle == context->swapchain->win_handle)
1311         return;
1312 
1313     TRACE("Updating context %p window from %p to %p.\n",
1314             context, context->win_handle, context->swapchain->win_handle);
1315 
1316     if (context->hdc)
1317         wined3d_release_dc(context->win_handle, context->hdc);
1318 
1319     context->win_handle = context->swapchain->win_handle;
1320     context->hdc_is_private = FALSE;
1321     context->hdc_has_format = FALSE;
1322     context->needs_set = 1;
1323     context->valid = 1;
1324 
1325     if (!(context->hdc = GetDCEx(context->win_handle, 0, DCX_USESTYLE | DCX_CACHE)))
1326     {
1327         ERR("Failed to get a device context for window %p.\n", context->win_handle);
1328         context->valid = 0;
1329     }
1330 }
1331 
context_destroy_gl_resources(struct wined3d_context * context)1332 static void context_destroy_gl_resources(struct wined3d_context *context)
1333 {
1334     struct wined3d_pipeline_statistics_query *pipeline_statistics_query;
1335     const struct wined3d_gl_info *gl_info = context->gl_info;
1336     struct wined3d_so_statistics_query *so_statistics_query;
1337     struct wined3d_timestamp_query *timestamp_query;
1338     struct wined3d_occlusion_query *occlusion_query;
1339     struct fbo_entry *entry, *entry2;
1340     struct wined3d_fence *fence;
1341     HGLRC restore_ctx;
1342     HDC restore_dc;
1343     unsigned int i;
1344 
1345     restore_ctx = wglGetCurrentContext();
1346     restore_dc = wglGetCurrentDC();
1347 
1348     if (restore_ctx == context->glCtx)
1349         restore_ctx = NULL;
1350     else if (context->valid)
1351         context_set_gl_context(context);
1352 
1353     LIST_FOR_EACH_ENTRY(so_statistics_query, &context->so_statistics_queries,
1354             struct wined3d_so_statistics_query, entry)
1355     {
1356         if (context->valid)
1357             GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(so_statistics_query->u.id), so_statistics_query->u.id));
1358         so_statistics_query->context = NULL;
1359     }
1360 
1361     LIST_FOR_EACH_ENTRY(pipeline_statistics_query, &context->pipeline_statistics_queries,
1362             struct wined3d_pipeline_statistics_query, entry)
1363     {
1364         if (context->valid)
1365             GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(pipeline_statistics_query->u.id), pipeline_statistics_query->u.id));
1366         pipeline_statistics_query->context = NULL;
1367     }
1368 
1369     LIST_FOR_EACH_ENTRY(timestamp_query, &context->timestamp_queries, struct wined3d_timestamp_query, entry)
1370     {
1371         if (context->valid)
1372             GL_EXTCALL(glDeleteQueries(1, &timestamp_query->id));
1373         timestamp_query->context = NULL;
1374     }
1375 
1376     LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
1377     {
1378         if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY])
1379             GL_EXTCALL(glDeleteQueries(1, &occlusion_query->id));
1380         occlusion_query->context = NULL;
1381     }
1382 
1383     LIST_FOR_EACH_ENTRY(fence, &context->fences, struct wined3d_fence, entry)
1384     {
1385         if (context->valid)
1386         {
1387             if (gl_info->supported[ARB_SYNC])
1388             {
1389                 if (fence->object.sync)
1390                     GL_EXTCALL(glDeleteSync(fence->object.sync));
1391             }
1392             else if (gl_info->supported[APPLE_FENCE])
1393             {
1394                 GL_EXTCALL(glDeleteFencesAPPLE(1, &fence->object.id));
1395             }
1396             else if (gl_info->supported[NV_FENCE])
1397             {
1398                 GL_EXTCALL(glDeleteFencesNV(1, &fence->object.id));
1399             }
1400         }
1401         fence->context = NULL;
1402     }
1403 
1404     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
1405     {
1406         if (!context->valid) entry->id = 0;
1407         context_destroy_fbo_entry(context, entry);
1408     }
1409 
1410     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
1411     {
1412         if (!context->valid) entry->id = 0;
1413         context_destroy_fbo_entry(context, entry);
1414     }
1415 
1416     if (context->valid)
1417     {
1418         if (context->dummy_arbfp_prog)
1419         {
1420             GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
1421         }
1422 
1423         if (gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1424         {
1425             for (i = 0; i < context->free_so_statistics_query_count; ++i)
1426             {
1427                 union wined3d_gl_so_statistics_query *q = &context->free_so_statistics_queries[i];
1428                 GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(q->id), q->id));
1429             }
1430         }
1431 
1432         if (gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1433         {
1434             for (i = 0; i < context->free_pipeline_statistics_query_count; ++i)
1435             {
1436                 union wined3d_gl_pipeline_statistics_query *q = &context->free_pipeline_statistics_queries[i];
1437                 GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(q->id), q->id));
1438             }
1439         }
1440 
1441         if (gl_info->supported[ARB_TIMER_QUERY])
1442             GL_EXTCALL(glDeleteQueries(context->free_timestamp_query_count, context->free_timestamp_queries));
1443 
1444         if (gl_info->supported[ARB_OCCLUSION_QUERY])
1445             GL_EXTCALL(glDeleteQueries(context->free_occlusion_query_count, context->free_occlusion_queries));
1446 
1447         if (gl_info->supported[ARB_SYNC])
1448         {
1449             for (i = 0; i < context->free_fence_count; ++i)
1450             {
1451                 GL_EXTCALL(glDeleteSync(context->free_fences[i].sync));
1452             }
1453         }
1454         else if (gl_info->supported[APPLE_FENCE])
1455         {
1456             for (i = 0; i < context->free_fence_count; ++i)
1457             {
1458                 GL_EXTCALL(glDeleteFencesAPPLE(1, &context->free_fences[i].id));
1459             }
1460         }
1461         else if (gl_info->supported[NV_FENCE])
1462         {
1463             for (i = 0; i < context->free_fence_count; ++i)
1464             {
1465                 GL_EXTCALL(glDeleteFencesNV(1, &context->free_fences[i].id));
1466             }
1467         }
1468 
1469         checkGLcall("context cleanup");
1470     }
1471 
1472     heap_free(context->free_so_statistics_queries);
1473     heap_free(context->free_pipeline_statistics_queries);
1474     heap_free(context->free_timestamp_queries);
1475     heap_free(context->free_occlusion_queries);
1476     heap_free(context->free_fences);
1477 
1478     context_restore_pixel_format(context);
1479     if (restore_ctx)
1480     {
1481         context_restore_gl_context(gl_info, restore_dc, restore_ctx);
1482     }
1483     else if (wglGetCurrentContext() && !wglMakeCurrent(NULL, NULL))
1484     {
1485         ERR("Failed to disable GL context.\n");
1486     }
1487 
1488     wined3d_release_dc(context->win_handle, context->hdc);
1489 
1490     if (!wglDeleteContext(context->glCtx))
1491     {
1492         DWORD err = GetLastError();
1493         ERR("wglDeleteContext(%p) failed, last error %#x.\n", context->glCtx, err);
1494     }
1495 }
1496 
context_get_tls_idx(void)1497 DWORD context_get_tls_idx(void)
1498 {
1499     return wined3d_context_tls_idx;
1500 }
1501 
context_set_tls_idx(DWORD idx)1502 void context_set_tls_idx(DWORD idx)
1503 {
1504     wined3d_context_tls_idx = idx;
1505 }
1506 
context_get_current(void)1507 struct wined3d_context *context_get_current(void)
1508 {
1509     return TlsGetValue(wined3d_context_tls_idx);
1510 }
1511 
context_set_current(struct wined3d_context * ctx)1512 BOOL context_set_current(struct wined3d_context *ctx)
1513 {
1514     struct wined3d_context *old = context_get_current();
1515 
1516     if (old == ctx)
1517     {
1518         TRACE("Already using D3D context %p.\n", ctx);
1519         return TRUE;
1520     }
1521 
1522     if (old)
1523     {
1524         if (old->destroyed)
1525         {
1526             TRACE("Switching away from destroyed context %p.\n", old);
1527             context_destroy_gl_resources(old);
1528             heap_free((void *)old->gl_info);
1529             heap_free(old);
1530         }
1531         else
1532         {
1533             if (wglGetCurrentContext())
1534             {
1535                 const struct wined3d_gl_info *gl_info = old->gl_info;
1536                 TRACE("Flushing context %p before switching to %p.\n", old, ctx);
1537                 gl_info->gl_ops.gl.p_glFlush();
1538             }
1539             old->current = 0;
1540         }
1541     }
1542 
1543     if (ctx)
1544     {
1545         if (!ctx->valid)
1546         {
1547             ERR("Trying to make invalid context %p current\n", ctx);
1548             return FALSE;
1549         }
1550 
1551         TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
1552         if (!context_set_gl_context(ctx))
1553             return FALSE;
1554         ctx->current = 1;
1555     }
1556     else if (wglGetCurrentContext())
1557     {
1558         TRACE("Clearing current D3D context.\n");
1559         if (!wglMakeCurrent(NULL, NULL))
1560         {
1561             DWORD err = GetLastError();
1562             ERR("Failed to clear current GL context, last error %#x.\n", err);
1563             TlsSetValue(wined3d_context_tls_idx, NULL);
1564             return FALSE;
1565         }
1566     }
1567 
1568     return TlsSetValue(wined3d_context_tls_idx, ctx);
1569 }
1570 
context_release(struct wined3d_context * context)1571 void context_release(struct wined3d_context *context)
1572 {
1573     TRACE("Releasing context %p, level %u.\n", context, context->level);
1574 
1575     if (WARN_ON(d3d))
1576     {
1577         if (!context->level)
1578             WARN("Context %p is not active.\n", context);
1579         else if (context != context_get_current())
1580             WARN("Context %p is not the current context.\n", context);
1581     }
1582 
1583     if (!--context->level)
1584     {
1585         if (context_restore_pixel_format(context))
1586             context->needs_set = 1;
1587         if (context->restore_ctx)
1588         {
1589             TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
1590             context_restore_gl_context(context->gl_info, context->restore_dc, context->restore_ctx);
1591             context->restore_ctx = NULL;
1592             context->restore_dc = NULL;
1593         }
1594 
1595         if (context->destroy_delayed)
1596         {
1597             TRACE("Destroying context %p.\n", context);
1598             context_destroy(context->device, context);
1599         }
1600     }
1601 }
1602 
1603 /* This is used when a context for render target A is active, but a separate context is
1604  * needed to access the WGL framebuffer for render target B. Re-acquire a context for rt
1605  * A to avoid breaking caller code. */
context_restore(struct wined3d_context * context,struct wined3d_surface * restore)1606 void context_restore(struct wined3d_context *context, struct wined3d_surface *restore)
1607 {
1608     if (context->current_rt.texture != restore->container
1609             || context->current_rt.sub_resource_idx != surface_get_sub_resource_idx(restore))
1610     {
1611         context_release(context);
1612         context = context_acquire(restore->container->resource.device,
1613                 restore->container, surface_get_sub_resource_idx(restore));
1614     }
1615 
1616     context_release(context);
1617 }
1618 
context_enter(struct wined3d_context * context)1619 static void context_enter(struct wined3d_context *context)
1620 {
1621     TRACE("Entering context %p, level %u.\n", context, context->level + 1);
1622 
1623     if (!context->level++)
1624     {
1625         const struct wined3d_context *current_context = context_get_current();
1626         HGLRC current_gl = wglGetCurrentContext();
1627 
1628         if (current_gl && (!current_context || current_context->glCtx != current_gl))
1629         {
1630             TRACE("Another GL context (%p on device context %p) is already current.\n",
1631                     current_gl, wglGetCurrentDC());
1632             context->restore_ctx = current_gl;
1633             context->restore_dc = wglGetCurrentDC();
1634             context->needs_set = 1;
1635         }
1636         else if (!context->needs_set && !(context->hdc_is_private && context->hdc_has_format)
1637                     && context->pixel_format != context->gl_info->gl_ops.wgl.p_wglGetPixelFormat(context->hdc))
1638             context->needs_set = 1;
1639     }
1640 }
1641 
context_invalidate_compute_state(struct wined3d_context * context,DWORD state_id)1642 void context_invalidate_compute_state(struct wined3d_context *context, DWORD state_id)
1643 {
1644     DWORD representative = context->state_table[state_id].representative - STATE_COMPUTE_OFFSET;
1645     unsigned int index, shift;
1646 
1647     index = representative / (sizeof(*context->dirty_compute_states) * CHAR_BIT);
1648     shift = representative & (sizeof(*context->dirty_compute_states) * CHAR_BIT - 1);
1649     context->dirty_compute_states[index] |= (1u << shift);
1650 }
1651 
context_invalidate_state(struct wined3d_context * context,DWORD state)1652 void context_invalidate_state(struct wined3d_context *context, DWORD state)
1653 {
1654     DWORD rep = context->state_table[state].representative;
1655     DWORD idx;
1656     BYTE shift;
1657 
1658     if (isStateDirty(context, rep)) return;
1659 
1660     context->dirtyArray[context->numDirtyEntries++] = rep;
1661     idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
1662     shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
1663     context->isStateDirty[idx] |= (1u << shift);
1664 }
1665 
1666 /* This function takes care of wined3d pixel format selection. */
context_choose_pixel_format(const struct wined3d_device * device,HDC hdc,const struct wined3d_format * color_format,const struct wined3d_format * ds_format,BOOL auxBuffers)1667 static int context_choose_pixel_format(const struct wined3d_device *device, HDC hdc,
1668         const struct wined3d_format *color_format, const struct wined3d_format *ds_format,
1669         BOOL auxBuffers)
1670 {
1671     unsigned int cfg_count = device->adapter->cfg_count;
1672     unsigned int current_value;
1673     PIXELFORMATDESCRIPTOR pfd;
1674     int iPixelFormat = 0;
1675     unsigned int i;
1676 
1677     TRACE("device %p, dc %p, color_format %s, ds_format %s, aux_buffers %#x.\n",
1678             device, hdc, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id),
1679             auxBuffers);
1680 
1681     current_value = 0;
1682     for (i = 0; i < cfg_count; ++i)
1683     {
1684         const struct wined3d_pixel_format *cfg = &device->adapter->cfgs[i];
1685         unsigned int value;
1686 
1687         /* For now only accept RGBA formats. Perhaps some day we will
1688          * allow floating point formats for pbuffers. */
1689         if (cfg->iPixelType != WGL_TYPE_RGBA_ARB)
1690             continue;
1691         /* In window mode we need a window drawable format and double buffering. */
1692         if (!(cfg->windowDrawable && cfg->doubleBuffer))
1693             continue;
1694         if (cfg->redSize < color_format->red_size)
1695             continue;
1696         if (cfg->greenSize < color_format->green_size)
1697             continue;
1698         if (cfg->blueSize < color_format->blue_size)
1699             continue;
1700         if (cfg->alphaSize < color_format->alpha_size)
1701             continue;
1702         if (cfg->depthSize < ds_format->depth_size)
1703             continue;
1704         if (ds_format->stencil_size && cfg->stencilSize != ds_format->stencil_size)
1705             continue;
1706         /* Check multisampling support. */
1707         if (cfg->numSamples)
1708             continue;
1709 
1710         value = 1;
1711         /* We try to locate a format which matches our requirements exactly. In case of
1712          * depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
1713         if (cfg->depthSize == ds_format->depth_size)
1714             value += 1;
1715         if (cfg->stencilSize == ds_format->stencil_size)
1716             value += 2;
1717         if (cfg->alphaSize == color_format->alpha_size)
1718             value += 4;
1719         /* We like to have aux buffers in backbuffer mode */
1720         if (auxBuffers && cfg->auxBuffers)
1721             value += 8;
1722         if (cfg->redSize == color_format->red_size
1723                 && cfg->greenSize == color_format->green_size
1724                 && cfg->blueSize == color_format->blue_size)
1725             value += 16;
1726 
1727         if (value > current_value)
1728         {
1729             iPixelFormat = cfg->iPixelFormat;
1730             current_value = value;
1731         }
1732     }
1733 
1734     if (!iPixelFormat)
1735     {
1736         ERR("Trying to locate a compatible pixel format because an exact match failed.\n");
1737 
1738         memset(&pfd, 0, sizeof(pfd));
1739         pfd.nSize      = sizeof(pfd);
1740         pfd.nVersion   = 1;
1741         pfd.dwFlags    = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
1742         pfd.iPixelType = PFD_TYPE_RGBA;
1743         pfd.cAlphaBits = color_format->alpha_size;
1744         pfd.cColorBits = color_format->red_size + color_format->green_size
1745                 + color_format->blue_size + color_format->alpha_size;
1746         pfd.cDepthBits = ds_format->depth_size;
1747         pfd.cStencilBits = ds_format->stencil_size;
1748         pfd.iLayerType = PFD_MAIN_PLANE;
1749 
1750         if (!(iPixelFormat = ChoosePixelFormat(hdc, &pfd)))
1751         {
1752             /* Something is very wrong as ChoosePixelFormat() barely fails. */
1753             ERR("Can't find a suitable pixel format.\n");
1754             return 0;
1755         }
1756     }
1757 
1758     TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s.\n",
1759             iPixelFormat, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id));
1760     return iPixelFormat;
1761 }
1762 
1763 /* Context activation is done by the caller. */
context_bind_dummy_textures(const struct wined3d_device * device,const struct wined3d_context * context)1764 void context_bind_dummy_textures(const struct wined3d_device *device, const struct wined3d_context *context)
1765 {
1766     const struct wined3d_dummy_textures *textures = &context->device->dummy_textures;
1767     const struct wined3d_gl_info *gl_info = context->gl_info;
1768     unsigned int i;
1769 
1770     for (i = 0; i < gl_info->limits.combined_samplers; ++i)
1771     {
1772         GL_EXTCALL(glActiveTexture(GL_TEXTURE0 + i));
1773 
1774         gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, textures->tex_1d);
1775         gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, textures->tex_2d);
1776 
1777         if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
1778             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textures->tex_rect);
1779 
1780         if (gl_info->supported[EXT_TEXTURE3D])
1781             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, textures->tex_3d);
1782 
1783         if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
1784             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, textures->tex_cube);
1785 
1786         if (gl_info->supported[ARB_TEXTURE_CUBE_MAP_ARRAY])
1787             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, textures->tex_cube_array);
1788 
1789         if (gl_info->supported[EXT_TEXTURE_ARRAY])
1790         {
1791             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D_ARRAY, textures->tex_1d_array);
1792             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_ARRAY, textures->tex_2d_array);
1793         }
1794         if (gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT])
1795             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_BUFFER, textures->tex_buffer);
1796 
1797         if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
1798         {
1799             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textures->tex_2d_ms);
1800             gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, textures->tex_2d_ms_array);
1801         }
1802     }
1803 
1804     checkGLcall("bind dummy textures");
1805 }
1806 
wined3d_check_gl_call(const struct wined3d_gl_info * gl_info,const char * file,unsigned int line,const char * name)1807 void wined3d_check_gl_call(const struct wined3d_gl_info *gl_info,
1808         const char *file, unsigned int line, const char *name)
1809 {
1810     GLint err;
1811 
1812     if (gl_info->supported[ARB_DEBUG_OUTPUT] || (err = gl_info->gl_ops.gl.p_glGetError()) == GL_NO_ERROR)
1813     {
1814         TRACE("%s call ok %s / %u.\n", name, file, line);
1815         return;
1816     }
1817 
1818     do
1819     {
1820         ERR(">>>>>>> %s (%#x) from %s @ %s / %u.\n",
1821                 debug_glerror(err), err, name, file,line);
1822         err = gl_info->gl_ops.gl.p_glGetError();
1823     } while (err != GL_NO_ERROR);
1824 }
1825 
context_debug_output_enabled(const struct wined3d_gl_info * gl_info)1826 static BOOL context_debug_output_enabled(const struct wined3d_gl_info *gl_info)
1827 {
1828     return gl_info->supported[ARB_DEBUG_OUTPUT]
1829             && (ERR_ON(d3d) || FIXME_ON(d3d) || WARN_ON(d3d_perf));
1830 }
1831 
wined3d_debug_callback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const char * message,void * ctx)1832 static void WINE_GLAPI wined3d_debug_callback(GLenum source, GLenum type, GLuint id,
1833         GLenum severity, GLsizei length, const char *message, void *ctx)
1834 {
1835     switch (type)
1836     {
1837         case GL_DEBUG_TYPE_ERROR_ARB:
1838             ERR("%p: %s.\n", ctx, debugstr_an(message, length));
1839             break;
1840 
1841         case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
1842         case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
1843         case GL_DEBUG_TYPE_PORTABILITY_ARB:
1844             FIXME("%p: %s.\n", ctx, debugstr_an(message, length));
1845             break;
1846 
1847         case GL_DEBUG_TYPE_PERFORMANCE_ARB:
1848             WARN_(d3d_perf)("%p: %s.\n", ctx, debugstr_an(message, length));
1849             break;
1850 
1851         default:
1852             FIXME("ctx %p, type %#x: %s.\n", ctx, type, debugstr_an(message, length));
1853             break;
1854     }
1855 }
1856 
context_create_wgl_attribs(const struct wined3d_gl_info * gl_info,HDC hdc,HGLRC share_ctx)1857 HGLRC context_create_wgl_attribs(const struct wined3d_gl_info *gl_info, HDC hdc, HGLRC share_ctx)
1858 {
1859     HGLRC ctx;
1860     unsigned int ctx_attrib_idx = 0;
1861     GLint ctx_attribs[7], ctx_flags = 0;
1862 
1863     if (context_debug_output_enabled(gl_info))
1864         ctx_flags = WGL_CONTEXT_DEBUG_BIT_ARB;
1865     ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
1866     ctx_attribs[ctx_attrib_idx++] = gl_info->selected_gl_version >> 16;
1867     ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MINOR_VERSION_ARB;
1868     ctx_attribs[ctx_attrib_idx++] = gl_info->selected_gl_version & 0xffff;
1869     if (gl_info->selected_gl_version >= MAKEDWORD_VERSION(3, 2))
1870         ctx_flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
1871     if (ctx_flags)
1872     {
1873         ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_FLAGS_ARB;
1874         ctx_attribs[ctx_attrib_idx++] = ctx_flags;
1875     }
1876     ctx_attribs[ctx_attrib_idx] = 0;
1877 
1878     if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
1879     {
1880         if (ctx_flags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
1881         {
1882             ctx_attribs[ctx_attrib_idx - 1] &= ~WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
1883             if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
1884                 WARN("Failed to create a WGL context with wglCreateContextAttribsARB, last error %#x.\n",
1885                         GetLastError());
1886         }
1887     }
1888     return ctx;
1889 }
1890 
context_create(struct wined3d_swapchain * swapchain,struct wined3d_texture * target,const struct wined3d_format * ds_format)1891 struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
1892         struct wined3d_texture *target, const struct wined3d_format *ds_format)
1893 {
1894     struct wined3d_device *device = swapchain->device;
1895     const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
1896     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1897     const struct wined3d_format *color_format;
1898     struct wined3d_context *ret;
1899     BOOL auxBuffers = FALSE;
1900     HGLRC ctx, share_ctx;
1901     DWORD target_usage;
1902     unsigned int i;
1903     DWORD state;
1904 
1905     TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
1906 
1907     wined3d_from_cs(device->cs);
1908 
1909     if (!(ret = heap_alloc_zero(sizeof(*ret))))
1910         return NULL;
1911 
1912     ret->free_timestamp_query_size = 4;
1913     if (!(ret->free_timestamp_queries = heap_calloc(ret->free_timestamp_query_size,
1914             sizeof(*ret->free_timestamp_queries))))
1915         goto out;
1916     list_init(&ret->timestamp_queries);
1917 
1918     ret->free_occlusion_query_size = 4;
1919     if (!(ret->free_occlusion_queries = heap_calloc(ret->free_occlusion_query_size,
1920             sizeof(*ret->free_occlusion_queries))))
1921         goto out;
1922     list_init(&ret->occlusion_queries);
1923 
1924     ret->free_fence_size = 4;
1925     if (!(ret->free_fences = heap_calloc(ret->free_fence_size, sizeof(*ret->free_fences))))
1926         goto out;
1927     list_init(&ret->fences);
1928 
1929     list_init(&ret->so_statistics_queries);
1930 
1931     list_init(&ret->pipeline_statistics_queries);
1932 
1933     list_init(&ret->fbo_list);
1934     list_init(&ret->fbo_destroy_list);
1935 
1936     if (!device->shader_backend->shader_allocate_context_data(ret))
1937     {
1938         ERR("Failed to allocate shader backend context data.\n");
1939         goto out;
1940     }
1941     if (!device->adapter->fragment_pipe->allocate_context_data(ret))
1942     {
1943         ERR("Failed to allocate fragment pipeline context data.\n");
1944         goto out;
1945     }
1946 
1947     for (i = 0; i < ARRAY_SIZE(ret->tex_unit_map); ++i)
1948         ret->tex_unit_map[i] = WINED3D_UNMAPPED_STAGE;
1949     for (i = 0; i < ARRAY_SIZE(ret->rev_tex_unit_map); ++i)
1950         ret->rev_tex_unit_map[i] = WINED3D_UNMAPPED_STAGE;
1951     if (gl_info->limits.graphics_samplers >= MAX_COMBINED_SAMPLERS)
1952     {
1953         /* Initialize the texture unit mapping to a 1:1 mapping. */
1954         unsigned int base, count;
1955 
1956         wined3d_gl_limits_get_texture_unit_range(&gl_info->limits, WINED3D_SHADER_TYPE_PIXEL, &base, &count);
1957         if (base + MAX_FRAGMENT_SAMPLERS > ARRAY_SIZE(ret->rev_tex_unit_map))
1958         {
1959             ERR("Unexpected texture unit base index %u.\n", base);
1960             goto out;
1961         }
1962         for (i = 0; i < min(count, MAX_FRAGMENT_SAMPLERS); ++i)
1963         {
1964             ret->tex_unit_map[i] = base + i;
1965             ret->rev_tex_unit_map[base + i] = i;
1966         }
1967 
1968         wined3d_gl_limits_get_texture_unit_range(&gl_info->limits, WINED3D_SHADER_TYPE_VERTEX, &base, &count);
1969         if (base + MAX_VERTEX_SAMPLERS > ARRAY_SIZE(ret->rev_tex_unit_map))
1970         {
1971             ERR("Unexpected texture unit base index %u.\n", base);
1972             goto out;
1973         }
1974         for (i = 0; i < min(count, MAX_VERTEX_SAMPLERS); ++i)
1975         {
1976             ret->tex_unit_map[MAX_FRAGMENT_SAMPLERS + i] = base + i;
1977             ret->rev_tex_unit_map[base + i] = MAX_FRAGMENT_SAMPLERS + i;
1978         }
1979     }
1980 
1981     if (!(ret->texture_type = heap_calloc(gl_info->limits.combined_samplers,
1982             sizeof(*ret->texture_type))))
1983         goto out;
1984 
1985     if (!(ret->hdc = GetDCEx(swapchain->win_handle, 0, DCX_USESTYLE | DCX_CACHE)))
1986     {
1987         WARN("Failed to retrieve device context, trying swapchain backup.\n");
1988 
1989         if ((ret->hdc = swapchain_get_backup_dc(swapchain)))
1990             ret->hdc_is_private = TRUE;
1991         else
1992         {
1993             ERR("Failed to retrieve a device context.\n");
1994             goto out;
1995         }
1996     }
1997 
1998     color_format = target->resource.format;
1999     target_usage = target->resource.usage;
2000 
2001     /* In case of ORM_BACKBUFFER, make sure to request an alpha component for
2002      * X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
2003     if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
2004     {
2005         auxBuffers = TRUE;
2006 
2007         if (color_format->id == WINED3DFMT_B4G4R4X4_UNORM)
2008             color_format = wined3d_get_format(gl_info, WINED3DFMT_B4G4R4A4_UNORM, target_usage);
2009         else if (color_format->id == WINED3DFMT_B8G8R8X8_UNORM)
2010             color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2011     }
2012 
2013     /* DirectDraw supports 8bit paletted render targets and these are used by
2014      * old games like StarCraft and C&C. Most modern hardware doesn't support
2015      * 8bit natively so we perform some form of 8bit -> 32bit conversion. The
2016      * conversion (ab)uses the alpha component for storing the palette index.
2017      * For this reason we require a format with 8bit alpha, so request
2018      * A8R8G8B8. */
2019     if (color_format->id == WINED3DFMT_P8_UINT)
2020         color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2021 
2022     /* When using FBOs for off-screen rendering, we only use the drawable for
2023      * presentation blits, and don't do any rendering to it. That means we
2024      * don't need depth or stencil buffers, and can mostly ignore the render
2025      * target format. This wouldn't necessarily be quite correct for 10bpc
2026      * display modes, but we don't currently support those.
2027      * Using the same format regardless of the color/depth/stencil targets
2028      * makes it much less likely that different wined3d instances will set
2029      * conflicting pixel formats. */
2030     if (wined3d_settings.offscreen_rendering_mode != ORM_BACKBUFFER)
2031     {
2032         color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2033         ds_format = wined3d_get_format(gl_info, WINED3DFMT_UNKNOWN, WINED3DUSAGE_DEPTHSTENCIL);
2034     }
2035 
2036     /* Try to find a pixel format which matches our requirements. */
2037     if (!(ret->pixel_format = context_choose_pixel_format(device, ret->hdc, color_format, ds_format, auxBuffers)))
2038         goto out;
2039 
2040     ret->gl_info = gl_info;
2041     ret->win_handle = swapchain->win_handle;
2042 
2043     context_enter(ret);
2044 
2045     if (!context_set_pixel_format(ret))
2046     {
2047         ERR("Failed to set pixel format %d on device context %p.\n", ret->pixel_format, ret->hdc);
2048         context_release(ret);
2049         goto out;
2050     }
2051 
2052     share_ctx = device->context_count ? device->contexts[0]->glCtx : NULL;
2053     if (gl_info->p_wglCreateContextAttribsARB)
2054     {
2055         if (!(ctx = context_create_wgl_attribs(gl_info, ret->hdc, share_ctx)))
2056             goto out;
2057     }
2058     else
2059     {
2060         if (!(ctx = wglCreateContext(ret->hdc)))
2061         {
2062             ERR("Failed to create a WGL context.\n");
2063             context_release(ret);
2064             goto out;
2065         }
2066 
2067         if (share_ctx && !wglShareLists(share_ctx, ctx))
2068         {
2069             ERR("wglShareLists(%p, %p) failed, last error %#x.\n", share_ctx, ctx, GetLastError());
2070             context_release(ret);
2071             if (!wglDeleteContext(ctx))
2072                 ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2073             goto out;
2074         }
2075     }
2076 
2077     if (!device_context_add(device, ret))
2078     {
2079         ERR("Failed to add the newly created context to the context list\n");
2080         context_release(ret);
2081         if (!wglDeleteContext(ctx))
2082             ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2083         goto out;
2084     }
2085 
2086     ret->d3d_info = d3d_info;
2087     ret->state_table = device->StateTable;
2088 
2089     /* Mark all states dirty to force a proper initialization of the states on
2090      * the first use of the context. Compute states do not need initialization. */
2091     for (state = 0; state <= STATE_HIGHEST; ++state)
2092     {
2093         if (ret->state_table[state].representative && !STATE_IS_COMPUTE(state))
2094             context_invalidate_state(ret, state);
2095     }
2096 
2097     ret->device = device;
2098     ret->swapchain = swapchain;
2099     ret->current_rt.texture = target;
2100     ret->current_rt.sub_resource_idx = 0;
2101     ret->tid = GetCurrentThreadId();
2102 
2103     ret->render_offscreen = wined3d_resource_is_offscreen(&target->resource);
2104     ret->draw_buffers_mask = context_generate_rt_mask(GL_BACK);
2105     ret->valid = 1;
2106 
2107     ret->glCtx = ctx;
2108     ret->hdc_has_format = TRUE;
2109     ret->needs_set = 1;
2110 
2111     /* Set up the context defaults */
2112     if (!context_set_current(ret))
2113     {
2114         ERR("Cannot activate context to set up defaults.\n");
2115         device_context_remove(device, ret);
2116         context_release(ret);
2117         if (!wglDeleteContext(ctx))
2118             ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2119         goto out;
2120     }
2121 
2122     if (context_debug_output_enabled(gl_info))
2123     {
2124         GL_EXTCALL(glDebugMessageCallback(wined3d_debug_callback, ret));
2125         if (TRACE_ON(d3d_synchronous))
2126             gl_info->gl_ops.gl.p_glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
2127         GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE));
2128         if (ERR_ON(d3d))
2129         {
2130             GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR,
2131                     GL_DONT_CARE, 0, NULL, GL_TRUE));
2132         }
2133         if (FIXME_ON(d3d))
2134         {
2135             GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
2136                     GL_DONT_CARE, 0, NULL, GL_TRUE));
2137             GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
2138                     GL_DONT_CARE, 0, NULL, GL_TRUE));
2139             GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_PORTABILITY,
2140                     GL_DONT_CARE, 0, NULL, GL_TRUE));
2141         }
2142         if (WARN_ON(d3d_perf))
2143         {
2144             GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE,
2145                     GL_DONT_CARE, 0, NULL, GL_TRUE));
2146         }
2147     }
2148 
2149     if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2150         gl_info->gl_ops.gl.p_glGetIntegerv(GL_AUX_BUFFERS, &ret->aux_buffers);
2151 
2152     TRACE("Setting up the screen\n");
2153 
2154     if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2155     {
2156         gl_info->gl_ops.gl.p_glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
2157         checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
2158 
2159         gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2160         checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
2161 
2162         gl_info->gl_ops.gl.p_glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
2163         checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
2164     }
2165     else
2166     {
2167         GLuint vao;
2168 
2169         GL_EXTCALL(glGenVertexArrays(1, &vao));
2170         GL_EXTCALL(glBindVertexArray(vao));
2171         checkGLcall("creating VAO");
2172     }
2173 
2174     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);
2175     checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
2176     gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2177     checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, 1);");
2178 
2179     if (gl_info->supported[ARB_VERTEX_BLEND])
2180     {
2181         /* Direct3D always uses n-1 weights for n world matrices and uses
2182          * 1 - sum for the last one this is equal to GL_WEIGHT_SUM_UNITY_ARB.
2183          * Enabling it doesn't do anything unless GL_VERTEX_BLEND_ARB isn't
2184          * enabled as well. */
2185         gl_info->gl_ops.gl.p_glEnable(GL_WEIGHT_SUM_UNITY_ARB);
2186         checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
2187     }
2188     if (gl_info->supported[NV_TEXTURE_SHADER2])
2189     {
2190         /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
2191          * the previous texture where to source the offset from is always unit - 1.
2192          */
2193         for (i = 1; i < gl_info->limits.textures; ++i)
2194         {
2195             context_active_texture(ret, gl_info, i);
2196             gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_SHADER_NV,
2197                     GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + i - 1);
2198             checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
2199         }
2200     }
2201     if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
2202     {
2203         /* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
2204          * enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
2205          * GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
2206          * because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
2207          * is ever assigned.
2208          *
2209          * So make sure a program is assigned to each context. The first real ARBFP use will set a different
2210          * program and the dummy program is destroyed when the context is destroyed.
2211          */
2212         static const char dummy_program[] =
2213                 "!!ARBfp1.0\n"
2214                 "MOV result.color, fragment.color.primary;\n"
2215                 "END\n";
2216         GL_EXTCALL(glGenProgramsARB(1, &ret->dummy_arbfp_prog));
2217         GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret->dummy_arbfp_prog));
2218         GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
2219     }
2220 
2221     if (gl_info->supported[ARB_POINT_SPRITE])
2222     {
2223         for (i = 0; i < gl_info->limits.textures; ++i)
2224         {
2225             context_active_texture(ret, gl_info, i);
2226             gl_info->gl_ops.gl.p_glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
2227             checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
2228         }
2229     }
2230 
2231     if (gl_info->supported[ARB_PROVOKING_VERTEX])
2232     {
2233         GL_EXTCALL(glProvokingVertex(GL_FIRST_VERTEX_CONVENTION));
2234     }
2235     else if (gl_info->supported[EXT_PROVOKING_VERTEX])
2236     {
2237         GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
2238     }
2239     if (!(d3d_info->wined3d_creation_flags & WINED3D_NO_PRIMITIVE_RESTART))
2240     {
2241         if (gl_info->supported[ARB_ES3_COMPATIBILITY])
2242         {
2243             gl_info->gl_ops.gl.p_glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2244             checkGLcall("enable GL_PRIMITIVE_RESTART_FIXED_INDEX");
2245         }
2246         else
2247         {
2248             FIXME("OpenGL implementation does not support GL_PRIMITIVE_RESTART_FIXED_INDEX.\n");
2249         }
2250     }
2251     if (!(d3d_info->wined3d_creation_flags & WINED3D_LEGACY_CUBEMAP_FILTERING)
2252             && gl_info->supported[ARB_SEAMLESS_CUBE_MAP])
2253     {
2254         gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
2255         checkGLcall("enable seamless cube map filtering");
2256     }
2257     if (gl_info->supported[ARB_CLIP_CONTROL])
2258         GL_EXTCALL(glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT));
2259     device->shader_backend->shader_init_context_state(ret);
2260     ret->shader_update_mask = (1u << WINED3D_SHADER_TYPE_PIXEL)
2261             | (1u << WINED3D_SHADER_TYPE_VERTEX)
2262             | (1u << WINED3D_SHADER_TYPE_GEOMETRY)
2263             | (1u << WINED3D_SHADER_TYPE_HULL)
2264             | (1u << WINED3D_SHADER_TYPE_DOMAIN)
2265             | (1u << WINED3D_SHADER_TYPE_COMPUTE);
2266 
2267     /* If this happens to be the first context for the device, dummy textures
2268      * are not created yet. In that case, they will be created (and bound) by
2269      * create_dummy_textures right after this context is initialized. */
2270     if (device->dummy_textures.tex_2d)
2271         context_bind_dummy_textures(device, ret);
2272 
2273     TRACE("Created context %p.\n", ret);
2274 
2275     return ret;
2276 
2277 out:
2278     if (ret->hdc)
2279         wined3d_release_dc(swapchain->win_handle, ret->hdc);
2280     device->shader_backend->shader_free_context_data(ret);
2281     device->adapter->fragment_pipe->free_context_data(ret);
2282     heap_free(ret->texture_type);
2283     heap_free(ret->free_fences);
2284     heap_free(ret->free_occlusion_queries);
2285     heap_free(ret->free_timestamp_queries);
2286     heap_free(ret);
2287     return NULL;
2288 }
2289 
context_destroy(struct wined3d_device * device,struct wined3d_context * context)2290 void context_destroy(struct wined3d_device *device, struct wined3d_context *context)
2291 {
2292     BOOL destroy;
2293 
2294     TRACE("Destroying ctx %p\n", context);
2295 
2296     wined3d_from_cs(device->cs);
2297 
2298     /* We delay destroying a context when it is active. The context_release()
2299      * function invokes context_destroy() again while leaving the last level. */
2300     if (context->level)
2301     {
2302         TRACE("Delaying destruction of context %p.\n", context);
2303         context->destroy_delayed = 1;
2304         /* FIXME: Get rid of a pointer to swapchain from wined3d_context. */
2305         context->swapchain = NULL;
2306         return;
2307     }
2308 
2309     if (context->tid == GetCurrentThreadId() || !context->current)
2310     {
2311         context_destroy_gl_resources(context);
2312         TlsSetValue(wined3d_context_tls_idx, NULL);
2313         destroy = TRUE;
2314     }
2315     else
2316     {
2317         /* Make a copy of gl_info for context_destroy_gl_resources use, the one
2318            in wined3d_adapter may go away in the meantime */
2319         struct wined3d_gl_info *gl_info = heap_alloc(sizeof(*gl_info));
2320         *gl_info = *context->gl_info;
2321         context->gl_info = gl_info;
2322         context->destroyed = 1;
2323         destroy = FALSE;
2324     }
2325 
2326     device->shader_backend->shader_free_context_data(context);
2327     device->adapter->fragment_pipe->free_context_data(context);
2328     heap_free(context->texture_type);
2329     device_context_remove(device, context);
2330     if (destroy)
2331         heap_free(context);
2332 }
2333 
context_get_tex_unit_mapping(const struct wined3d_context * context,const struct wined3d_shader_version * shader_version,unsigned int * base,unsigned int * count)2334 const DWORD *context_get_tex_unit_mapping(const struct wined3d_context *context,
2335         const struct wined3d_shader_version *shader_version, unsigned int *base, unsigned int *count)
2336 {
2337     const struct wined3d_gl_info *gl_info = context->gl_info;
2338 
2339     if (!shader_version)
2340     {
2341         *base = 0;
2342         *count = MAX_TEXTURES;
2343         return context->tex_unit_map;
2344     }
2345 
2346     if (shader_version->major >= 4)
2347     {
2348         wined3d_gl_limits_get_texture_unit_range(&gl_info->limits, shader_version->type, base, count);
2349         return NULL;
2350     }
2351 
2352     switch (shader_version->type)
2353     {
2354         case WINED3D_SHADER_TYPE_PIXEL:
2355             *base = 0;
2356             *count = MAX_FRAGMENT_SAMPLERS;
2357             break;
2358         case WINED3D_SHADER_TYPE_VERTEX:
2359             *base = MAX_FRAGMENT_SAMPLERS;
2360             *count = MAX_VERTEX_SAMPLERS;
2361             break;
2362         default:
2363             ERR("Unhandled shader type %#x.\n", shader_version->type);
2364             *base = 0;
2365             *count = 0;
2366     }
2367 
2368     return context->tex_unit_map;
2369 }
2370 
2371 /* Context activation is done by the caller. */
set_blit_dimension(const struct wined3d_gl_info * gl_info,UINT width,UINT height)2372 static void set_blit_dimension(const struct wined3d_gl_info *gl_info, UINT width, UINT height)
2373 {
2374     const GLdouble projection[] =
2375     {
2376         2.0 / width,          0.0,  0.0, 0.0,
2377                 0.0, 2.0 / height,  0.0, 0.0,
2378                 0.0,          0.0,  2.0, 0.0,
2379                -1.0,         -1.0, -1.0, 1.0,
2380     };
2381 
2382     if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2383     {
2384         gl_info->gl_ops.gl.p_glMatrixMode(GL_PROJECTION);
2385         checkGLcall("glMatrixMode(GL_PROJECTION)");
2386         gl_info->gl_ops.gl.p_glLoadMatrixd(projection);
2387         checkGLcall("glLoadMatrixd");
2388     }
2389     gl_info->gl_ops.gl.p_glViewport(0, 0, width, height);
2390     checkGLcall("glViewport");
2391 }
2392 
context_get_rt_size(const struct wined3d_context * context,SIZE * size)2393 static void context_get_rt_size(const struct wined3d_context *context, SIZE *size)
2394 {
2395     const struct wined3d_texture *rt = context->current_rt.texture;
2396     unsigned int level;
2397 
2398     if (rt->swapchain)
2399     {
2400         RECT window_size;
2401 
2402         GetClientRect(context->win_handle, &window_size);
2403         size->cx = window_size.right - window_size.left;
2404         size->cy = window_size.bottom - window_size.top;
2405 
2406         return;
2407     }
2408 
2409     level = context->current_rt.sub_resource_idx % rt->level_count;
2410     size->cx = wined3d_texture_get_level_width(rt, level);
2411     size->cy = wined3d_texture_get_level_height(rt, level);
2412 }
2413 
context_enable_clip_distances(struct wined3d_context * context,unsigned int enable_mask)2414 void context_enable_clip_distances(struct wined3d_context *context, unsigned int enable_mask)
2415 {
2416     const struct wined3d_gl_info *gl_info = context->gl_info;
2417     unsigned int clip_distance_count = gl_info->limits.user_clip_distances;
2418     unsigned int i, disable_mask, current_mask;
2419 
2420     disable_mask = ~enable_mask;
2421     enable_mask &= (1u << clip_distance_count) - 1;
2422     disable_mask &= (1u << clip_distance_count) - 1;
2423     current_mask = context->clip_distance_mask;
2424     context->clip_distance_mask = enable_mask;
2425 
2426     enable_mask &= ~current_mask;
2427     while (enable_mask)
2428     {
2429         i = wined3d_bit_scan(&enable_mask);
2430         gl_info->gl_ops.gl.p_glEnable(GL_CLIP_DISTANCE0 + i);
2431     }
2432     disable_mask &= current_mask;
2433     while (disable_mask)
2434     {
2435         i = wined3d_bit_scan(&disable_mask);
2436         gl_info->gl_ops.gl.p_glDisable(GL_CLIP_DISTANCE0 + i);
2437     }
2438     checkGLcall("toggle clip distances");
2439 }
2440 
2441 /*****************************************************************************
2442  * SetupForBlit
2443  *
2444  * Sets up a context for DirectDraw blitting.
2445  * All texture units are disabled, texture unit 0 is set as current unit
2446  * fog, lighting, blending, alpha test, z test, scissor test, culling disabled
2447  * color writing enabled for all channels
2448  * register combiners disabled, shaders disabled
2449  * world matrix is set to identity, texture matrix 0 too
2450  * projection matrix is setup for drawing screen coordinates
2451  *
2452  * Params:
2453  *  This: Device to activate the context for
2454  *  context: Context to setup
2455  *
2456  *****************************************************************************/
2457 /* Context activation is done by the caller. */
SetupForBlit(const struct wined3d_device * device,struct wined3d_context * context)2458 static void SetupForBlit(const struct wined3d_device *device, struct wined3d_context *context)
2459 {
2460     const struct wined3d_gl_info *gl_info = context->gl_info;
2461     DWORD sampler;
2462     SIZE rt_size;
2463     int i;
2464 
2465     TRACE("Setting up context %p for blitting\n", context);
2466 
2467     context_get_rt_size(context, &rt_size);
2468 
2469     if (context->last_was_blit)
2470     {
2471         if (context->blit_w != rt_size.cx || context->blit_h != rt_size.cy)
2472         {
2473             set_blit_dimension(gl_info, rt_size.cx, rt_size.cy);
2474             context->blit_w = rt_size.cx;
2475             context->blit_h = rt_size.cy;
2476             /* No need to dirtify here, the states are still dirtified because
2477              * they weren't applied since the last SetupForBlit() call. */
2478         }
2479         TRACE("Context is already set up for blitting, nothing to do\n");
2480         return;
2481     }
2482     context->last_was_blit = TRUE;
2483 
2484     if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2485     {
2486         /* Disable all textures. The caller can then bind a texture it wants to blit
2487          * from
2488          *
2489          * The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
2490          * function texture unit. No need to care for higher samplers
2491          */
2492         for (i = gl_info->limits.textures - 1; i > 0 ; --i)
2493         {
2494             sampler = context->rev_tex_unit_map[i];
2495             context_active_texture(context, gl_info, i);
2496 
2497             if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2498             {
2499                 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2500                 checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
2501             }
2502             gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_3D);
2503             checkGLcall("glDisable GL_TEXTURE_3D");
2504             if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2505             {
2506                 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2507                 checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
2508             }
2509             gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2510             checkGLcall("glDisable GL_TEXTURE_2D");
2511 
2512             gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2513             checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
2514 
2515             if (sampler != WINED3D_UNMAPPED_STAGE)
2516             {
2517                 if (sampler < MAX_TEXTURES)
2518                     context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3D_TSS_COLOR_OP));
2519                 context_invalidate_state(context, STATE_SAMPLER(sampler));
2520             }
2521         }
2522 
2523         context_active_texture(context, gl_info, 0);
2524         if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2525         {
2526             gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2527             checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
2528         }
2529         gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_3D);
2530         checkGLcall("glDisable GL_TEXTURE_3D");
2531         if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2532         {
2533             gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2534             checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
2535         }
2536         gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2537         checkGLcall("glDisable GL_TEXTURE_2D");
2538 
2539         gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2540 
2541         gl_info->gl_ops.gl.p_glMatrixMode(GL_TEXTURE);
2542         checkGLcall("glMatrixMode(GL_TEXTURE)");
2543         gl_info->gl_ops.gl.p_glLoadIdentity();
2544         checkGLcall("glLoadIdentity()");
2545 
2546         if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
2547         {
2548             gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
2549                     GL_TEXTURE_LOD_BIAS_EXT, 0.0f);
2550             checkGLcall("glTexEnvf GL_TEXTURE_LOD_BIAS_EXT ...");
2551         }
2552 
2553         /* Setup transforms */
2554         gl_info->gl_ops.gl.p_glMatrixMode(GL_MODELVIEW);
2555         checkGLcall("glMatrixMode(GL_MODELVIEW)");
2556         gl_info->gl_ops.gl.p_glLoadIdentity();
2557         checkGLcall("glLoadIdentity()");
2558         context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(0)));
2559 
2560         /* Other misc states */
2561         gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2562         checkGLcall("glDisable(GL_ALPHA_TEST)");
2563         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHATESTENABLE));
2564         gl_info->gl_ops.gl.p_glDisable(GL_LIGHTING);
2565         checkGLcall("glDisable GL_LIGHTING");
2566         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_LIGHTING));
2567         glDisableWINE(GL_FOG);
2568         checkGLcall("glDisable GL_FOG");
2569         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_FOGENABLE));
2570     }
2571 
2572     if (gl_info->supported[ARB_SAMPLER_OBJECTS])
2573         GL_EXTCALL(glBindSampler(0, 0));
2574     context_active_texture(context, gl_info, 0);
2575 
2576     sampler = context->rev_tex_unit_map[0];
2577     if (sampler != WINED3D_UNMAPPED_STAGE)
2578     {
2579         if (sampler < MAX_TEXTURES)
2580         {
2581             context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_TEXTURE0 + sampler));
2582             context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3D_TSS_COLOR_OP));
2583         }
2584         context_invalidate_state(context, STATE_SAMPLER(sampler));
2585     }
2586 
2587     /* Other misc states */
2588     gl_info->gl_ops.gl.p_glDisable(GL_DEPTH_TEST);
2589     checkGLcall("glDisable GL_DEPTH_TEST");
2590     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZENABLE));
2591     gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2592     checkGLcall("glDisable GL_BLEND");
2593     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
2594     gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2595     checkGLcall("glDisable GL_CULL_FACE");
2596     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CULLMODE));
2597     gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2598     checkGLcall("glDisable GL_STENCIL_TEST");
2599     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILENABLE));
2600     gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2601     checkGLcall("glDisable GL_SCISSOR_TEST");
2602     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
2603     if (gl_info->supported[ARB_POINT_SPRITE])
2604     {
2605         gl_info->gl_ops.gl.p_glDisable(GL_POINT_SPRITE_ARB);
2606         checkGLcall("glDisable GL_POINT_SPRITE_ARB");
2607         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE));
2608     }
2609     gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE);
2610     checkGLcall("glColorMask");
2611     for (i = 0; i < MAX_RENDER_TARGETS; ++i)
2612         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITE(i)));
2613     if (gl_info->supported[EXT_SECONDARY_COLOR])
2614     {
2615         gl_info->gl_ops.gl.p_glDisable(GL_COLOR_SUM_EXT);
2616         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SPECULARENABLE));
2617         checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
2618     }
2619 
2620     context->last_was_rhw = TRUE;
2621     context_invalidate_state(context, STATE_VDECL); /* because of last_was_rhw = TRUE */
2622 
2623     context_enable_clip_distances(context, 0);
2624     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CLIPPING));
2625 
2626     /* FIXME: Make draw_textured_quad() able to work with a upper left origin. */
2627     if (gl_info->supported[ARB_CLIP_CONTROL])
2628         GL_EXTCALL(glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE));
2629 
2630     set_blit_dimension(gl_info, rt_size.cx, rt_size.cy);
2631 
2632     /* Disable shaders */
2633     device->shader_backend->shader_disable(device->shader_priv, context);
2634 
2635     context->blit_w = rt_size.cx;
2636     context->blit_h = rt_size.cy;
2637     context_invalidate_state(context, STATE_VIEWPORT);
2638     context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
2639 }
2640 
is_rt_mask_onscreen(DWORD rt_mask)2641 static inline BOOL is_rt_mask_onscreen(DWORD rt_mask)
2642 {
2643     return rt_mask & (1u << 31);
2644 }
2645 
draw_buffer_from_rt_mask(DWORD rt_mask)2646 static inline GLenum draw_buffer_from_rt_mask(DWORD rt_mask)
2647 {
2648     return rt_mask & ~(1u << 31);
2649 }
2650 
2651 /* Context activation is done by the caller. */
context_apply_draw_buffers(struct wined3d_context * context,DWORD rt_mask)2652 static void context_apply_draw_buffers(struct wined3d_context *context, DWORD rt_mask)
2653 {
2654     const struct wined3d_gl_info *gl_info = context->gl_info;
2655     GLenum draw_buffers[MAX_RENDER_TARGET_VIEWS];
2656 
2657     if (!rt_mask)
2658     {
2659         gl_info->gl_ops.gl.p_glDrawBuffer(GL_NONE);
2660     }
2661     else if (is_rt_mask_onscreen(rt_mask))
2662     {
2663         gl_info->gl_ops.gl.p_glDrawBuffer(draw_buffer_from_rt_mask(rt_mask));
2664     }
2665     else
2666     {
2667         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2668         {
2669             unsigned int i = 0;
2670 
2671             while (rt_mask)
2672             {
2673                 if (rt_mask & 1)
2674                     draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
2675                 else
2676                     draw_buffers[i] = GL_NONE;
2677 
2678                 rt_mask >>= 1;
2679                 ++i;
2680             }
2681 
2682             if (gl_info->supported[ARB_DRAW_BUFFERS])
2683             {
2684                 GL_EXTCALL(glDrawBuffers(i, draw_buffers));
2685             }
2686             else
2687             {
2688                 gl_info->gl_ops.gl.p_glDrawBuffer(draw_buffers[0]);
2689             }
2690         }
2691         else
2692         {
2693             ERR("Unexpected draw buffers mask with backbuffer ORM.\n");
2694         }
2695     }
2696 
2697     checkGLcall("apply draw buffers");
2698 }
2699 
2700 /* Context activation is done by the caller. */
context_set_draw_buffer(struct wined3d_context * context,GLenum buffer)2701 void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer)
2702 {
2703     const struct wined3d_gl_info *gl_info = context->gl_info;
2704     DWORD *current_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2705     DWORD new_mask = context_generate_rt_mask(buffer);
2706 
2707     if (new_mask == *current_mask)
2708         return;
2709 
2710     gl_info->gl_ops.gl.p_glDrawBuffer(buffer);
2711     checkGLcall("glDrawBuffer()");
2712 
2713     *current_mask = new_mask;
2714 }
2715 
2716 /* Context activation is done by the caller. */
context_active_texture(struct wined3d_context * context,const struct wined3d_gl_info * gl_info,unsigned int unit)2717 void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info, unsigned int unit)
2718 {
2719     GL_EXTCALL(glActiveTexture(GL_TEXTURE0 + unit));
2720     checkGLcall("glActiveTexture");
2721     context->active_texture = unit;
2722 }
2723 
context_bind_bo(struct wined3d_context * context,GLenum binding,GLuint name)2724 void context_bind_bo(struct wined3d_context *context, GLenum binding, GLuint name)
2725 {
2726     const struct wined3d_gl_info *gl_info = context->gl_info;
2727 
2728     if (binding == GL_ELEMENT_ARRAY_BUFFER)
2729         context_invalidate_state(context, STATE_INDEXBUFFER);
2730 
2731     GL_EXTCALL(glBindBuffer(binding, name));
2732 }
2733 
context_bind_texture(struct wined3d_context * context,GLenum target,GLuint name)2734 void context_bind_texture(struct wined3d_context *context, GLenum target, GLuint name)
2735 {
2736     const struct wined3d_dummy_textures *textures = &context->device->dummy_textures;
2737     const struct wined3d_gl_info *gl_info = context->gl_info;
2738     DWORD unit = context->active_texture;
2739     DWORD old_texture_type = context->texture_type[unit];
2740 
2741     if (name)
2742     {
2743         gl_info->gl_ops.gl.p_glBindTexture(target, name);
2744     }
2745     else
2746     {
2747         target = GL_NONE;
2748     }
2749 
2750     if (old_texture_type != target)
2751     {
2752         switch (old_texture_type)
2753         {
2754             case GL_NONE:
2755                 /* nothing to do */
2756                 break;
2757             case GL_TEXTURE_1D:
2758                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, textures->tex_1d);
2759                 checkGLcall("glBindTexture");
2760                 break;
2761             case GL_TEXTURE_1D_ARRAY:
2762                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D_ARRAY, textures->tex_1d_array);
2763                 checkGLcall("glBindTexture");
2764                 break;
2765             case GL_TEXTURE_2D:
2766                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, textures->tex_2d);
2767                 break;
2768             case GL_TEXTURE_2D_ARRAY:
2769                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_ARRAY, textures->tex_2d_array);
2770                 break;
2771             case GL_TEXTURE_RECTANGLE_ARB:
2772                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textures->tex_rect);
2773                 break;
2774             case GL_TEXTURE_CUBE_MAP:
2775                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, textures->tex_cube);
2776                 break;
2777             case GL_TEXTURE_CUBE_MAP_ARRAY:
2778                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, textures->tex_cube_array);
2779                 break;
2780             case GL_TEXTURE_3D:
2781                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, textures->tex_3d);
2782                 break;
2783             case GL_TEXTURE_BUFFER:
2784                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_BUFFER, textures->tex_buffer);
2785                 break;
2786             case GL_TEXTURE_2D_MULTISAMPLE:
2787                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textures->tex_2d_ms);
2788                 break;
2789             case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
2790                 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, textures->tex_2d_ms_array);
2791                 break;
2792             default:
2793                 ERR("Unexpected texture target %#x.\n", old_texture_type);
2794         }
2795 
2796         context->texture_type[unit] = target;
2797     }
2798 
2799     checkGLcall("bind texture");
2800 }
2801 
context_map_bo_address(struct wined3d_context * context,const struct wined3d_bo_address * data,size_t size,GLenum binding,DWORD flags)2802 void *context_map_bo_address(struct wined3d_context *context,
2803         const struct wined3d_bo_address *data, size_t size, GLenum binding, DWORD flags)
2804 {
2805     const struct wined3d_gl_info *gl_info;
2806     BYTE *memory;
2807 
2808     if (!data->buffer_object)
2809         return data->addr;
2810 
2811     gl_info = context->gl_info;
2812     context_bind_bo(context, binding, data->buffer_object);
2813 
2814     if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
2815     {
2816         GLbitfield map_flags = wined3d_resource_gl_map_flags(flags) & ~GL_MAP_FLUSH_EXPLICIT_BIT;
2817         memory = GL_EXTCALL(glMapBufferRange(binding, (INT_PTR)data->addr, size, map_flags));
2818     }
2819     else
2820     {
2821         memory = GL_EXTCALL(glMapBuffer(binding, wined3d_resource_gl_legacy_map_flags(flags)));
2822         memory += (INT_PTR)data->addr;
2823     }
2824 
2825     context_bind_bo(context, binding, 0);
2826     checkGLcall("Map buffer object");
2827 
2828     return memory;
2829 }
2830 
context_unmap_bo_address(struct wined3d_context * context,const struct wined3d_bo_address * data,GLenum binding)2831 void context_unmap_bo_address(struct wined3d_context *context,
2832         const struct wined3d_bo_address *data, GLenum binding)
2833 {
2834     const struct wined3d_gl_info *gl_info;
2835 
2836     if (!data->buffer_object)
2837         return;
2838 
2839     gl_info = context->gl_info;
2840     context_bind_bo(context, binding, data->buffer_object);
2841     GL_EXTCALL(glUnmapBuffer(binding));
2842     context_bind_bo(context, binding, 0);
2843     checkGLcall("Unmap buffer object");
2844 }
2845 
context_copy_bo_address(struct wined3d_context * context,const struct wined3d_bo_address * dst,GLenum dst_binding,const struct wined3d_bo_address * src,GLenum src_binding,size_t size)2846 void context_copy_bo_address(struct wined3d_context *context,
2847         const struct wined3d_bo_address *dst, GLenum dst_binding,
2848         const struct wined3d_bo_address *src, GLenum src_binding, size_t size)
2849 {
2850     const struct wined3d_gl_info *gl_info;
2851     BYTE *dst_ptr, *src_ptr;
2852 
2853     gl_info = context->gl_info;
2854 
2855     if (dst->buffer_object && src->buffer_object)
2856     {
2857         if (gl_info->supported[ARB_COPY_BUFFER])
2858         {
2859             GL_EXTCALL(glBindBuffer(GL_COPY_READ_BUFFER, src->buffer_object));
2860             GL_EXTCALL(glBindBuffer(GL_COPY_WRITE_BUFFER, dst->buffer_object));
2861             GL_EXTCALL(glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
2862                     (GLintptr)src->addr, (GLintptr)dst->addr, size));
2863             checkGLcall("direct buffer copy");
2864         }
2865         else
2866         {
2867             src_ptr = context_map_bo_address(context, src, size, src_binding, WINED3D_MAP_READ);
2868             dst_ptr = context_map_bo_address(context, dst, size, dst_binding, WINED3D_MAP_WRITE);
2869 
2870             memcpy(dst_ptr, src_ptr, size);
2871 
2872             context_unmap_bo_address(context, dst, dst_binding);
2873             context_unmap_bo_address(context, src, src_binding);
2874         }
2875     }
2876     else if (!dst->buffer_object && src->buffer_object)
2877     {
2878         context_bind_bo(context, src_binding, src->buffer_object);
2879         GL_EXTCALL(glGetBufferSubData(src_binding, (GLintptr)src->addr, size, dst->addr));
2880         checkGLcall("buffer download");
2881     }
2882     else if (dst->buffer_object && !src->buffer_object)
2883     {
2884         context_bind_bo(context, dst_binding, dst->buffer_object);
2885         GL_EXTCALL(glBufferSubData(dst_binding, (GLintptr)dst->addr, size, src->addr));
2886         checkGLcall("buffer upload");
2887     }
2888     else
2889     {
2890         memcpy(dst->addr, src->addr, size);
2891     }
2892 }
2893 
context_set_render_offscreen(struct wined3d_context * context,BOOL offscreen)2894 static void context_set_render_offscreen(struct wined3d_context *context, BOOL offscreen)
2895 {
2896     if (context->render_offscreen == offscreen)
2897         return;
2898 
2899     context_invalidate_state(context, STATE_VIEWPORT);
2900     context_invalidate_state(context, STATE_SCISSORRECT);
2901     if (!context->gl_info->supported[ARB_CLIP_CONTROL])
2902     {
2903         context_invalidate_state(context, STATE_FRONTFACE);
2904         context_invalidate_state(context, STATE_POINTSPRITECOORDORIGIN);
2905         context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
2906     }
2907     context_invalidate_state(context, STATE_SHADER(WINED3D_SHADER_TYPE_DOMAIN));
2908     if (context->gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS])
2909         context_invalidate_state(context, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
2910     context->render_offscreen = offscreen;
2911 }
2912 
match_depth_stencil_format(const struct wined3d_format * existing,const struct wined3d_format * required)2913 static BOOL match_depth_stencil_format(const struct wined3d_format *existing,
2914         const struct wined3d_format *required)
2915 {
2916     if (existing == required)
2917         return TRUE;
2918     if ((existing->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FLOAT)
2919             != (required->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FLOAT))
2920         return FALSE;
2921     if (existing->depth_size < required->depth_size)
2922         return FALSE;
2923     /* If stencil bits are used the exact amount is required - otherwise
2924      * wrapping won't work correctly. */
2925     if (required->stencil_size && required->stencil_size != existing->stencil_size)
2926         return FALSE;
2927     return TRUE;
2928 }
2929 
2930 /* Context activation is done by the caller. */
context_validate_onscreen_formats(struct wined3d_context * context,const struct wined3d_rendertarget_view * depth_stencil)2931 static void context_validate_onscreen_formats(struct wined3d_context *context,
2932         const struct wined3d_rendertarget_view *depth_stencil)
2933 {
2934     /* Onscreen surfaces are always in a swapchain */
2935     struct wined3d_swapchain *swapchain = context->current_rt.texture->swapchain;
2936 
2937     if (context->render_offscreen || !depth_stencil) return;
2938     if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->format)) return;
2939 
2940     /* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
2941      * or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
2942      * format. */
2943     WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
2944 
2945     /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
2946     if (!(wined3d_texture_load_location(context->current_rt.texture, context->current_rt.sub_resource_idx,
2947             context, WINED3D_LOCATION_TEXTURE_RGB)))
2948         ERR("Failed to load location.\n");
2949     swapchain->render_to_fbo = TRUE;
2950     swapchain_update_draw_bindings(swapchain);
2951     context_set_render_offscreen(context, TRUE);
2952 }
2953 
context_get_offscreen_gl_buffer(const struct wined3d_context * context)2954 GLenum context_get_offscreen_gl_buffer(const struct wined3d_context *context)
2955 {
2956     switch (wined3d_settings.offscreen_rendering_mode)
2957     {
2958         case ORM_FBO:
2959             return GL_COLOR_ATTACHMENT0;
2960 
2961         case ORM_BACKBUFFER:
2962             return context->aux_buffers > 0 ? GL_AUX0 : GL_BACK;
2963 
2964         default:
2965             FIXME("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
2966             return GL_BACK;
2967     }
2968 }
2969 
context_generate_rt_mask_no_fbo(const struct wined3d_context * context,struct wined3d_texture * rt)2970 static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_context *context, struct wined3d_texture *rt)
2971 {
2972     if (!rt || rt->resource.format->id == WINED3DFMT_NULL)
2973         return 0;
2974     else if (rt->swapchain)
2975         return context_generate_rt_mask_from_resource(&rt->resource);
2976     else
2977         return context_generate_rt_mask(context_get_offscreen_gl_buffer(context));
2978 }
2979 
2980 /* Context activation is done by the caller. */
context_apply_blit_state(struct wined3d_context * context,const struct wined3d_device * device)2981 void context_apply_blit_state(struct wined3d_context *context, const struct wined3d_device *device)
2982 {
2983     struct wined3d_texture *rt = context->current_rt.texture;
2984     struct wined3d_surface *surface;
2985     DWORD rt_mask, *cur_mask;
2986 
2987     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2988     {
2989         if (context->render_offscreen)
2990         {
2991             wined3d_texture_load(rt, context, FALSE);
2992 
2993             surface = rt->sub_resources[context->current_rt.sub_resource_idx].u.surface;
2994             context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, surface, NULL, rt->resource.draw_binding);
2995             if (rt->resource.format->id != WINED3DFMT_NULL)
2996                 rt_mask = 1;
2997             else
2998                 rt_mask = 0;
2999         }
3000         else
3001         {
3002             context->current_fbo = NULL;
3003             context_bind_fbo(context, GL_FRAMEBUFFER, 0);
3004             rt_mask = context_generate_rt_mask_from_resource(&rt->resource);
3005         }
3006     }
3007     else
3008     {
3009         rt_mask = context_generate_rt_mask_no_fbo(context, rt);
3010     }
3011 
3012     cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3013 
3014     if (rt_mask != *cur_mask)
3015     {
3016         context_apply_draw_buffers(context, rt_mask);
3017         *cur_mask = rt_mask;
3018     }
3019 
3020     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3021     {
3022         context_check_fbo_status(context, GL_FRAMEBUFFER);
3023     }
3024 
3025     SetupForBlit(device, context);
3026     context_invalidate_state(context, STATE_FRAMEBUFFER);
3027 }
3028 
have_framebuffer_attachment(unsigned int rt_count,struct wined3d_rendertarget_view * const * rts,const struct wined3d_rendertarget_view * ds)3029 static BOOL have_framebuffer_attachment(unsigned int rt_count, struct wined3d_rendertarget_view * const *rts,
3030         const struct wined3d_rendertarget_view *ds)
3031 {
3032     unsigned int i;
3033 
3034     if (ds)
3035         return TRUE;
3036 
3037     for (i = 0; i < rt_count; ++i)
3038     {
3039         if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
3040             return TRUE;
3041     }
3042 
3043     return FALSE;
3044 }
3045 
3046 /* Context activation is done by the caller. */
context_apply_clear_state(struct wined3d_context * context,const struct wined3d_state * state,UINT rt_count,const struct wined3d_fb_state * fb)3047 BOOL context_apply_clear_state(struct wined3d_context *context, const struct wined3d_state *state,
3048         UINT rt_count, const struct wined3d_fb_state *fb)
3049 {
3050     struct wined3d_rendertarget_view * const *rts = fb->render_targets;
3051     struct wined3d_rendertarget_view *dsv = fb->depth_stencil;
3052     const struct wined3d_gl_info *gl_info = context->gl_info;
3053     DWORD rt_mask = 0, *cur_mask;
3054     unsigned int i;
3055 
3056     if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != state->fb
3057             || rt_count != gl_info->limits.buffers)
3058     {
3059         if (!have_framebuffer_attachment(rt_count, rts, dsv))
3060         {
3061             WARN("Invalid render target config, need at least one attachment.\n");
3062             return FALSE;
3063         }
3064 
3065         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3066         {
3067             context_validate_onscreen_formats(context, dsv);
3068 
3069             if (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource))
3070             {
3071                 memset(context->blit_targets, 0, sizeof(context->blit_targets));
3072                 for (i = 0; i < rt_count; ++i)
3073                 {
3074                     if (rts[i])
3075                     {
3076                         context->blit_targets[i].gl_view = rts[i]->gl_view;
3077                         context->blit_targets[i].resource = rts[i]->resource;
3078                         context->blit_targets[i].sub_resource_idx = rts[i]->sub_resource_idx;
3079                         context->blit_targets[i].layer_count = rts[i]->layer_count;
3080                     }
3081                     if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
3082                         rt_mask |= (1u << i);
3083                 }
3084                 context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets,
3085                         wined3d_rendertarget_view_get_surface(dsv),
3086                         rt_count ? rts[0]->resource->draw_binding : 0,
3087                         dsv ? dsv->resource->draw_binding : 0);
3088             }
3089             else
3090             {
3091                 context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL,
3092                         WINED3D_LOCATION_DRAWABLE, WINED3D_LOCATION_DRAWABLE);
3093                 rt_mask = context_generate_rt_mask_from_resource(rts[0]->resource);
3094             }
3095 
3096             /* If the framebuffer is not the device's fb the device's fb has to be reapplied
3097              * next draw. Otherwise we could mark the framebuffer state clean here, once the
3098              * state management allows this */
3099             context_invalidate_state(context, STATE_FRAMEBUFFER);
3100         }
3101         else
3102         {
3103             rt_mask = context_generate_rt_mask_no_fbo(context,
3104                     rt_count ? wined3d_rendertarget_view_get_surface(rts[0])->container : NULL);
3105         }
3106     }
3107     else if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3108             && (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource)))
3109     {
3110         for (i = 0; i < rt_count; ++i)
3111         {
3112             if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
3113                 rt_mask |= (1u << i);
3114         }
3115     }
3116     else
3117     {
3118         rt_mask = context_generate_rt_mask_no_fbo(context,
3119                 rt_count ? wined3d_rendertarget_view_get_surface(rts[0])->container : NULL);
3120     }
3121 
3122     cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3123 
3124     if (rt_mask != *cur_mask)
3125     {
3126         context_apply_draw_buffers(context, rt_mask);
3127         *cur_mask = rt_mask;
3128         context_invalidate_state(context, STATE_FRAMEBUFFER);
3129     }
3130 
3131     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3132     {
3133         context_check_fbo_status(context, GL_FRAMEBUFFER);
3134     }
3135 
3136     context->last_was_blit = FALSE;
3137 
3138     /* Blending and clearing should be orthogonal, but tests on the nvidia
3139      * driver show that disabling blending when clearing improves the clearing
3140      * performance incredibly. */
3141     gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
3142     gl_info->gl_ops.gl.p_glEnable(GL_SCISSOR_TEST);
3143     if (rt_count && gl_info->supported[ARB_FRAMEBUFFER_SRGB])
3144     {
3145         if (needs_srgb_write(context, state, fb))
3146             gl_info->gl_ops.gl.p_glEnable(GL_FRAMEBUFFER_SRGB);
3147         else
3148             gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB);
3149         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
3150     }
3151     checkGLcall("setting up state for clear");
3152 
3153     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
3154     context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
3155     context_invalidate_state(context, STATE_SCISSORRECT);
3156 
3157     return TRUE;
3158 }
3159 
find_draw_buffers_mask(const struct wined3d_context * context,const struct wined3d_state * state)3160 static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_state *state)
3161 {
3162     struct wined3d_rendertarget_view * const *rts = state->fb->render_targets;
3163     struct wined3d_shader *ps = state->shader[WINED3D_SHADER_TYPE_PIXEL];
3164     DWORD rt_mask, mask;
3165     unsigned int i;
3166 
3167     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO)
3168         return context_generate_rt_mask_no_fbo(context, wined3d_rendertarget_view_get_surface(rts[0])->container);
3169     else if (!context->render_offscreen)
3170         return context_generate_rt_mask_from_resource(rts[0]->resource);
3171 
3172     /* If we attach more buffers than supported in dual blend mode, the NVIDIA
3173      * driver generates the following error:
3174      *      GL_INVALID_OPERATION error generated. State(s) are invalid: blend.
3175      * DX11 does not treat this configuration as invalid, so disable the unused ones.
3176      */
3177     rt_mask = ps ? ps->reg_maps.rt_mask : 1;
3178     if (wined3d_dualblend_enabled(state, context->gl_info))
3179         rt_mask &= context->d3d_info->valid_dual_rt_mask;
3180     else
3181         rt_mask &= context->d3d_info->valid_rt_mask;
3182 
3183     mask = rt_mask;
3184     i = 0;
3185     while (mask)
3186     {
3187         i = wined3d_bit_scan(&mask);
3188         if (!rts[i] || rts[i]->format->id == WINED3DFMT_NULL)
3189             rt_mask &= ~(1u << i);
3190     }
3191 
3192     return rt_mask;
3193 }
3194 
3195 /* Context activation is done by the caller. */
context_state_fb(struct wined3d_context * context,const struct wined3d_state * state,DWORD state_id)3196 void context_state_fb(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
3197 {
3198     DWORD rt_mask = find_draw_buffers_mask(context, state);
3199     const struct wined3d_fb_state *fb = state->fb;
3200     DWORD color_location = 0;
3201     DWORD *cur_mask;
3202 
3203     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3204     {
3205         if (!context->render_offscreen)
3206         {
3207             context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL,
3208                     WINED3D_LOCATION_DRAWABLE, WINED3D_LOCATION_DRAWABLE);
3209         }
3210         else
3211         {
3212             unsigned int i;
3213 
3214             memset(context->blit_targets, 0, sizeof(context->blit_targets));
3215             for (i = 0; i < context->gl_info->limits.buffers; ++i)
3216             {
3217                 if (!fb->render_targets[i])
3218                     continue;
3219 
3220                 context->blit_targets[i].gl_view = fb->render_targets[i]->gl_view;
3221                 context->blit_targets[i].resource = fb->render_targets[i]->resource;
3222                 context->blit_targets[i].sub_resource_idx = fb->render_targets[i]->sub_resource_idx;
3223                 context->blit_targets[i].layer_count = fb->render_targets[i]->layer_count;
3224 
3225                 if (!color_location)
3226                     color_location = fb->render_targets[i]->resource->draw_binding;
3227             }
3228             context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets,
3229                     wined3d_rendertarget_view_get_surface(fb->depth_stencil),
3230                     color_location, fb->depth_stencil ? fb->depth_stencil->resource->draw_binding : 0);
3231         }
3232     }
3233 
3234     cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3235     if (rt_mask != *cur_mask)
3236     {
3237         context_apply_draw_buffers(context, rt_mask);
3238         *cur_mask = rt_mask;
3239     }
3240     context->constant_update_mask |= WINED3D_SHADER_CONST_PS_Y_CORR;
3241 }
3242 
context_map_stage(struct wined3d_context * context,DWORD stage,DWORD unit)3243 static void context_map_stage(struct wined3d_context *context, DWORD stage, DWORD unit)
3244 {
3245     DWORD i = context->rev_tex_unit_map[unit];
3246     DWORD j = context->tex_unit_map[stage];
3247 
3248     TRACE("Mapping stage %u to unit %u.\n", stage, unit);
3249     context->tex_unit_map[stage] = unit;
3250     if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3251         context->tex_unit_map[i] = WINED3D_UNMAPPED_STAGE;
3252 
3253     context->rev_tex_unit_map[unit] = stage;
3254     if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3255         context->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3256 }
3257 
context_invalidate_texture_stage(struct wined3d_context * context,DWORD stage)3258 static void context_invalidate_texture_stage(struct wined3d_context *context, DWORD stage)
3259 {
3260     DWORD i;
3261 
3262     for (i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3263         context_invalidate_state(context, STATE_TEXTURESTAGE(stage, i));
3264 }
3265 
context_update_fixed_function_usage_map(struct wined3d_context * context,const struct wined3d_state * state)3266 static void context_update_fixed_function_usage_map(struct wined3d_context *context,
3267         const struct wined3d_state *state)
3268 {
3269     UINT i, start, end;
3270 
3271     context->fixed_function_usage_map = 0;
3272     for (i = 0; i < MAX_TEXTURES; ++i)
3273     {
3274         enum wined3d_texture_op color_op = state->texture_states[i][WINED3D_TSS_COLOR_OP];
3275         enum wined3d_texture_op alpha_op = state->texture_states[i][WINED3D_TSS_ALPHA_OP];
3276         DWORD color_arg1 = state->texture_states[i][WINED3D_TSS_COLOR_ARG1] & WINED3DTA_SELECTMASK;
3277         DWORD color_arg2 = state->texture_states[i][WINED3D_TSS_COLOR_ARG2] & WINED3DTA_SELECTMASK;
3278         DWORD color_arg3 = state->texture_states[i][WINED3D_TSS_COLOR_ARG0] & WINED3DTA_SELECTMASK;
3279         DWORD alpha_arg1 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG1] & WINED3DTA_SELECTMASK;
3280         DWORD alpha_arg2 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG2] & WINED3DTA_SELECTMASK;
3281         DWORD alpha_arg3 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG0] & WINED3DTA_SELECTMASK;
3282 
3283         /* Not used, and disable higher stages. */
3284         if (color_op == WINED3D_TOP_DISABLE)
3285             break;
3286 
3287         if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG2)
3288                 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG1)
3289                 || ((color_arg3 == WINED3DTA_TEXTURE)
3290                     && (color_op == WINED3D_TOP_MULTIPLY_ADD || color_op == WINED3D_TOP_LERP))
3291                 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG2)
3292                 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG1)
3293                 || ((alpha_arg3 == WINED3DTA_TEXTURE)
3294                     && (alpha_op == WINED3D_TOP_MULTIPLY_ADD || alpha_op == WINED3D_TOP_LERP)))
3295             context->fixed_function_usage_map |= (1u << i);
3296 
3297         if ((color_op == WINED3D_TOP_BUMPENVMAP || color_op == WINED3D_TOP_BUMPENVMAP_LUMINANCE)
3298                 && i < MAX_TEXTURES - 1)
3299             context->fixed_function_usage_map |= (1u << (i + 1));
3300     }
3301 
3302     if (i < context->lowest_disabled_stage)
3303     {
3304         start = i;
3305         end = context->lowest_disabled_stage;
3306     }
3307     else
3308     {
3309         start = context->lowest_disabled_stage;
3310         end = i;
3311     }
3312 
3313     context->lowest_disabled_stage = i;
3314     for (i = start + 1; i < end; ++i)
3315     {
3316         context_invalidate_state(context, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3317     }
3318 }
3319 
context_map_fixed_function_samplers(struct wined3d_context * context,const struct wined3d_state * state)3320 static void context_map_fixed_function_samplers(struct wined3d_context *context,
3321         const struct wined3d_state *state)
3322 {
3323     const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3324     unsigned int i, tex;
3325     WORD ffu_map;
3326 
3327     ffu_map = context->fixed_function_usage_map;
3328 
3329     if (d3d_info->limits.ffp_textures == d3d_info->limits.ffp_blend_stages
3330             || context->lowest_disabled_stage <= d3d_info->limits.ffp_textures)
3331     {
3332         for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3333         {
3334             if (!(ffu_map & 1))
3335                 continue;
3336 
3337             if (context->tex_unit_map[i] != i)
3338             {
3339                 context_map_stage(context, i, i);
3340                 context_invalidate_state(context, STATE_SAMPLER(i));
3341                 context_invalidate_texture_stage(context, i);
3342             }
3343         }
3344         return;
3345     }
3346 
3347     /* Now work out the mapping */
3348     tex = 0;
3349     for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3350     {
3351         if (!(ffu_map & 1))
3352             continue;
3353 
3354         if (context->tex_unit_map[i] != tex)
3355         {
3356             context_map_stage(context, i, tex);
3357             context_invalidate_state(context, STATE_SAMPLER(i));
3358             context_invalidate_texture_stage(context, i);
3359         }
3360 
3361         ++tex;
3362     }
3363 }
3364 
context_map_psamplers(struct wined3d_context * context,const struct wined3d_state * state)3365 static void context_map_psamplers(struct wined3d_context *context, const struct wined3d_state *state)
3366 {
3367     const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3368     const struct wined3d_shader_resource_info *resource_info =
3369             state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info;
3370     unsigned int i;
3371 
3372     for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
3373     {
3374         if (resource_info[i].type && context->tex_unit_map[i] != i)
3375         {
3376             context_map_stage(context, i, i);
3377             context_invalidate_state(context, STATE_SAMPLER(i));
3378             if (i < d3d_info->limits.ffp_blend_stages)
3379                 context_invalidate_texture_stage(context, i);
3380         }
3381     }
3382 }
3383 
context_unit_free_for_vs(const struct wined3d_context * context,const struct wined3d_shader_resource_info * ps_resource_info,DWORD unit)3384 static BOOL context_unit_free_for_vs(const struct wined3d_context *context,
3385         const struct wined3d_shader_resource_info *ps_resource_info, DWORD unit)
3386 {
3387     DWORD current_mapping = context->rev_tex_unit_map[unit];
3388 
3389     /* Not currently used */
3390     if (current_mapping == WINED3D_UNMAPPED_STAGE)
3391         return TRUE;
3392 
3393     if (current_mapping < MAX_FRAGMENT_SAMPLERS)
3394     {
3395         /* Used by a fragment sampler */
3396 
3397         if (!ps_resource_info)
3398         {
3399             /* No pixel shader, check fixed function */
3400             return current_mapping >= MAX_TEXTURES || !(context->fixed_function_usage_map & (1u << current_mapping));
3401         }
3402 
3403         /* Pixel shader, check the shader's sampler map */
3404         return !ps_resource_info[current_mapping].type;
3405     }
3406 
3407     return TRUE;
3408 }
3409 
context_map_vsamplers(struct wined3d_context * context,BOOL ps,const struct wined3d_state * state)3410 static void context_map_vsamplers(struct wined3d_context *context, BOOL ps, const struct wined3d_state *state)
3411 {
3412     const struct wined3d_shader_resource_info *vs_resource_info =
3413             state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.resource_info;
3414     const struct wined3d_shader_resource_info *ps_resource_info = NULL;
3415     const struct wined3d_gl_info *gl_info = context->gl_info;
3416     int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.graphics_samplers) - 1;
3417     int i;
3418 
3419     /* Note that we only care if a resource is used or not, not the
3420      * resource's specific type. Otherwise we'd need to call
3421      * shader_update_samplers() here for 1.x pixelshaders. */
3422     if (ps)
3423         ps_resource_info = state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info;
3424 
3425     for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
3426     {
3427         DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3428         if (vs_resource_info[i].type)
3429         {
3430             while (start >= 0)
3431             {
3432                 if (context_unit_free_for_vs(context, ps_resource_info, start))
3433                 {
3434                     if (context->tex_unit_map[vsampler_idx] != start)
3435                     {
3436                         context_map_stage(context, vsampler_idx, start);
3437                         context_invalidate_state(context, STATE_SAMPLER(vsampler_idx));
3438                     }
3439 
3440                     --start;
3441                     break;
3442                 }
3443 
3444                 --start;
3445             }
3446             if (context->tex_unit_map[vsampler_idx] == WINED3D_UNMAPPED_STAGE)
3447                 WARN("Couldn't find a free texture unit for vertex sampler %u.\n", i);
3448         }
3449     }
3450 }
3451 
context_update_tex_unit_map(struct wined3d_context * context,const struct wined3d_state * state)3452 static void context_update_tex_unit_map(struct wined3d_context *context, const struct wined3d_state *state)
3453 {
3454     const struct wined3d_gl_info *gl_info = context->gl_info;
3455     BOOL vs = use_vs(state);
3456     BOOL ps = use_ps(state);
3457 
3458     if (!ps)
3459         context_update_fixed_function_usage_map(context, state);
3460 
3461     /* Try to go for a 1:1 mapping of the samplers when possible. Pixel shaders
3462      * need a 1:1 map at the moment.
3463      * When the mapping of a stage is changed, sampler and ALL texture stage
3464      * states have to be reset. */
3465 
3466     if (gl_info->limits.graphics_samplers >= MAX_COMBINED_SAMPLERS)
3467         return;
3468 
3469     if (ps)
3470         context_map_psamplers(context, state);
3471     else
3472         context_map_fixed_function_samplers(context, state);
3473 
3474     if (vs)
3475         context_map_vsamplers(context, ps, state);
3476 }
3477 
3478 /* Context activation is done by the caller. */
context_state_drawbuf(struct wined3d_context * context,const struct wined3d_state * state,DWORD state_id)3479 void context_state_drawbuf(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
3480 {
3481     DWORD rt_mask, *cur_mask;
3482 
3483     if (isStateDirty(context, STATE_FRAMEBUFFER)) return;
3484 
3485     cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3486     rt_mask = find_draw_buffers_mask(context, state);
3487     if (rt_mask != *cur_mask)
3488     {
3489         context_apply_draw_buffers(context, rt_mask);
3490         *cur_mask = rt_mask;
3491     }
3492 }
3493 
fixed_get_input(BYTE usage,BYTE usage_idx,unsigned int * regnum)3494 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
3495 {
3496     if ((usage == WINED3D_DECL_USAGE_POSITION || usage == WINED3D_DECL_USAGE_POSITIONT) && !usage_idx)
3497         *regnum = WINED3D_FFP_POSITION;
3498     else if (usage == WINED3D_DECL_USAGE_BLEND_WEIGHT && !usage_idx)
3499         *regnum = WINED3D_FFP_BLENDWEIGHT;
3500     else if (usage == WINED3D_DECL_USAGE_BLEND_INDICES && !usage_idx)
3501         *regnum = WINED3D_FFP_BLENDINDICES;
3502     else if (usage == WINED3D_DECL_USAGE_NORMAL && !usage_idx)
3503         *regnum = WINED3D_FFP_NORMAL;
3504     else if (usage == WINED3D_DECL_USAGE_PSIZE && !usage_idx)
3505         *regnum = WINED3D_FFP_PSIZE;
3506     else if (usage == WINED3D_DECL_USAGE_COLOR && !usage_idx)
3507         *regnum = WINED3D_FFP_DIFFUSE;
3508     else if (usage == WINED3D_DECL_USAGE_COLOR && usage_idx == 1)
3509         *regnum = WINED3D_FFP_SPECULAR;
3510     else if (usage == WINED3D_DECL_USAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
3511         *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
3512     else
3513     {
3514         WARN("Unsupported input stream [usage=%s, usage_idx=%u].\n", debug_d3ddeclusage(usage), usage_idx);
3515         *regnum = ~0u;
3516         return FALSE;
3517     }
3518 
3519     return TRUE;
3520 }
3521 
3522 /* Context activation is done by the caller. */
wined3d_stream_info_from_declaration(struct wined3d_stream_info * stream_info,const struct wined3d_state * state,const struct wined3d_gl_info * gl_info,const struct wined3d_d3d_info * d3d_info)3523 void wined3d_stream_info_from_declaration(struct wined3d_stream_info *stream_info,
3524         const struct wined3d_state *state, const struct wined3d_gl_info *gl_info,
3525         const struct wined3d_d3d_info *d3d_info)
3526 {
3527     /* We need to deal with frequency data! */
3528     struct wined3d_vertex_declaration *declaration = state->vertex_declaration;
3529     BOOL generic_attributes = d3d_info->ffp_generic_attributes;
3530     BOOL use_vshader = use_vs(state);
3531     unsigned int i;
3532 
3533     stream_info->use_map = 0;
3534     stream_info->swizzle_map = 0;
3535     stream_info->position_transformed = 0;
3536 
3537     if (!declaration)
3538         return;
3539 
3540     stream_info->position_transformed = declaration->position_transformed;
3541 
3542     /* Translate the declaration into strided data. */
3543     for (i = 0; i < declaration->element_count; ++i)
3544     {
3545         const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
3546         const struct wined3d_stream_state *stream = &state->streams[element->input_slot];
3547         BOOL stride_used;
3548         unsigned int idx;
3549 
3550         TRACE("%p Element %p (%u of %u).\n", declaration->elements,
3551                 element, i + 1, declaration->element_count);
3552 
3553         if (!stream->buffer)
3554             continue;
3555 
3556         TRACE("offset %u input_slot %u usage_idx %d.\n", element->offset, element->input_slot, element->usage_idx);
3557 
3558         if (use_vshader)
3559         {
3560             if (element->output_slot == WINED3D_OUTPUT_SLOT_UNUSED)
3561             {
3562                 stride_used = FALSE;
3563             }
3564             else if (element->output_slot == WINED3D_OUTPUT_SLOT_SEMANTIC)
3565             {
3566                 /* TODO: Assuming vertexdeclarations are usually used with the
3567                  * same or a similar shader, it might be worth it to store the
3568                  * last used output slot and try that one first. */
3569                 stride_used = vshader_get_input(state->shader[WINED3D_SHADER_TYPE_VERTEX],
3570                         element->usage, element->usage_idx, &idx);
3571             }
3572             else
3573             {
3574                 idx = element->output_slot;
3575                 stride_used = TRUE;
3576             }
3577         }
3578         else
3579         {
3580             if (!generic_attributes && !element->ffp_valid)
3581             {
3582                 WARN("Skipping unsupported fixed function element of format %s and usage %s.\n",
3583                         debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
3584                 stride_used = FALSE;
3585             }
3586             else
3587             {
3588                 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
3589             }
3590         }
3591 
3592         if (stride_used)
3593         {
3594             TRACE("Load %s array %u [usage %s, usage_idx %u, "
3595                     "input_slot %u, offset %u, stride %u, format %s, class %s, step_rate %u].\n",
3596                     use_vshader ? "shader": "fixed function", idx,
3597                     debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
3598                     element->offset, stream->stride, debug_d3dformat(element->format->id),
3599                     debug_d3dinput_classification(element->input_slot_class), element->instance_data_step_rate);
3600 
3601             stream_info->elements[idx].format = element->format;
3602             stream_info->elements[idx].data.buffer_object = 0;
3603             stream_info->elements[idx].data.addr = (BYTE *)NULL + stream->offset + element->offset;
3604             stream_info->elements[idx].stride = stream->stride;
3605             stream_info->elements[idx].stream_idx = element->input_slot;
3606             if (stream->flags & WINED3DSTREAMSOURCE_INSTANCEDATA)
3607             {
3608                 stream_info->elements[idx].divisor = 1;
3609             }
3610             else if (element->input_slot_class == WINED3D_INPUT_PER_INSTANCE_DATA)
3611             {
3612                 stream_info->elements[idx].divisor = element->instance_data_step_rate;
3613                 if (!element->instance_data_step_rate)
3614                     FIXME("Instance step rate 0 not implemented.\n");
3615             }
3616             else
3617             {
3618                 stream_info->elements[idx].divisor = 0;
3619             }
3620 
3621             if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
3622                     && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
3623             {
3624                 stream_info->swizzle_map |= 1u << idx;
3625             }
3626             stream_info->use_map |= 1u << idx;
3627         }
3628     }
3629 }
3630 
3631 /* Context activation is done by the caller. */
context_update_stream_info(struct wined3d_context * context,const struct wined3d_state * state)3632 static void context_update_stream_info(struct wined3d_context *context, const struct wined3d_state *state)
3633 {
3634     struct wined3d_stream_info *stream_info = &context->stream_info;
3635     const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3636     const struct wined3d_gl_info *gl_info = context->gl_info;
3637     DWORD prev_all_vbo = stream_info->all_vbo;
3638     unsigned int i;
3639     WORD map;
3640 
3641     wined3d_stream_info_from_declaration(stream_info, state, gl_info, d3d_info);
3642 
3643     stream_info->all_vbo = 1;
3644     context->buffer_fence_count = 0;
3645     for (i = 0, map = stream_info->use_map; map; map >>= 1, ++i)
3646     {
3647         struct wined3d_stream_info_element *element;
3648         struct wined3d_bo_address data;
3649         struct wined3d_buffer *buffer;
3650 
3651         if (!(map & 1))
3652             continue;
3653 
3654         element = &stream_info->elements[i];
3655         buffer = state->streams[element->stream_idx].buffer;
3656 
3657         /* We can't use VBOs if the base vertex index is negative. OpenGL
3658          * doesn't accept negative offsets (or rather offsets bigger than the
3659          * VBO, because the pointer is unsigned), so use system memory
3660          * sources. In most sane cases the pointer - offset will still be > 0,
3661          * otherwise it will wrap around to some big value. Hope that with the
3662          * indices the driver wraps it back internally. If not,
3663          * draw_primitive_immediate_mode() is needed, including a vertex buffer
3664          * path. */
3665         if (state->load_base_vertex_index < 0)
3666         {
3667             WARN_(d3d_perf)("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
3668                     state->load_base_vertex_index);
3669             element->data.buffer_object = 0;
3670             element->data.addr += (ULONG_PTR)wined3d_buffer_load_sysmem(buffer, context);
3671             if ((UINT_PTR)element->data.addr < -state->load_base_vertex_index * element->stride)
3672                 FIXME("System memory vertex data load offset is negative!\n");
3673         }
3674         else
3675         {
3676             wined3d_buffer_load(buffer, context, state);
3677             wined3d_buffer_get_memory(buffer, &data, buffer->locations);
3678             element->data.buffer_object = data.buffer_object;
3679             element->data.addr += (ULONG_PTR)data.addr;
3680         }
3681 
3682         if (!element->data.buffer_object)
3683             stream_info->all_vbo = 0;
3684 
3685         if (buffer->fence)
3686             context->buffer_fences[context->buffer_fence_count++] = buffer->fence;
3687 
3688         TRACE("Load array %u {%#x:%p}.\n", i, element->data.buffer_object, element->data.addr);
3689     }
3690 
3691     if (prev_all_vbo != stream_info->all_vbo)
3692         context_invalidate_state(context, STATE_INDEXBUFFER);
3693 
3694     context->use_immediate_mode_draw = FALSE;
3695 
3696     if (stream_info->all_vbo)
3697         return;
3698 
3699     if (use_vs(state))
3700     {
3701         if (state->vertex_declaration->half_float_conv_needed)
3702         {
3703             TRACE("Using immediate mode draw with vertex shaders for FLOAT16 conversion.\n");
3704             context->use_immediate_mode_draw = TRUE;
3705         }
3706     }
3707     else
3708     {
3709         WORD slow_mask = -!d3d_info->ffp_generic_attributes & (1u << WINED3D_FFP_PSIZE);
3710         slow_mask |= -(!gl_info->supported[ARB_VERTEX_ARRAY_BGRA] && !d3d_info->ffp_generic_attributes)
3711                 & ((1u << WINED3D_FFP_DIFFUSE) | (1u << WINED3D_FFP_SPECULAR) | (1u << WINED3D_FFP_BLENDWEIGHT));
3712 
3713         if ((stream_info->position_transformed && !d3d_info->xyzrhw)
3714                 || (stream_info->use_map & slow_mask))
3715             context->use_immediate_mode_draw = TRUE;
3716     }
3717 }
3718 
3719 /* Context activation is done by the caller. */
context_preload_texture(struct wined3d_context * context,const struct wined3d_state * state,unsigned int idx)3720 static void context_preload_texture(struct wined3d_context *context,
3721         const struct wined3d_state *state, unsigned int idx)
3722 {
3723     struct wined3d_texture *texture;
3724 
3725     if (!(texture = state->textures[idx]))
3726         return;
3727 
3728     wined3d_texture_load(texture, context, state->sampler_states[idx][WINED3D_SAMP_SRGB_TEXTURE]);
3729 }
3730 
3731 /* Context activation is done by the caller. */
context_preload_textures(struct wined3d_context * context,const struct wined3d_state * state)3732 static void context_preload_textures(struct wined3d_context *context, const struct wined3d_state *state)
3733 {
3734     unsigned int i;
3735 
3736     if (use_vs(state))
3737     {
3738         for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
3739         {
3740             if (state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.resource_info[i].type)
3741                 context_preload_texture(context, state, MAX_FRAGMENT_SAMPLERS + i);
3742         }
3743     }
3744 
3745     if (use_ps(state))
3746     {
3747         for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
3748         {
3749             if (state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info[i].type)
3750                 context_preload_texture(context, state, i);
3751         }
3752     }
3753     else
3754     {
3755         WORD ffu_map = context->fixed_function_usage_map;
3756 
3757         for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3758         {
3759             if (ffu_map & 1)
3760                 context_preload_texture(context, state, i);
3761         }
3762     }
3763 }
3764 
context_load_shader_resources(struct wined3d_context * context,const struct wined3d_state * state,unsigned int shader_mask)3765 static void context_load_shader_resources(struct wined3d_context *context, const struct wined3d_state *state,
3766         unsigned int shader_mask)
3767 {
3768     struct wined3d_shader_sampler_map_entry *entry;
3769     struct wined3d_shader_resource_view *view;
3770     struct wined3d_shader *shader;
3771     unsigned int i, j;
3772 
3773     for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
3774     {
3775         if (!(shader_mask & (1u << i)))
3776             continue;
3777 
3778         if (!(shader = state->shader[i]))
3779             continue;
3780 
3781         for (j = 0; j < WINED3D_MAX_CBS; ++j)
3782         {
3783             if (state->cb[i][j])
3784                 wined3d_buffer_load(state->cb[i][j], context, state);
3785         }
3786 
3787         for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
3788         {
3789             entry = &shader->reg_maps.sampler_map.entries[j];
3790 
3791             if (!(view = state->shader_resource_view[i][entry->resource_idx]))
3792                 continue;
3793 
3794             if (view->resource->type == WINED3D_RTYPE_BUFFER)
3795                 wined3d_buffer_load(buffer_from_resource(view->resource), context, state);
3796             else
3797                 wined3d_texture_load(texture_from_resource(view->resource), context, FALSE);
3798         }
3799     }
3800 }
3801 
context_bind_shader_resources(struct wined3d_context * context,const struct wined3d_state * state,enum wined3d_shader_type shader_type)3802 static void context_bind_shader_resources(struct wined3d_context *context,
3803         const struct wined3d_state *state, enum wined3d_shader_type shader_type)
3804 {
3805     unsigned int bind_idx, shader_sampler_count, base, count, i;
3806     const struct wined3d_device *device = context->device;
3807     struct wined3d_shader_sampler_map_entry *entry;
3808     struct wined3d_shader_resource_view *view;
3809     const struct wined3d_shader *shader;
3810     struct wined3d_sampler *sampler;
3811     const DWORD *tex_unit_map;
3812 
3813     if (!(shader = state->shader[shader_type]))
3814         return;
3815 
3816     tex_unit_map = context_get_tex_unit_mapping(context,
3817             &shader->reg_maps.shader_version, &base, &count);
3818 
3819     shader_sampler_count = shader->reg_maps.sampler_map.count;
3820     if (shader_sampler_count > count)
3821         FIXME("Shader %p needs %u samplers, but only %u are supported.\n",
3822                 shader, shader_sampler_count, count);
3823     count = min(shader_sampler_count, count);
3824 
3825     for (i = 0; i < count; ++i)
3826     {
3827         entry = &shader->reg_maps.sampler_map.entries[i];
3828         bind_idx = base + entry->bind_idx;
3829         if (tex_unit_map)
3830             bind_idx = tex_unit_map[bind_idx];
3831 
3832         if (!(view = state->shader_resource_view[shader_type][entry->resource_idx]))
3833         {
3834             WARN("No resource view bound at index %u, %u.\n", shader_type, entry->resource_idx);
3835             continue;
3836         }
3837 
3838         if (entry->sampler_idx == WINED3D_SAMPLER_DEFAULT)
3839             sampler = device->default_sampler;
3840         else if (!(sampler = state->sampler[shader_type][entry->sampler_idx]))
3841             sampler = device->null_sampler;
3842         wined3d_shader_resource_view_bind(view, bind_idx, sampler, context);
3843     }
3844 }
3845 
context_load_unordered_access_resources(struct wined3d_context * context,const struct wined3d_shader * shader,struct wined3d_unordered_access_view * const * views)3846 static void context_load_unordered_access_resources(struct wined3d_context *context,
3847         const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
3848 {
3849     struct wined3d_unordered_access_view *view;
3850     struct wined3d_texture *texture;
3851     struct wined3d_buffer *buffer;
3852     unsigned int i;
3853 
3854     context->uses_uavs = 0;
3855 
3856     if (!shader)
3857         return;
3858 
3859     for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
3860     {
3861         if (!(view = views[i]))
3862             continue;
3863 
3864         if (view->resource->type == WINED3D_RTYPE_BUFFER)
3865         {
3866             buffer = buffer_from_resource(view->resource);
3867             wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
3868             wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);
3869         }
3870         else
3871         {
3872             texture = texture_from_resource(view->resource);
3873             wined3d_texture_load(texture, context, FALSE);
3874             wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_TEXTURE_RGB);
3875         }
3876 
3877         context->uses_uavs = 1;
3878     }
3879 }
3880 
context_bind_unordered_access_views(struct wined3d_context * context,const struct wined3d_shader * shader,struct wined3d_unordered_access_view * const * views)3881 static void context_bind_unordered_access_views(struct wined3d_context *context,
3882         const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
3883 {
3884     const struct wined3d_gl_info *gl_info = context->gl_info;
3885     struct wined3d_unordered_access_view *view;
3886     GLuint texture_name;
3887     unsigned int i;
3888     GLint level;
3889 
3890     if (!shader)
3891         return;
3892 
3893     for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
3894     {
3895         if (!(view = views[i]))
3896         {
3897             if (shader->reg_maps.uav_resource_info[i].type)
3898                 WARN("No unordered access view bound at index %u.\n", i);
3899             GL_EXTCALL(glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R8));
3900             continue;
3901         }
3902 
3903         if (view->gl_view.name)
3904         {
3905             texture_name = view->gl_view.name;
3906             level = 0;
3907         }
3908         else if (view->resource->type != WINED3D_RTYPE_BUFFER)
3909         {
3910             struct wined3d_texture *texture = texture_from_resource(view->resource);
3911             texture_name = wined3d_texture_get_texture_name(texture, context, FALSE);
3912             level = view->desc.u.texture.level_idx;
3913         }
3914         else
3915         {
3916             FIXME("Unsupported buffer unordered access view.\n");
3917             GL_EXTCALL(glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R8));
3918             continue;
3919         }
3920 
3921         GL_EXTCALL(glBindImageTexture(i, texture_name, level, GL_TRUE, 0, GL_READ_WRITE,
3922                 view->format->glInternal));
3923 
3924         if (view->counter_bo)
3925             GL_EXTCALL(glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, view->counter_bo));
3926     }
3927     checkGLcall("Bind unordered access views");
3928 }
3929 
context_load_stream_output_buffers(struct wined3d_context * context,const struct wined3d_state * state)3930 static void context_load_stream_output_buffers(struct wined3d_context *context,
3931         const struct wined3d_state *state)
3932 {
3933     unsigned int i;
3934 
3935     for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
3936     {
3937         struct wined3d_buffer *buffer;
3938         if (!(buffer = state->stream_output[i].buffer))
3939             continue;
3940 
3941         wined3d_buffer_load(buffer, context, state);
3942         wined3d_buffer_invalidate_location(buffer, ~WINED3D_LOCATION_BUFFER);
3943     }
3944 }
3945 
3946 /* Context activation is done by the caller. */
context_apply_draw_state(struct wined3d_context * context,const struct wined3d_device * device,const struct wined3d_state * state)3947 static BOOL context_apply_draw_state(struct wined3d_context *context,
3948         const struct wined3d_device *device, const struct wined3d_state *state)
3949 {
3950     const struct StateEntry *state_table = context->state_table;
3951     const struct wined3d_gl_info *gl_info = context->gl_info;
3952     const struct wined3d_fb_state *fb = state->fb;
3953     unsigned int i;
3954     WORD map;
3955 
3956     if (!have_framebuffer_attachment(gl_info->limits.buffers, fb->render_targets, fb->depth_stencil))
3957     {
3958         if (!gl_info->supported[ARB_FRAMEBUFFER_NO_ATTACHMENTS])
3959         {
3960             FIXME("OpenGL implementation does not support framebuffers with no attachments.\n");
3961             return FALSE;
3962         }
3963 
3964         context_set_render_offscreen(context, TRUE);
3965     }
3966 
3967     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && isStateDirty(context, STATE_FRAMEBUFFER))
3968     {
3969         context_validate_onscreen_formats(context, fb->depth_stencil);
3970     }
3971 
3972     /* Preload resources before FBO setup. Texture preload in particular may
3973      * result in changes to the current FBO, due to using e.g. FBO blits for
3974      * updating a resource location. */
3975     context_update_tex_unit_map(context, state);
3976     context_preload_textures(context, state);
3977     context_load_shader_resources(context, state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
3978     context_load_unordered_access_resources(context, state->shader[WINED3D_SHADER_TYPE_PIXEL],
3979             state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
3980     context_load_stream_output_buffers(context, state);
3981     /* TODO: Right now the dependency on the vertex shader is necessary
3982      * since wined3d_stream_info_from_declaration() depends on the reg_maps of
3983      * the current VS but maybe it's possible to relax the coupling in some
3984      * situations at least. */
3985     if (isStateDirty(context, STATE_VDECL) || isStateDirty(context, STATE_STREAMSRC)
3986             || isStateDirty(context, STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX)))
3987     {
3988         context_update_stream_info(context, state);
3989     }
3990     else
3991     {
3992         for (i = 0, map = context->stream_info.use_map; map; map >>= 1, ++i)
3993         {
3994             if (map & 1)
3995                 wined3d_buffer_load(state->streams[context->stream_info.elements[i].stream_idx].buffer,
3996                         context, state);
3997         }
3998         /* Loading the buffers above may have invalidated the stream info. */
3999         if (isStateDirty(context, STATE_STREAMSRC))
4000             context_update_stream_info(context, state);
4001     }
4002     if (state->index_buffer)
4003     {
4004         if (context->stream_info.all_vbo)
4005             wined3d_buffer_load(state->index_buffer, context, state);
4006         else
4007             wined3d_buffer_load_sysmem(state->index_buffer, context);
4008     }
4009 
4010     for (i = 0; i < context->numDirtyEntries; ++i)
4011     {
4012         DWORD rep = context->dirtyArray[i];
4013         DWORD idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
4014         BYTE shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
4015         context->isStateDirty[idx] &= ~(1u << shift);
4016         state_table[rep].apply(context, state, rep);
4017     }
4018 
4019     if (context->shader_update_mask & ~(1u << WINED3D_SHADER_TYPE_COMPUTE))
4020     {
4021         device->shader_backend->shader_select(device->shader_priv, context, state);
4022         context->shader_update_mask &= 1u << WINED3D_SHADER_TYPE_COMPUTE;
4023     }
4024 
4025     if (context->constant_update_mask)
4026     {
4027         device->shader_backend->shader_load_constants(device->shader_priv, context, state);
4028         context->constant_update_mask = 0;
4029     }
4030 
4031     if (context->update_shader_resource_bindings)
4032     {
4033         for (i = 0; i < WINED3D_SHADER_TYPE_GRAPHICS_COUNT; ++i)
4034             context_bind_shader_resources(context, state, i);
4035         context->update_shader_resource_bindings = 0;
4036         if (gl_info->limits.combined_samplers == gl_info->limits.graphics_samplers)
4037             context->update_compute_shader_resource_bindings = 1;
4038     }
4039 
4040     if (context->update_unordered_access_view_bindings)
4041     {
4042         context_bind_unordered_access_views(context,
4043                 state->shader[WINED3D_SHADER_TYPE_PIXEL],
4044                 state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
4045         context->update_unordered_access_view_bindings = 0;
4046         context->update_compute_unordered_access_view_bindings = 1;
4047     }
4048 
4049     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4050     {
4051         context_check_fbo_status(context, GL_FRAMEBUFFER);
4052     }
4053 
4054     context->numDirtyEntries = 0; /* This makes the whole list clean */
4055     context->last_was_blit = FALSE;
4056 
4057     return TRUE;
4058 }
4059 
context_apply_compute_state(struct wined3d_context * context,const struct wined3d_device * device,const struct wined3d_state * state)4060 static void context_apply_compute_state(struct wined3d_context *context,
4061         const struct wined3d_device *device, const struct wined3d_state *state)
4062 {
4063     const struct StateEntry *state_table = context->state_table;
4064     const struct wined3d_gl_info *gl_info = context->gl_info;
4065     unsigned int state_id, i;
4066 
4067     context_load_shader_resources(context, state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
4068     context_load_unordered_access_resources(context, state->shader[WINED3D_SHADER_TYPE_COMPUTE],
4069             state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
4070 
4071     for (i = 0, state_id = STATE_COMPUTE_OFFSET; i < ARRAY_SIZE(context->dirty_compute_states); ++i)
4072     {
4073         unsigned int dirty_mask = context->dirty_compute_states[i];
4074         while (dirty_mask)
4075         {
4076             unsigned int current_state_id = state_id + wined3d_bit_scan(&dirty_mask);
4077             state_table[current_state_id].apply(context, state, current_state_id);
4078         }
4079         state_id += sizeof(*context->dirty_compute_states) * CHAR_BIT;
4080     }
4081     memset(context->dirty_compute_states, 0, sizeof(*context->dirty_compute_states));
4082 
4083     if (context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_COMPUTE))
4084     {
4085         device->shader_backend->shader_select_compute(device->shader_priv, context, state);
4086         context->shader_update_mask &= ~(1u << WINED3D_SHADER_TYPE_COMPUTE);
4087     }
4088 
4089     if (context->update_compute_shader_resource_bindings)
4090     {
4091         context_bind_shader_resources(context, state, WINED3D_SHADER_TYPE_COMPUTE);
4092         context->update_compute_shader_resource_bindings = 0;
4093         if (gl_info->limits.combined_samplers == gl_info->limits.graphics_samplers)
4094             context->update_shader_resource_bindings = 1;
4095     }
4096 
4097     if (context->update_compute_unordered_access_view_bindings)
4098     {
4099         context_bind_unordered_access_views(context,
4100                 state->shader[WINED3D_SHADER_TYPE_COMPUTE],
4101                 state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
4102         context->update_compute_unordered_access_view_bindings = 0;
4103         context->update_unordered_access_view_bindings = 1;
4104     }
4105 
4106     /* Updates to currently bound render targets aren't necessarily coherent
4107      * between the graphics and compute pipelines. Unbind any currently bound
4108      * FBO here to ensure preceding updates to its attachments by the graphics
4109      * pipeline are visible to the compute pipeline.
4110      *
4111      * Without this, the bloom effect in Nier:Automata is too bright on the
4112      * Mesa radeonsi driver, and presumably on other Mesa based drivers. */
4113     context_bind_fbo(context, GL_FRAMEBUFFER, 0);
4114     context_invalidate_state(context, STATE_FRAMEBUFFER);
4115 
4116     context->last_was_blit = FALSE;
4117 }
4118 
use_transform_feedback(const struct wined3d_state * state)4119 static BOOL use_transform_feedback(const struct wined3d_state *state)
4120 {
4121     const struct wined3d_shader *shader;
4122     if (!(shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]))
4123         return FALSE;
4124     return shader->u.gs.so_desc.element_count;
4125 }
4126 
context_end_transform_feedback(struct wined3d_context * context)4127 void context_end_transform_feedback(struct wined3d_context *context)
4128 {
4129     const struct wined3d_gl_info *gl_info = context->gl_info;
4130     if (context->transform_feedback_active)
4131     {
4132         GL_EXTCALL(glEndTransformFeedback());
4133         checkGLcall("glEndTransformFeedback");
4134         context->transform_feedback_active = 0;
4135         context->transform_feedback_paused = 0;
4136     }
4137 }
4138 
context_pause_transform_feedback(struct wined3d_context * context,BOOL force)4139 static void context_pause_transform_feedback(struct wined3d_context *context, BOOL force)
4140 {
4141     const struct wined3d_gl_info *gl_info = context->gl_info;
4142 
4143     if (!context->transform_feedback_active || context->transform_feedback_paused)
4144         return;
4145 
4146     if (gl_info->supported[ARB_TRANSFORM_FEEDBACK2])
4147     {
4148         GL_EXTCALL(glPauseTransformFeedback());
4149         checkGLcall("glPauseTransformFeedback");
4150         context->transform_feedback_paused = 1;
4151         return;
4152     }
4153 
4154     WARN("Cannot pause transform feedback operations.\n");
4155 
4156     if (force)
4157         context_end_transform_feedback(context);
4158 }
4159 
context_setup_target(struct wined3d_context * context,struct wined3d_texture * texture,unsigned int sub_resource_idx)4160 static void context_setup_target(struct wined3d_context *context,
4161         struct wined3d_texture *texture, unsigned int sub_resource_idx)
4162 {
4163     BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
4164 
4165     render_offscreen = wined3d_resource_is_offscreen(&texture->resource);
4166     if (context->current_rt.texture == texture
4167             && context->current_rt.sub_resource_idx == sub_resource_idx
4168             && render_offscreen == old_render_offscreen)
4169         return;
4170 
4171     /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
4172      * the alpha blend state changes with different render target formats. */
4173     if (!context->current_rt.texture)
4174     {
4175         context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
4176     }
4177     else
4178     {
4179         const struct wined3d_format *old = context->current_rt.texture->resource.format;
4180         const struct wined3d_format *new = texture->resource.format;
4181 
4182         if (old->id != new->id)
4183         {
4184             /* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
4185             if ((old->alpha_size && !new->alpha_size) || (!old->alpha_size && new->alpha_size)
4186                     || !(texture->resource.format_flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
4187                 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
4188 
4189             /* Update sRGB writing when switching between formats that do/do not support sRGB writing */
4190             if ((context->current_rt.texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE)
4191                     != (texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE))
4192                 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
4193         }
4194 
4195         /* When switching away from an offscreen render target, and we're not
4196          * using FBOs, we have to read the drawable into the texture. This is
4197          * done via PreLoad (and WINED3D_LOCATION_DRAWABLE set on the surface).
4198          * There are some things that need care though. PreLoad needs a GL context,
4199          * and FindContext is called before the context is activated. It also
4200          * has to be called with the old rendertarget active, otherwise a
4201          * wrong drawable is read. */
4202         if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
4203                 && old_render_offscreen && (context->current_rt.texture != texture
4204                 || context->current_rt.sub_resource_idx != sub_resource_idx))
4205         {
4206             unsigned int prev_sub_resource_idx = context->current_rt.sub_resource_idx;
4207             struct wined3d_texture *prev_texture = context->current_rt.texture;
4208 
4209             /* Read the back buffer of the old drawable into the destination texture. */
4210             if (prev_texture->texture_srgb.name)
4211                 wined3d_texture_load(prev_texture, context, TRUE);
4212             wined3d_texture_load(prev_texture, context, FALSE);
4213             wined3d_texture_invalidate_location(prev_texture, prev_sub_resource_idx, WINED3D_LOCATION_DRAWABLE);
4214         }
4215     }
4216 
4217     context->current_rt.texture = texture;
4218     context->current_rt.sub_resource_idx = sub_resource_idx;
4219     context_set_render_offscreen(context, render_offscreen);
4220 }
4221 
context_activate(struct wined3d_context * context,struct wined3d_texture * texture,unsigned int sub_resource_idx)4222 static void context_activate(struct wined3d_context *context,
4223         struct wined3d_texture *texture, unsigned int sub_resource_idx)
4224 {
4225     context_enter(context);
4226     context_update_window(context);
4227     context_setup_target(context, texture, sub_resource_idx);
4228     if (!context->valid)
4229         return;
4230 
4231     if (context != context_get_current())
4232     {
4233         if (!context_set_current(context))
4234             ERR("Failed to activate the new context.\n");
4235     }
4236     else if (context->needs_set)
4237     {
4238         context_set_gl_context(context);
4239     }
4240 }
4241 
context_acquire(const struct wined3d_device * device,struct wined3d_texture * texture,unsigned int sub_resource_idx)4242 struct wined3d_context *context_acquire(const struct wined3d_device *device,
4243         struct wined3d_texture *texture, unsigned int sub_resource_idx)
4244 {
4245     struct wined3d_context *current_context = context_get_current();
4246     struct wined3d_context *context;
4247     BOOL swapchain_texture;
4248 
4249     TRACE("device %p, texture %p, sub_resource_idx %u.\n", device, texture, sub_resource_idx);
4250 
4251     wined3d_from_cs(device->cs);
4252 
4253     if (current_context && current_context->destroyed)
4254         current_context = NULL;
4255 
4256     swapchain_texture = texture && texture->swapchain;
4257     if (!texture)
4258     {
4259         if (current_context
4260                 && current_context->current_rt.texture
4261                 && current_context->device == device)
4262         {
4263             texture = current_context->current_rt.texture;
4264             sub_resource_idx = current_context->current_rt.sub_resource_idx;
4265         }
4266         else
4267         {
4268             struct wined3d_swapchain *swapchain = device->swapchains[0];
4269 
4270             if (swapchain->back_buffers)
4271                 texture = swapchain->back_buffers[0];
4272             else
4273                 texture = swapchain->front_buffer;
4274             sub_resource_idx = 0;
4275         }
4276     }
4277 
4278     if (current_context && current_context->current_rt.texture == texture)
4279     {
4280         context = current_context;
4281     }
4282     else if (swapchain_texture)
4283     {
4284         TRACE("Rendering onscreen.\n");
4285 
4286         context = swapchain_get_context(texture->swapchain);
4287     }
4288     else
4289     {
4290         TRACE("Rendering offscreen.\n");
4291 
4292         /* Stay with the current context if possible. Otherwise use the
4293          * context for the primary swapchain. */
4294         if (current_context && current_context->device == device)
4295             context = current_context;
4296         else
4297             context = swapchain_get_context(device->swapchains[0]);
4298     }
4299 
4300     context_activate(context, texture, sub_resource_idx);
4301 
4302     return context;
4303 }
4304 
context_reacquire(const struct wined3d_device * device,struct wined3d_context * context)4305 struct wined3d_context *context_reacquire(const struct wined3d_device *device,
4306         struct wined3d_context *context)
4307 {
4308     struct wined3d_context *acquired_context;
4309 
4310     wined3d_from_cs(device->cs);
4311 
4312     if (!context || context->tid != GetCurrentThreadId())
4313         return NULL;
4314 
4315     if (context->current_rt.texture)
4316     {
4317         context_activate(context, context->current_rt.texture, context->current_rt.sub_resource_idx);
4318         return context;
4319     }
4320 
4321     acquired_context = context_acquire(device, NULL, 0);
4322     if (acquired_context != context)
4323         ERR("Acquired context %p instead of %p.\n", acquired_context, context);
4324     return acquired_context;
4325 }
4326 
dispatch_compute(struct wined3d_device * device,const struct wined3d_state * state,const struct wined3d_dispatch_parameters * parameters)4327 void dispatch_compute(struct wined3d_device *device, const struct wined3d_state *state,
4328         const struct wined3d_dispatch_parameters *parameters)
4329 {
4330     const struct wined3d_gl_info *gl_info;
4331     struct wined3d_context *context;
4332 
4333     context = context_acquire(device, NULL, 0);
4334     if (!context->valid)
4335     {
4336         context_release(context);
4337         WARN("Invalid context, skipping dispatch.\n");
4338         return;
4339     }
4340     gl_info = context->gl_info;
4341 
4342     if (!gl_info->supported[ARB_COMPUTE_SHADER])
4343     {
4344         context_release(context);
4345         FIXME("OpenGL implementation does not support compute shaders.\n");
4346         return;
4347     }
4348 
4349     if (parameters->indirect)
4350         wined3d_buffer_load(parameters->u.indirect.buffer, context, state);
4351 
4352     context_apply_compute_state(context, device, state);
4353 
4354     if (!state->shader[WINED3D_SHADER_TYPE_COMPUTE])
4355     {
4356         context_release(context);
4357         WARN("No compute shader bound, skipping dispatch.\n");
4358         return;
4359     }
4360 
4361     if (parameters->indirect)
4362     {
4363         const struct wined3d_indirect_dispatch_parameters *indirect = &parameters->u.indirect;
4364         struct wined3d_buffer *buffer = indirect->buffer;
4365 
4366         GL_EXTCALL(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer->buffer_object));
4367         GL_EXTCALL(glDispatchComputeIndirect((GLintptr)indirect->offset));
4368         GL_EXTCALL(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0));
4369     }
4370     else
4371     {
4372         const struct wined3d_direct_dispatch_parameters *direct = &parameters->u.direct;
4373         GL_EXTCALL(glDispatchCompute(direct->group_count_x, direct->group_count_y, direct->group_count_z));
4374     }
4375     checkGLcall("dispatch compute");
4376 
4377     GL_EXTCALL(glMemoryBarrier(GL_ALL_BARRIER_BITS));
4378     checkGLcall("glMemoryBarrier");
4379 
4380     if (wined3d_settings.strict_draw_ordering)
4381         gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
4382 
4383     context_release(context);
4384 }
4385 
4386 /* Context activation is done by the caller. */
draw_primitive_arrays(struct wined3d_context * context,const struct wined3d_state * state,const void * idx_data,unsigned int idx_size,int base_vertex_idx,unsigned int start_idx,unsigned int count,unsigned int start_instance,unsigned int instance_count)4387 static void draw_primitive_arrays(struct wined3d_context *context, const struct wined3d_state *state,
4388         const void *idx_data, unsigned int idx_size, int base_vertex_idx, unsigned int start_idx,
4389         unsigned int count, unsigned int start_instance, unsigned int instance_count)
4390 {
4391     const struct wined3d_ffp_attrib_ops *ops = &context->d3d_info->ffp_attrib_ops;
4392     GLenum idx_type = idx_size == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
4393     const struct wined3d_stream_info *si = &context->stream_info;
4394     unsigned int instanced_elements[ARRAY_SIZE(si->elements)];
4395     const struct wined3d_gl_info *gl_info = context->gl_info;
4396     unsigned int instanced_element_count = 0;
4397     GLenum mode = state->gl_primitive_type;
4398     const void *indices;
4399     unsigned int i, j;
4400 
4401     indices = (const char *)idx_data + idx_size * start_idx;
4402 
4403     if (!instance_count)
4404     {
4405         if (!idx_size)
4406         {
4407             gl_info->gl_ops.gl.p_glDrawArrays(mode, start_idx, count);
4408             checkGLcall("glDrawArrays");
4409             return;
4410         }
4411 
4412         if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
4413         {
4414             GL_EXTCALL(glDrawElementsBaseVertex(mode, count, idx_type, indices, base_vertex_idx));
4415             checkGLcall("glDrawElementsBaseVertex");
4416             return;
4417         }
4418 
4419         gl_info->gl_ops.gl.p_glDrawElements(mode, count, idx_type, indices);
4420         checkGLcall("glDrawElements");
4421         return;
4422     }
4423 
4424     if (start_instance && !(gl_info->supported[ARB_BASE_INSTANCE] && gl_info->supported[ARB_INSTANCED_ARRAYS]))
4425         FIXME("Start instance (%u) not supported.\n", start_instance);
4426 
4427     if (gl_info->supported[ARB_INSTANCED_ARRAYS])
4428     {
4429         if (!idx_size)
4430         {
4431             if (gl_info->supported[ARB_BASE_INSTANCE])
4432             {
4433                 GL_EXTCALL(glDrawArraysInstancedBaseInstance(mode, start_idx, count, instance_count, start_instance));
4434                 checkGLcall("glDrawArraysInstancedBaseInstance");
4435                 return;
4436             }
4437 
4438             GL_EXTCALL(glDrawArraysInstanced(mode, start_idx, count, instance_count));
4439             checkGLcall("glDrawArraysInstanced");
4440             return;
4441         }
4442 
4443         if (gl_info->supported[ARB_BASE_INSTANCE])
4444         {
4445             GL_EXTCALL(glDrawElementsInstancedBaseVertexBaseInstance(mode, count, idx_type,
4446                     indices, instance_count, base_vertex_idx, start_instance));
4447             checkGLcall("glDrawElementsInstancedBaseVertexBaseInstance");
4448             return;
4449         }
4450         if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
4451         {
4452             GL_EXTCALL(glDrawElementsInstancedBaseVertex(mode, count, idx_type,
4453                     indices, instance_count, base_vertex_idx));
4454             checkGLcall("glDrawElementsInstancedBaseVertex");
4455             return;
4456         }
4457 
4458         GL_EXTCALL(glDrawElementsInstanced(mode, count, idx_type, indices, instance_count));
4459         checkGLcall("glDrawElementsInstanced");
4460         return;
4461     }
4462 
4463     /* Instancing emulation by mixing immediate mode and arrays. */
4464 
4465     /* This is a nasty thing. MSDN says no hardware supports this and
4466      * applications have to use software vertex processing. We don't support
4467      * this for now.
4468      *
4469      * Shouldn't be too hard to support with OpenGL, in theory just call
4470      * glDrawArrays() instead of drawElements(). But the stream fequency value
4471      * has a different meaning in that situation. */
4472     if (!idx_size)
4473     {
4474         FIXME("Non-indexed instanced drawing is not supported.\n");
4475         return;
4476     }
4477 
4478     for (i = 0; i < ARRAY_SIZE(si->elements); ++i)
4479     {
4480         if (!(si->use_map & (1u << i)))
4481             continue;
4482 
4483         if (state->streams[si->elements[i].stream_idx].flags & WINED3DSTREAMSOURCE_INSTANCEDATA)
4484             instanced_elements[instanced_element_count++] = i;
4485     }
4486 
4487     for (i = 0; i < instance_count; ++i)
4488     {
4489         /* Specify the instanced attributes using immediate mode calls. */
4490         for (j = 0; j < instanced_element_count; ++j)
4491         {
4492             const struct wined3d_stream_info_element *element;
4493             unsigned int element_idx;
4494             const BYTE *ptr;
4495 
4496             element_idx = instanced_elements[j];
4497             element = &si->elements[element_idx];
4498             ptr = element->data.addr + element->stride * i;
4499             if (element->data.buffer_object)
4500                 ptr += (ULONG_PTR)wined3d_buffer_load_sysmem(state->streams[element->stream_idx].buffer, context);
4501             ops->generic[element->format->emit_idx](element_idx, ptr);
4502         }
4503 
4504         if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
4505         {
4506             GL_EXTCALL(glDrawElementsBaseVertex(mode, count, idx_type, indices, base_vertex_idx));
4507             checkGLcall("glDrawElementsBaseVertex");
4508         }
4509         else
4510         {
4511             gl_info->gl_ops.gl.p_glDrawElements(mode, count, idx_type, indices);
4512             checkGLcall("glDrawElements");
4513         }
4514     }
4515 }
4516 
software_vertex_blending(struct wined3d_context * context,const struct wined3d_state * state,const struct wined3d_stream_info * si,unsigned int element_idx,unsigned int stride_idx,float * result)4517 static const BYTE *software_vertex_blending(struct wined3d_context *context,
4518         const struct wined3d_state *state, const struct wined3d_stream_info *si,
4519         unsigned int element_idx, unsigned int stride_idx, float *result)
4520 {
4521 #define SI_FORMAT(idx) (si->elements[(idx)].format->emit_idx)
4522 #define SI_PTR(idx1, idx2) (si->elements[(idx1)].data.addr + si->elements[(idx1)].stride * (idx2))
4523 
4524     const float *data = (const float *)SI_PTR(element_idx, stride_idx);
4525     float vector[4] = {0.0f, 0.0f, 0.0f, 1.0f};
4526     float cur_weight, weight_sum = 0.0f;
4527     struct wined3d_matrix m;
4528     const BYTE *blend_index;
4529     const float *weights;
4530     int i, num_weights;
4531 
4532     if (element_idx != WINED3D_FFP_POSITION && element_idx != WINED3D_FFP_NORMAL)
4533         return (BYTE *)data;
4534 
4535     if (!use_indexed_vertex_blending(state, si) || !use_software_vertex_processing(context->device))
4536         return (BYTE *)data;
4537 
4538     if (!si->elements[WINED3D_FFP_BLENDINDICES].data.addr ||
4539         !si->elements[WINED3D_FFP_BLENDWEIGHT].data.addr)
4540     {
4541         FIXME("no blend indices / weights set\n");
4542         return (BYTE *)data;
4543     }
4544 
4545     if (SI_FORMAT(WINED3D_FFP_BLENDINDICES) != WINED3D_FFP_EMIT_UBYTE4)
4546     {
4547         FIXME("unsupported blend index format: %u\n", SI_FORMAT(WINED3D_FFP_BLENDINDICES));
4548         return (BYTE *)data;
4549     }
4550 
4551     /* FIXME: validate weight format */
4552     switch (state->render_states[WINED3D_RS_VERTEXBLEND])
4553     {
4554         case WINED3D_VBF_0WEIGHTS: num_weights = 0; break;
4555         case WINED3D_VBF_1WEIGHTS: num_weights = 1; break;
4556         case WINED3D_VBF_2WEIGHTS: num_weights = 2; break;
4557         case WINED3D_VBF_3WEIGHTS: num_weights = 3; break;
4558         default:
4559             FIXME("unsupported vertex blend render state: %u\n", state->render_states[WINED3D_RS_VERTEXBLEND]);
4560             return (BYTE *)data;
4561     }
4562 
4563     switch (SI_FORMAT(element_idx))
4564     {
4565         case WINED3D_FFP_EMIT_FLOAT4: vector[3] = data[3];
4566         case WINED3D_FFP_EMIT_FLOAT3: vector[2] = data[2];
4567         case WINED3D_FFP_EMIT_FLOAT2: vector[1] = data[1];
4568         default:
4569             FIXME("unsupported value format: %u\n", SI_FORMAT(element_idx));
4570             return (BYTE *)data;
4571     }
4572 
4573     blend_index = SI_PTR(WINED3D_FFP_BLENDINDICES, stride_idx);
4574     weights = (const float *)SI_PTR(WINED3D_FFP_BLENDWEIGHT, stride_idx);
4575     result[0] = result[1] = result[2] = result[3] = 0.0f;
4576 
4577     for (i = 0; i < num_weights + 1; i++)
4578     {
4579         cur_weight = (i < num_weights) ? weights[i] : 1.0f - weight_sum;
4580         get_modelview_matrix(context, state, blend_index[i], &m);
4581 
4582         if (element_idx == WINED3D_FFP_POSITION)
4583         {
4584             result[0] += cur_weight * (vector[0] * m._11 + vector[1] * m._21 + vector[2] * m._31 + vector[3] * m._41);
4585             result[1] += cur_weight * (vector[0] * m._12 + vector[1] * m._22 + vector[2] * m._32 + vector[3] * m._42);
4586             result[2] += cur_weight * (vector[0] * m._13 + vector[1] * m._23 + vector[2] * m._33 + vector[3] * m._43);
4587             result[3] += cur_weight * (vector[0] * m._14 + vector[1] * m._24 + vector[2] * m._34 + vector[3] * m._44);
4588         }
4589         else
4590         {
4591             if (context->d3d_info->wined3d_creation_flags & WINED3D_LEGACY_FFP_LIGHTING)
4592                 invert_matrix_3d(&m, &m);
4593             else
4594                 invert_matrix(&m, &m);
4595 
4596             /* multiply with transposed M */
4597             result[0] += cur_weight * (vector[0] * m._11 + vector[1] * m._12 + vector[2] * m._13);
4598             result[1] += cur_weight * (vector[0] * m._21 + vector[1] * m._22 + vector[2] * m._23);
4599             result[2] += cur_weight * (vector[0] * m._31 + vector[1] * m._32 + vector[2] * m._33);
4600         }
4601 
4602         weight_sum += weights[i];
4603     }
4604 
4605 #undef SI_FORMAT
4606 #undef SI_PTR
4607 
4608     return (BYTE *)result;
4609 }
4610 
get_stride_idx(const void * idx_data,unsigned int idx_size,unsigned int base_vertex_idx,unsigned int start_idx,unsigned int vertex_idx)4611 static unsigned int get_stride_idx(const void *idx_data, unsigned int idx_size,
4612         unsigned int base_vertex_idx, unsigned int start_idx, unsigned int vertex_idx)
4613 {
4614     if (!idx_data)
4615         return start_idx + vertex_idx;
4616     if (idx_size == 2)
4617         return ((const WORD *)idx_data)[start_idx + vertex_idx] + base_vertex_idx;
4618     return ((const DWORD *)idx_data)[start_idx + vertex_idx] + base_vertex_idx;
4619 }
4620 
4621 /* Context activation is done by the caller. */
draw_primitive_immediate_mode(struct wined3d_context * context,const struct wined3d_state * state,const struct wined3d_stream_info * si,const void * idx_data,unsigned int idx_size,int base_vertex_idx,unsigned int start_idx,unsigned int vertex_count,unsigned int instance_count)4622 static void draw_primitive_immediate_mode(struct wined3d_context *context, const struct wined3d_state *state,
4623         const struct wined3d_stream_info *si, const void *idx_data, unsigned int idx_size,
4624         int base_vertex_idx, unsigned int start_idx, unsigned int vertex_count, unsigned int instance_count)
4625 {
4626     const BYTE *position = NULL, *normal = NULL, *diffuse = NULL, *specular = NULL;
4627     const struct wined3d_d3d_info *d3d_info = context->d3d_info;
4628     unsigned int coord_idx, stride_idx, texture_idx, vertex_idx;
4629     const struct wined3d_gl_info *gl_info = context->gl_info;
4630     const struct wined3d_stream_info_element *element;
4631     const BYTE *tex_coords[WINED3DDP_MAXTEXCOORD];
4632     unsigned int texture_unit, texture_stages;
4633     const struct wined3d_ffp_attrib_ops *ops;
4634     unsigned int untracked_material_count;
4635     unsigned int tex_mask = 0;
4636     BOOL specular_fog = FALSE;
4637     BOOL ps = use_ps(state);
4638     const void *ptr;
4639     float tmp[4];
4640 
4641     static unsigned int once;
4642 
4643     if (!once++)
4644         FIXME_(d3d_perf)("Drawing using immediate mode.\n");
4645     else
4646         WARN_(d3d_perf)("Drawing using immediate mode.\n");
4647 
4648     if (!idx_size && idx_data)
4649         ERR("Non-NULL idx_data with 0 idx_size, this should never happen.\n");
4650 
4651     if (instance_count)
4652         FIXME("Instancing not implemented.\n");
4653 
4654     /* Immediate mode drawing can't make use of indices in a VBO - get the
4655      * data from the index buffer. */
4656     if (idx_size)
4657         idx_data = wined3d_buffer_load_sysmem(state->index_buffer, context) + state->index_offset;
4658 
4659     ops = &d3d_info->ffp_attrib_ops;
4660 
4661     gl_info->gl_ops.gl.p_glBegin(state->gl_primitive_type);
4662 
4663     if (use_vs(state) || d3d_info->ffp_generic_attributes)
4664     {
4665         for (vertex_idx = 0; vertex_idx < vertex_count; ++vertex_idx)
4666         {
4667             unsigned int use_map = si->use_map;
4668             unsigned int element_idx;
4669 
4670             stride_idx = get_stride_idx(idx_data, idx_size, base_vertex_idx, start_idx, vertex_idx);
4671             for (element_idx = MAX_ATTRIBS - 1; use_map; use_map &= ~(1u << element_idx), --element_idx)
4672             {
4673                 if (!(use_map & 1u << element_idx))
4674                     continue;
4675 
4676                 ptr = software_vertex_blending(context, state, si, element_idx, stride_idx, tmp);
4677                 ops->generic[si->elements[element_idx].format->emit_idx](element_idx, ptr);
4678             }
4679         }
4680 
4681         gl_info->gl_ops.gl.p_glEnd();
4682         return;
4683     }
4684 
4685     if (si->use_map & (1u << WINED3D_FFP_POSITION))
4686         position = si->elements[WINED3D_FFP_POSITION].data.addr;
4687 
4688     if (si->use_map & (1u << WINED3D_FFP_NORMAL))
4689         normal = si->elements[WINED3D_FFP_NORMAL].data.addr;
4690     else
4691         gl_info->gl_ops.gl.p_glNormal3f(0.0f, 0.0f, 0.0f);
4692 
4693     untracked_material_count = context->num_untracked_materials;
4694     if (si->use_map & (1u << WINED3D_FFP_DIFFUSE))
4695     {
4696         element = &si->elements[WINED3D_FFP_DIFFUSE];
4697         diffuse = element->data.addr;
4698 
4699         if (untracked_material_count && element->format->id != WINED3DFMT_B8G8R8A8_UNORM)
4700             FIXME("Implement diffuse color tracking from %s.\n", debug_d3dformat(element->format->id));
4701     }
4702     else
4703     {
4704         gl_info->gl_ops.gl.p_glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
4705     }
4706 
4707     if (si->use_map & (1u << WINED3D_FFP_SPECULAR))
4708     {
4709         element = &si->elements[WINED3D_FFP_SPECULAR];
4710         specular = element->data.addr;
4711 
4712         /* Special case where the fog density is stored in the specular alpha channel. */
4713         if (state->render_states[WINED3D_RS_FOGENABLE]
4714                 && (state->render_states[WINED3D_RS_FOGVERTEXMODE] == WINED3D_FOG_NONE
4715                     || si->elements[WINED3D_FFP_POSITION].format->id == WINED3DFMT_R32G32B32A32_FLOAT)
4716                 && state->render_states[WINED3D_RS_FOGTABLEMODE] == WINED3D_FOG_NONE)
4717         {
4718             if (gl_info->supported[EXT_FOG_COORD])
4719             {
4720                 if (element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
4721                     specular_fog = TRUE;
4722                 else
4723                     FIXME("Implement fog coordinates from %s.\n", debug_d3dformat(element->format->id));
4724             }
4725             else
4726             {
4727                 static unsigned int once;
4728 
4729                 if (!once++)
4730                     FIXME("Implement fog for transformed vertices in software.\n");
4731             }
4732         }
4733     }
4734     else if (gl_info->supported[EXT_SECONDARY_COLOR])
4735     {
4736         GL_EXTCALL(glSecondaryColor3fEXT)(0.0f, 0.0f, 0.0f);
4737     }
4738 
4739     texture_stages = d3d_info->limits.ffp_blend_stages;
4740     for (texture_idx = 0; texture_idx < texture_stages; ++texture_idx)
4741     {
4742         if (!gl_info->supported[ARB_MULTITEXTURE] && texture_idx > 0)
4743         {
4744             FIXME("Program using multiple concurrent textures which this OpenGL implementation doesn't support.\n");
4745             continue;
4746         }
4747 
4748         if (!ps && !state->textures[texture_idx])
4749             continue;
4750 
4751         texture_unit = context->tex_unit_map[texture_idx];
4752         if (texture_unit == WINED3D_UNMAPPED_STAGE)
4753             continue;
4754 
4755         coord_idx = state->texture_states[texture_idx][WINED3D_TSS_TEXCOORD_INDEX];
4756         if (coord_idx > 7)
4757         {
4758             TRACE("Skipping generated coordinates (%#x) for texture %u.\n", coord_idx, texture_idx);
4759             continue;
4760         }
4761 
4762         if (si->use_map & (1u << (WINED3D_FFP_TEXCOORD0 + coord_idx)))
4763         {
4764             tex_coords[coord_idx] = si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].data.addr;
4765             tex_mask |= (1u << texture_idx);
4766         }
4767         else
4768         {
4769             TRACE("Setting default coordinates for texture %u.\n", texture_idx);
4770             if (gl_info->supported[ARB_MULTITEXTURE])
4771                 GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_unit, 0.0f, 0.0f, 0.0f, 1.0f));
4772             else
4773                 gl_info->gl_ops.gl.p_glTexCoord4f(0.0f, 0.0f, 0.0f, 1.0f);
4774         }
4775     }
4776 
4777     /* Blending data and point sizes are not supported by this function. They
4778      * are not supported by the fixed function pipeline at all. A FIXME for
4779      * them is printed after decoding the vertex declaration. */
4780     for (vertex_idx = 0; vertex_idx < vertex_count; ++vertex_idx)
4781     {
4782         unsigned int tmp_tex_mask;
4783 
4784         stride_idx = get_stride_idx(idx_data, idx_size, base_vertex_idx, start_idx, vertex_idx);
4785 
4786         if (normal)
4787         {
4788             ptr = software_vertex_blending(context, state, si, WINED3D_FFP_NORMAL, stride_idx, tmp);
4789             ops->normal[si->elements[WINED3D_FFP_NORMAL].format->emit_idx](ptr);
4790         }
4791 
4792         if (diffuse)
4793         {
4794             ptr = diffuse + stride_idx * si->elements[WINED3D_FFP_DIFFUSE].stride;
4795             ops->diffuse[si->elements[WINED3D_FFP_DIFFUSE].format->emit_idx](ptr);
4796 
4797             if (untracked_material_count)
4798             {
4799                 struct wined3d_color color;
4800                 unsigned int i;
4801 
4802                 wined3d_color_from_d3dcolor(&color, *(const DWORD *)ptr);
4803                 for (i = 0; i < untracked_material_count; ++i)
4804                 {
4805                     gl_info->gl_ops.gl.p_glMaterialfv(GL_FRONT_AND_BACK, context->untracked_materials[i], &color.r);
4806                 }
4807             }
4808         }
4809 
4810         if (specular)
4811         {
4812             ptr = specular + stride_idx * si->elements[WINED3D_FFP_SPECULAR].stride;
4813             ops->specular[si->elements[WINED3D_FFP_SPECULAR].format->emit_idx](ptr);
4814 
4815             if (specular_fog)
4816                 GL_EXTCALL(glFogCoordfEXT((float)(*(const DWORD *)ptr >> 24)));
4817         }
4818 
4819         tmp_tex_mask = tex_mask;
4820         for (texture_idx = 0; tmp_tex_mask; tmp_tex_mask >>= 1, ++texture_idx)
4821         {
4822             if (!(tmp_tex_mask & 1))
4823                 continue;
4824 
4825             coord_idx = state->texture_states[texture_idx][WINED3D_TSS_TEXCOORD_INDEX];
4826             ptr = tex_coords[coord_idx] + (stride_idx * si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].stride);
4827             ops->texcoord[si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].format->emit_idx](
4828                     GL_TEXTURE0_ARB + context->tex_unit_map[texture_idx], ptr);
4829         }
4830 
4831         if (position)
4832         {
4833             ptr = software_vertex_blending(context, state, si, WINED3D_FFP_POSITION, stride_idx, tmp);
4834             ops->position[si->elements[WINED3D_FFP_POSITION].format->emit_idx](ptr);
4835         }
4836     }
4837 
4838     gl_info->gl_ops.gl.p_glEnd();
4839     checkGLcall("draw immediate mode");
4840 }
4841 
draw_indirect(struct wined3d_context * context,const struct wined3d_state * state,const struct wined3d_indirect_draw_parameters * parameters,unsigned int idx_size)4842 static void draw_indirect(struct wined3d_context *context, const struct wined3d_state *state,
4843         const struct wined3d_indirect_draw_parameters *parameters, unsigned int idx_size)
4844 {
4845     const struct wined3d_gl_info *gl_info = context->gl_info;
4846     struct wined3d_buffer *buffer = parameters->buffer;
4847     const void *offset;
4848 
4849     if (!gl_info->supported[ARB_DRAW_INDIRECT])
4850     {
4851         FIXME("OpenGL implementation does not support indirect draws.\n");
4852         return;
4853     }
4854 
4855     GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->buffer_object));
4856 
4857     offset = (void *)(GLintptr)parameters->offset;
4858     if (idx_size)
4859     {
4860         GLenum idx_type = idx_size == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
4861         if (state->index_offset)
4862             FIXME("Ignoring index offset %u.\n", state->index_offset);
4863         GL_EXTCALL(glDrawElementsIndirect(state->gl_primitive_type, idx_type, offset));
4864     }
4865     else
4866     {
4867         GL_EXTCALL(glDrawArraysIndirect(state->gl_primitive_type, offset));
4868     }
4869 
4870     GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));
4871 
4872     checkGLcall("draw indirect");
4873 }
4874 
remove_vbos(struct wined3d_context * context,const struct wined3d_state * state,struct wined3d_stream_info * s)4875 static void remove_vbos(struct wined3d_context *context,
4876         const struct wined3d_state *state, struct wined3d_stream_info *s)
4877 {
4878     unsigned int i;
4879 
4880     for (i = 0; i < ARRAY_SIZE(s->elements); ++i)
4881     {
4882         struct wined3d_stream_info_element *e;
4883 
4884         if (!(s->use_map & (1u << i)))
4885             continue;
4886 
4887         e = &s->elements[i];
4888         if (e->data.buffer_object)
4889         {
4890             struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer;
4891             e->data.buffer_object = 0;
4892             e->data.addr += (ULONG_PTR)wined3d_buffer_load_sysmem(vb, context);
4893         }
4894     }
4895 }
4896 
gl_tfb_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)4897 static GLenum gl_tfb_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
4898 {
4899     GLenum gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4900     switch (gl_primitive_type)
4901     {
4902         case GL_POINTS:
4903             return GL_POINTS;
4904 
4905         case GL_LINE_STRIP:
4906         case GL_LINE_STRIP_ADJACENCY:
4907         case GL_LINES_ADJACENCY:
4908         case GL_LINES:
4909             return GL_LINES;
4910 
4911         case GL_TRIANGLE_FAN:
4912         case GL_TRIANGLE_STRIP:
4913         case GL_TRIANGLE_STRIP_ADJACENCY:
4914         case GL_TRIANGLES_ADJACENCY:
4915         case GL_TRIANGLES:
4916             return GL_TRIANGLES;
4917 
4918         default:
4919             return gl_primitive_type;
4920     }
4921 }
4922 
4923 /* Routine common to the draw primitive and draw indexed primitive routines */
draw_primitive(struct wined3d_device * device,const struct wined3d_state * state,const struct wined3d_draw_parameters * parameters)4924 void draw_primitive(struct wined3d_device *device, const struct wined3d_state *state,
4925         const struct wined3d_draw_parameters *parameters)
4926 {
4927     BOOL emulation = FALSE, rasterizer_discard = FALSE;
4928     const struct wined3d_fb_state *fb = state->fb;
4929     const struct wined3d_stream_info *stream_info;
4930     struct wined3d_rendertarget_view *dsv, *rtv;
4931     struct wined3d_stream_info si_emulated;
4932     struct wined3d_fence *ib_fence = NULL;
4933     const struct wined3d_gl_info *gl_info;
4934     struct wined3d_context *context;
4935     unsigned int i, idx_size = 0;
4936     const void *idx_data = NULL;
4937 
4938     if (!parameters->indirect && !parameters->u.direct.index_count)
4939         return;
4940 
4941     if (!(rtv = fb->render_targets[0]))
4942         rtv = fb->depth_stencil;
4943     if (rtv)
4944         context = context_acquire(device, wined3d_texture_from_resource(rtv->resource), rtv->sub_resource_idx);
4945     else
4946         context = context_acquire(device, NULL, 0);
4947     if (!context->valid)
4948     {
4949         context_release(context);
4950         WARN("Invalid context, skipping draw.\n");
4951         return;
4952     }
4953     gl_info = context->gl_info;
4954 
4955     if (!use_transform_feedback(state))
4956         context_pause_transform_feedback(context, TRUE);
4957 
4958     for (i = 0; i < gl_info->limits.buffers; ++i)
4959     {
4960         if (!(rtv = fb->render_targets[i]) || rtv->format->id == WINED3DFMT_NULL)
4961             continue;
4962 
4963         if (state->render_states[WINED3D_RS_COLORWRITE(i)])
4964         {
4965             wined3d_rendertarget_view_load_location(rtv, context, rtv->resource->draw_binding);
4966             wined3d_rendertarget_view_invalidate_location(rtv, ~rtv->resource->draw_binding);
4967         }
4968         else
4969         {
4970             wined3d_rendertarget_view_prepare_location(rtv, context, rtv->resource->draw_binding);
4971         }
4972     }
4973 
4974     if ((dsv = fb->depth_stencil))
4975     {
4976         /* Note that this depends on the context_acquire() call above to set
4977          * context->render_offscreen properly. We don't currently take the
4978          * Z-compare function into account, but we could skip loading the
4979          * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note
4980          * that we never copy the stencil data.*/
4981         DWORD location = context->render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
4982 
4983         if (state->render_states[WINED3D_RS_ZWRITEENABLE] || state->render_states[WINED3D_RS_ZENABLE])
4984             wined3d_rendertarget_view_load_location(dsv, context, location);
4985         else
4986             wined3d_rendertarget_view_prepare_location(dsv, context, location);
4987     }
4988 
4989     if (parameters->indirect)
4990         wined3d_buffer_load(parameters->u.indirect.buffer, context, state);
4991 
4992     if (!context_apply_draw_state(context, device, state))
4993     {
4994         context_release(context);
4995         WARN("Unable to apply draw state, skipping draw.\n");
4996         return;
4997     }
4998 
4999     if (dsv && state->render_states[WINED3D_RS_ZWRITEENABLE])
5000     {
5001         DWORD location = context->render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
5002 
5003         wined3d_rendertarget_view_validate_location(dsv, location);
5004         wined3d_rendertarget_view_invalidate_location(dsv, ~location);
5005     }
5006 
5007     stream_info = &context->stream_info;
5008 
5009     if (parameters->indexed)
5010     {
5011         struct wined3d_buffer *index_buffer = state->index_buffer;
5012         if (!index_buffer->buffer_object || !stream_info->all_vbo)
5013         {
5014             idx_data = index_buffer->resource.heap_memory;
5015         }
5016         else
5017         {
5018             ib_fence = index_buffer->fence;
5019             idx_data = NULL;
5020         }
5021         idx_data = (const BYTE *)idx_data + state->index_offset;
5022 
5023         if (state->index_format == WINED3DFMT_R16_UINT)
5024             idx_size = 2;
5025         else
5026             idx_size = 4;
5027     }
5028 
5029     if (!use_vs(state))
5030     {
5031         if (!stream_info->position_transformed && context->num_untracked_materials
5032                 && state->render_states[WINED3D_RS_LIGHTING])
5033         {
5034             static BOOL warned;
5035 
5036             if (!warned++)
5037                 FIXME("Using software emulation because not all material properties could be tracked.\n");
5038             else
5039                 WARN_(d3d_perf)("Using software emulation because not all material properties could be tracked.\n");
5040             emulation = TRUE;
5041         }
5042         else if (context->fog_coord && state->render_states[WINED3D_RS_FOGENABLE])
5043         {
5044             static BOOL warned;
5045 
5046             /* Either write a pipeline replacement shader or convert the
5047              * specular alpha from unsigned byte to a float in the vertex
5048              * buffer. */
5049             if (!warned++)
5050                 FIXME("Using software emulation because manual fog coordinates are provided.\n");
5051             else
5052                 WARN_(d3d_perf)("Using software emulation because manual fog coordinates are provided.\n");
5053             emulation = TRUE;
5054         }
5055          else if (use_indexed_vertex_blending(state, stream_info) && use_software_vertex_processing(context->device))
5056         {
5057             WARN_(d3d_perf)("Using software emulation because application requested SVP.\n");
5058             emulation = TRUE;
5059         }
5060 
5061 
5062         if (emulation)
5063         {
5064             si_emulated = context->stream_info;
5065             remove_vbos(context, state, &si_emulated);
5066             stream_info = &si_emulated;
5067         }
5068     }
5069 
5070     if (use_transform_feedback(state))
5071     {
5072         const struct wined3d_shader *shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY];
5073 
5074         if (is_rasterization_disabled(shader))
5075         {
5076             glEnable(GL_RASTERIZER_DISCARD);
5077             checkGLcall("enable rasterizer discard");
5078             rasterizer_discard = TRUE;
5079         }
5080 
5081         if (context->transform_feedback_paused)
5082         {
5083             GL_EXTCALL(glResumeTransformFeedback());
5084             checkGLcall("glResumeTransformFeedback");
5085             context->transform_feedback_paused = 0;
5086         }
5087         else if (!context->transform_feedback_active)
5088         {
5089             GLenum mode = gl_tfb_primitive_type_from_d3d(shader->u.gs.output_type);
5090             GL_EXTCALL(glBeginTransformFeedback(mode));
5091             checkGLcall("glBeginTransformFeedback");
5092             context->transform_feedback_active = 1;
5093         }
5094     }
5095 
5096     if (state->gl_primitive_type == GL_PATCHES)
5097     {
5098         GL_EXTCALL(glPatchParameteri(GL_PATCH_VERTICES, state->gl_patch_vertices));
5099         checkGLcall("glPatchParameteri");
5100     }
5101 
5102     if (parameters->indirect)
5103     {
5104         if (!context->use_immediate_mode_draw && !emulation)
5105             draw_indirect(context, state, &parameters->u.indirect, idx_size);
5106         else
5107             FIXME("Indirect draws with immediate mode/emulation are not supported.\n");
5108     }
5109     else
5110     {
5111         unsigned int instance_count = parameters->u.direct.instance_count;
5112         if (context->instance_count)
5113             instance_count = context->instance_count;
5114 
5115         if (context->use_immediate_mode_draw || emulation)
5116             draw_primitive_immediate_mode(context, state, stream_info, idx_data,
5117                     idx_size, parameters->u.direct.base_vertex_idx,
5118                     parameters->u.direct.start_idx, parameters->u.direct.index_count, instance_count);
5119         else
5120             draw_primitive_arrays(context, state, idx_data, idx_size, parameters->u.direct.base_vertex_idx,
5121                     parameters->u.direct.start_idx, parameters->u.direct.index_count,
5122                     parameters->u.direct.start_instance, instance_count);
5123     }
5124 
5125     if (context->uses_uavs)
5126     {
5127         GL_EXTCALL(glMemoryBarrier(GL_ALL_BARRIER_BITS));
5128         checkGLcall("glMemoryBarrier");
5129     }
5130 
5131     context_pause_transform_feedback(context, FALSE);
5132 
5133     if (rasterizer_discard)
5134     {
5135         glDisable(GL_RASTERIZER_DISCARD);
5136         checkGLcall("disable rasterizer discard");
5137     }
5138 
5139     if (ib_fence)
5140         wined3d_fence_issue(ib_fence, device);
5141     for (i = 0; i < context->buffer_fence_count; ++i)
5142         wined3d_fence_issue(context->buffer_fences[i], device);
5143 
5144     if (wined3d_settings.strict_draw_ordering)
5145         gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5146 
5147     context_release(context);
5148 }
5149