1c2c66affSColin Finck /*
2c2c66affSColin Finck * Context and render target management in wined3d
3c2c66affSColin Finck *
49987f029SAmine Khaldi * Copyright 2002-2004 Jason Edmeades
59987f029SAmine Khaldi * Copyright 2002-2004 Raphael Junqueira
69987f029SAmine Khaldi * Copyright 2004 Christian Costa
79987f029SAmine Khaldi * Copyright 2005 Oliver Stieber
89987f029SAmine Khaldi * Copyright 2006, 2008 Henri Verbeet
9c2c66affSColin Finck * Copyright 2007-2011, 2013 Stefan Dösinger for CodeWeavers
10c2c66affSColin Finck * Copyright 2009-2011 Henri Verbeet for CodeWeavers
11c2c66affSColin Finck *
12c2c66affSColin Finck * This library is free software; you can redistribute it and/or
13c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
14c2c66affSColin Finck * License as published by the Free Software Foundation; either
15c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
16c2c66affSColin Finck *
17c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
18c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
19c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20c2c66affSColin Finck * Lesser General Public License for more details.
21c2c66affSColin Finck *
22c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
23c2c66affSColin Finck * License along with this library; if not, write to the Free Software
24c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25c2c66affSColin Finck */
26c2c66affSColin Finck
279987f029SAmine Khaldi #include "config.h"
289987f029SAmine Khaldi #include "wine/port.h"
299987f029SAmine Khaldi
309987f029SAmine Khaldi #include <stdio.h>
319987f029SAmine Khaldi #ifdef HAVE_FLOAT_H
329987f029SAmine Khaldi # include <float.h>
339987f029SAmine Khaldi #endif
349987f029SAmine Khaldi
35c2c66affSColin Finck #include "wined3d_private.h"
36c2c66affSColin Finck
379987f029SAmine Khaldi #ifdef __REACTOS__
389987f029SAmine Khaldi #include <reactos/undocuser.h>
399987f029SAmine Khaldi #endif
409987f029SAmine Khaldi
41c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(d3d);
42c2c66affSColin Finck WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
43c2c66affSColin Finck WINE_DECLARE_DEBUG_CHANNEL(d3d_synchronous);
44c2c66affSColin Finck
45c2c66affSColin Finck #define WINED3D_MAX_FBO_ENTRIES 64
46c2c66affSColin Finck #define WINED3D_ALL_LAYERS (~0u)
47c2c66affSColin Finck
48c2c66affSColin Finck static DWORD wined3d_context_tls_idx;
49c2c66affSColin Finck
50c2c66affSColin Finck /* FBO helper functions */
51c2c66affSColin Finck
52c2c66affSColin Finck /* Context activation is done by the caller. */
context_bind_fbo(struct wined3d_context * context,GLenum target,GLuint fbo)53c2c66affSColin Finck static void context_bind_fbo(struct wined3d_context *context, GLenum target, GLuint fbo)
54c2c66affSColin Finck {
55c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
56c2c66affSColin Finck
57c2c66affSColin Finck switch (target)
58c2c66affSColin Finck {
59c2c66affSColin Finck case GL_READ_FRAMEBUFFER:
60c2c66affSColin Finck if (context->fbo_read_binding == fbo) return;
61c2c66affSColin Finck context->fbo_read_binding = fbo;
62c2c66affSColin Finck break;
63c2c66affSColin Finck
64c2c66affSColin Finck case GL_DRAW_FRAMEBUFFER:
65c2c66affSColin Finck if (context->fbo_draw_binding == fbo) return;
66c2c66affSColin Finck context->fbo_draw_binding = fbo;
67c2c66affSColin Finck break;
68c2c66affSColin Finck
69c2c66affSColin Finck case GL_FRAMEBUFFER:
70c2c66affSColin Finck if (context->fbo_read_binding == fbo
71c2c66affSColin Finck && context->fbo_draw_binding == fbo) return;
72c2c66affSColin Finck context->fbo_read_binding = fbo;
73c2c66affSColin Finck context->fbo_draw_binding = fbo;
74c2c66affSColin Finck break;
75c2c66affSColin Finck
76c2c66affSColin Finck default:
77c2c66affSColin Finck FIXME("Unhandled target %#x.\n", target);
78c2c66affSColin Finck break;
79c2c66affSColin Finck }
80c2c66affSColin Finck
81c2c66affSColin Finck gl_info->fbo_ops.glBindFramebuffer(target, fbo);
82c2c66affSColin Finck checkGLcall("glBindFramebuffer()");
83c2c66affSColin Finck }
84c2c66affSColin Finck
85c2c66affSColin Finck /* Context activation is done by the caller. */
context_clean_fbo_attachments(const struct wined3d_gl_info * gl_info,GLenum target)86c2c66affSColin Finck static void context_clean_fbo_attachments(const struct wined3d_gl_info *gl_info, GLenum target)
87c2c66affSColin Finck {
88c2c66affSColin Finck unsigned int i;
89c2c66affSColin Finck
90c2c66affSColin Finck for (i = 0; i < gl_info->limits.buffers; ++i)
91c2c66affSColin Finck {
92c2c66affSColin Finck gl_info->fbo_ops.glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0);
93c2c66affSColin Finck checkGLcall("glFramebufferTexture2D()");
94c2c66affSColin Finck }
95c2c66affSColin Finck gl_info->fbo_ops.glFramebufferTexture2D(target, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
96c2c66affSColin Finck checkGLcall("glFramebufferTexture2D()");
97c2c66affSColin Finck
98c2c66affSColin Finck gl_info->fbo_ops.glFramebufferTexture2D(target, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
99c2c66affSColin Finck checkGLcall("glFramebufferTexture2D()");
100c2c66affSColin Finck }
101c2c66affSColin Finck
102c2c66affSColin Finck /* Context activation is done by the caller. */
context_destroy_fbo(struct wined3d_context * context,GLuint fbo)103c2c66affSColin Finck static void context_destroy_fbo(struct wined3d_context *context, GLuint fbo)
104c2c66affSColin Finck {
105c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
106c2c66affSColin Finck
107c2c66affSColin Finck context_bind_fbo(context, GL_FRAMEBUFFER, fbo);
108c2c66affSColin Finck context_clean_fbo_attachments(gl_info, GL_FRAMEBUFFER);
109c2c66affSColin Finck context_bind_fbo(context, GL_FRAMEBUFFER, 0);
110c2c66affSColin Finck
111c2c66affSColin Finck gl_info->fbo_ops.glDeleteFramebuffers(1, &fbo);
112c2c66affSColin Finck checkGLcall("glDeleteFramebuffers()");
113c2c66affSColin Finck }
114c2c66affSColin Finck
context_attach_depth_stencil_rb(const struct wined3d_gl_info * gl_info,GLenum fbo_target,DWORD flags,GLuint rb)115c2c66affSColin Finck static void context_attach_depth_stencil_rb(const struct wined3d_gl_info *gl_info,
116c2c66affSColin Finck GLenum fbo_target, DWORD flags, GLuint rb)
117c2c66affSColin Finck {
118c2c66affSColin Finck if (flags & WINED3D_FBO_ENTRY_FLAG_DEPTH)
119c2c66affSColin Finck {
120c2c66affSColin Finck gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb);
121c2c66affSColin Finck checkGLcall("glFramebufferRenderbuffer()");
122c2c66affSColin Finck }
123c2c66affSColin Finck
124c2c66affSColin Finck if (flags & WINED3D_FBO_ENTRY_FLAG_STENCIL)
125c2c66affSColin Finck {
126c2c66affSColin Finck gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb);
127c2c66affSColin Finck checkGLcall("glFramebufferRenderbuffer()");
128c2c66affSColin Finck }
129c2c66affSColin Finck }
130c2c66affSColin Finck
context_attach_gl_texture_fbo(struct wined3d_context * context,GLenum fbo_target,GLenum attachment,const struct wined3d_fbo_resource * resource)131c2c66affSColin Finck static void context_attach_gl_texture_fbo(struct wined3d_context *context,
132c2c66affSColin Finck GLenum fbo_target, GLenum attachment, const struct wined3d_fbo_resource *resource)
133c2c66affSColin Finck {
134c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
135c2c66affSColin Finck
136c2c66affSColin Finck if (!resource)
137c2c66affSColin Finck {
138c2c66affSColin Finck gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, attachment, GL_TEXTURE_2D, 0, 0);
139c2c66affSColin Finck }
140c2c66affSColin Finck else if (resource->layer == WINED3D_ALL_LAYERS)
141c2c66affSColin Finck {
142c2c66affSColin Finck if (!gl_info->fbo_ops.glFramebufferTexture)
143c2c66affSColin Finck {
144c2c66affSColin Finck FIXME("OpenGL implementation doesn't support glFramebufferTexture().\n");
145c2c66affSColin Finck return;
146c2c66affSColin Finck }
147c2c66affSColin Finck
148c2c66affSColin Finck gl_info->fbo_ops.glFramebufferTexture(fbo_target, attachment,
149c2c66affSColin Finck resource->object, resource->level);
150c2c66affSColin Finck }
151*81cffd76SJoachim Henze else if (resource->target == GL_TEXTURE_1D_ARRAY || resource->target == GL_TEXTURE_2D_ARRAY ||
152*81cffd76SJoachim Henze resource->target == GL_TEXTURE_3D)
153c2c66affSColin Finck {
154c2c66affSColin Finck if (!gl_info->fbo_ops.glFramebufferTextureLayer)
155c2c66affSColin Finck {
156c2c66affSColin Finck FIXME("OpenGL implementation doesn't support glFramebufferTextureLayer().\n");
157c2c66affSColin Finck return;
158c2c66affSColin Finck }
159c2c66affSColin Finck
160c2c66affSColin Finck gl_info->fbo_ops.glFramebufferTextureLayer(fbo_target, attachment,
161c2c66affSColin Finck resource->object, resource->level, resource->layer);
162c2c66affSColin Finck }
1639987f029SAmine Khaldi else if (resource->target == GL_TEXTURE_1D)
1649987f029SAmine Khaldi {
1659987f029SAmine Khaldi gl_info->fbo_ops.glFramebufferTexture1D(fbo_target, attachment,
1669987f029SAmine Khaldi resource->target, resource->object, resource->level);
167*81cffd76SJoachim Henze checkGLcall("glFramebufferTexture1D()");
1689987f029SAmine Khaldi }
169c2c66affSColin Finck else
170c2c66affSColin Finck {
171c2c66affSColin Finck gl_info->fbo_ops.glFramebufferTexture2D(fbo_target, attachment,
172c2c66affSColin Finck resource->target, resource->object, resource->level);
173c2c66affSColin Finck }
174c2c66affSColin Finck checkGLcall("attach texture to fbo");
175c2c66affSColin Finck }
176c2c66affSColin Finck
177c2c66affSColin Finck /* 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)178c2c66affSColin Finck static void context_attach_depth_stencil_fbo(struct wined3d_context *context,
179c2c66affSColin Finck GLenum fbo_target, const struct wined3d_fbo_resource *resource, BOOL rb_namespace,
180c2c66affSColin Finck DWORD flags)
181c2c66affSColin Finck {
182c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
183c2c66affSColin Finck
184c2c66affSColin Finck if (resource->object)
185c2c66affSColin Finck {
186c2c66affSColin Finck TRACE("Attach depth stencil %u.\n", resource->object);
187c2c66affSColin Finck
188c2c66affSColin Finck if (rb_namespace)
189c2c66affSColin Finck {
190c2c66affSColin Finck context_attach_depth_stencil_rb(gl_info, fbo_target,
191c2c66affSColin Finck flags, resource->object);
192c2c66affSColin Finck }
193c2c66affSColin Finck else
194c2c66affSColin Finck {
195c2c66affSColin Finck if (flags & WINED3D_FBO_ENTRY_FLAG_DEPTH)
196c2c66affSColin Finck context_attach_gl_texture_fbo(context, fbo_target, GL_DEPTH_ATTACHMENT, resource);
197c2c66affSColin Finck
198c2c66affSColin Finck if (flags & WINED3D_FBO_ENTRY_FLAG_STENCIL)
199c2c66affSColin Finck context_attach_gl_texture_fbo(context, fbo_target, GL_STENCIL_ATTACHMENT, resource);
200c2c66affSColin Finck }
201c2c66affSColin Finck
202c2c66affSColin Finck if (!(flags & WINED3D_FBO_ENTRY_FLAG_DEPTH))
203c2c66affSColin Finck context_attach_gl_texture_fbo(context, fbo_target, GL_DEPTH_ATTACHMENT, NULL);
204c2c66affSColin Finck
205c2c66affSColin Finck if (!(flags & WINED3D_FBO_ENTRY_FLAG_STENCIL))
206c2c66affSColin Finck context_attach_gl_texture_fbo(context, fbo_target, GL_STENCIL_ATTACHMENT, NULL);
207c2c66affSColin Finck }
208c2c66affSColin Finck else
209c2c66affSColin Finck {
210c2c66affSColin Finck TRACE("Attach depth stencil 0.\n");
211c2c66affSColin Finck
212c2c66affSColin Finck context_attach_gl_texture_fbo(context, fbo_target, GL_DEPTH_ATTACHMENT, NULL);
213c2c66affSColin Finck context_attach_gl_texture_fbo(context, fbo_target, GL_STENCIL_ATTACHMENT, NULL);
214c2c66affSColin Finck }
215c2c66affSColin Finck }
216c2c66affSColin Finck
217c2c66affSColin Finck /* 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)218c2c66affSColin Finck static void context_attach_surface_fbo(struct wined3d_context *context,
219c2c66affSColin Finck GLenum fbo_target, DWORD idx, const struct wined3d_fbo_resource *resource, BOOL rb_namespace)
220c2c66affSColin Finck {
221c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
222c2c66affSColin Finck
223c2c66affSColin Finck TRACE("Attach GL object %u to %u.\n", resource->object, idx);
224c2c66affSColin Finck
225c2c66affSColin Finck if (resource->object)
226c2c66affSColin Finck {
227c2c66affSColin Finck if (rb_namespace)
228c2c66affSColin Finck {
229c2c66affSColin Finck gl_info->fbo_ops.glFramebufferRenderbuffer(fbo_target, GL_COLOR_ATTACHMENT0 + idx,
230c2c66affSColin Finck GL_RENDERBUFFER, resource->object);
231c2c66affSColin Finck checkGLcall("glFramebufferRenderbuffer()");
232c2c66affSColin Finck }
233c2c66affSColin Finck else
234c2c66affSColin Finck {
235c2c66affSColin Finck context_attach_gl_texture_fbo(context, fbo_target, GL_COLOR_ATTACHMENT0 + idx, resource);
236c2c66affSColin Finck }
237c2c66affSColin Finck }
238c2c66affSColin Finck else
239c2c66affSColin Finck {
240c2c66affSColin Finck context_attach_gl_texture_fbo(context, fbo_target, GL_COLOR_ATTACHMENT0 + idx, NULL);
241c2c66affSColin Finck }
242c2c66affSColin Finck }
243c2c66affSColin Finck
context_dump_fbo_attachment(const struct wined3d_gl_info * gl_info,GLenum target,GLenum attachment)244c2c66affSColin Finck static void context_dump_fbo_attachment(const struct wined3d_gl_info *gl_info, GLenum target,
245c2c66affSColin Finck GLenum attachment)
246c2c66affSColin Finck {
247c2c66affSColin Finck static const struct
248c2c66affSColin Finck {
249c2c66affSColin Finck GLenum target;
250c2c66affSColin Finck GLenum binding;
251c2c66affSColin Finck const char *str;
252c2c66affSColin Finck enum wined3d_gl_extension extension;
253c2c66affSColin Finck }
254c2c66affSColin Finck texture_type[] =
255c2c66affSColin Finck {
256c2c66affSColin Finck {GL_TEXTURE_2D, GL_TEXTURE_BINDING_2D, "2d", WINED3D_GL_EXT_NONE},
257c2c66affSColin Finck {GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_BINDING_RECTANGLE_ARB, "rectangle", ARB_TEXTURE_RECTANGLE},
258c2c66affSColin Finck {GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BINDING_2D_ARRAY, "2d-array" , EXT_TEXTURE_ARRAY},
2599987f029SAmine Khaldi {GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BINDING_CUBE_MAP, "cube", ARB_TEXTURE_CUBE_MAP},
2609987f029SAmine Khaldi {GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_BINDING_2D_MULTISAMPLE, "2d-ms", ARB_TEXTURE_MULTISAMPLE},
2619987f029SAmine Khaldi {GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, "2d-array-ms", ARB_TEXTURE_MULTISAMPLE},
262c2c66affSColin Finck };
263c2c66affSColin Finck
264c2c66affSColin Finck GLint type, name, samples, width, height, old_texture, level, face, fmt, tex_target;
2659987f029SAmine Khaldi const char *tex_type_str;
2669987f029SAmine Khaldi unsigned int i;
267c2c66affSColin Finck
268c2c66affSColin Finck gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
269c2c66affSColin Finck GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &name);
270c2c66affSColin Finck gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
271c2c66affSColin Finck GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
272c2c66affSColin Finck
273c2c66affSColin Finck if (type == GL_RENDERBUFFER)
274c2c66affSColin Finck {
275c2c66affSColin Finck gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, name);
276c2c66affSColin Finck gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
277c2c66affSColin Finck gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
278c2c66affSColin Finck if (gl_info->limits.samples > 1)
279c2c66affSColin Finck gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
280c2c66affSColin Finck else
281c2c66affSColin Finck samples = 1;
282c2c66affSColin Finck gl_info->fbo_ops.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_INTERNAL_FORMAT, &fmt);
283c2c66affSColin Finck FIXME(" %s: renderbuffer %d, %dx%d, %d samples, format %#x.\n",
284c2c66affSColin Finck debug_fboattachment(attachment), name, width, height, samples, fmt);
285c2c66affSColin Finck }
286c2c66affSColin Finck else if (type == GL_TEXTURE)
287c2c66affSColin Finck {
288c2c66affSColin Finck gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
289c2c66affSColin Finck GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &level);
290c2c66affSColin Finck gl_info->fbo_ops.glGetFramebufferAttachmentParameteriv(target, attachment,
291c2c66affSColin Finck GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, &face);
292c2c66affSColin Finck
2939987f029SAmine Khaldi if (gl_info->gl_ops.ext.p_glGetTextureParameteriv)
2949987f029SAmine Khaldi {
2959987f029SAmine Khaldi GL_EXTCALL(glGetTextureParameteriv(name, GL_TEXTURE_TARGET, &tex_target));
2969987f029SAmine Khaldi
2979987f029SAmine Khaldi for (i = 0; i < ARRAY_SIZE(texture_type); ++i)
2989987f029SAmine Khaldi {
2999987f029SAmine Khaldi if (texture_type[i].target == tex_target)
3009987f029SAmine Khaldi {
3019987f029SAmine Khaldi tex_type_str = texture_type[i].str;
3029987f029SAmine Khaldi break;
3039987f029SAmine Khaldi }
3049987f029SAmine Khaldi }
3059987f029SAmine Khaldi if (i == ARRAY_SIZE(texture_type))
3069987f029SAmine Khaldi tex_type_str = wine_dbg_sprintf("%#x", tex_target);
3079987f029SAmine Khaldi }
3089987f029SAmine Khaldi else if (face)
309c2c66affSColin Finck {
310c2c66affSColin Finck gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &old_texture);
311c2c66affSColin Finck gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, name);
312c2c66affSColin Finck
313c2c66affSColin Finck tex_target = GL_TEXTURE_CUBE_MAP;
314c2c66affSColin Finck tex_type_str = "cube";
315c2c66affSColin Finck }
316c2c66affSColin Finck else
317c2c66affSColin Finck {
318c2c66affSColin Finck tex_type_str = NULL;
3199987f029SAmine Khaldi
320d6ac0a71SAmine Khaldi for (i = 0; i < ARRAY_SIZE(texture_type); ++i)
321c2c66affSColin Finck {
322c2c66affSColin Finck if (!gl_info->supported[texture_type[i].extension])
323c2c66affSColin Finck continue;
324c2c66affSColin Finck
325c2c66affSColin Finck gl_info->gl_ops.gl.p_glGetIntegerv(texture_type[i].binding, &old_texture);
326c2c66affSColin Finck while (gl_info->gl_ops.gl.p_glGetError());
327c2c66affSColin Finck
328c2c66affSColin Finck gl_info->gl_ops.gl.p_glBindTexture(texture_type[i].target, name);
329c2c66affSColin Finck if (!gl_info->gl_ops.gl.p_glGetError())
330c2c66affSColin Finck {
331c2c66affSColin Finck tex_target = texture_type[i].target;
332c2c66affSColin Finck tex_type_str = texture_type[i].str;
333c2c66affSColin Finck break;
334c2c66affSColin Finck }
335c2c66affSColin Finck gl_info->gl_ops.gl.p_glBindTexture(texture_type[i].target, old_texture);
336c2c66affSColin Finck }
3379987f029SAmine Khaldi
338c2c66affSColin Finck if (!tex_type_str)
339c2c66affSColin Finck {
340c2c66affSColin Finck FIXME("Cannot find type of texture %d.\n", name);
341c2c66affSColin Finck return;
342c2c66affSColin Finck }
3439987f029SAmine Khaldi }
344c2c66affSColin Finck
3459987f029SAmine Khaldi if (gl_info->gl_ops.ext.p_glGetTextureParameteriv)
3469987f029SAmine Khaldi {
3479987f029SAmine Khaldi GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_INTERNAL_FORMAT, &fmt));
3489987f029SAmine Khaldi GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_WIDTH, &width));
3499987f029SAmine Khaldi GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_HEIGHT, &height));
3509987f029SAmine Khaldi GL_EXTCALL(glGetTextureLevelParameteriv(name, level, GL_TEXTURE_SAMPLES, &samples));
3519987f029SAmine Khaldi }
3529987f029SAmine Khaldi else
3539987f029SAmine Khaldi {
354c2c66affSColin Finck gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_INTERNAL_FORMAT, &fmt);
355c2c66affSColin Finck gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_WIDTH, &width);
356c2c66affSColin Finck gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_HEIGHT, &height);
3579987f029SAmine Khaldi if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
3589987f029SAmine Khaldi gl_info->gl_ops.gl.p_glGetTexLevelParameteriv(tex_target, level, GL_TEXTURE_SAMPLES, &samples);
3599987f029SAmine Khaldi else
3609987f029SAmine Khaldi samples = 1;
361c2c66affSColin Finck
362c2c66affSColin Finck gl_info->gl_ops.gl.p_glBindTexture(tex_target, old_texture);
3639987f029SAmine Khaldi }
3649987f029SAmine Khaldi
3659987f029SAmine Khaldi FIXME(" %s: %s texture %d, %dx%d, %d samples, format %#x.\n",
3669987f029SAmine Khaldi debug_fboattachment(attachment), tex_type_str, name, width, height, samples, fmt);
367c2c66affSColin Finck }
368c2c66affSColin Finck else if (type == GL_NONE)
369c2c66affSColin Finck {
370c2c66affSColin Finck FIXME(" %s: NONE.\n", debug_fboattachment(attachment));
371c2c66affSColin Finck }
372c2c66affSColin Finck else
373c2c66affSColin Finck {
374c2c66affSColin Finck ERR(" %s: Unknown attachment %#x.\n", debug_fboattachment(attachment), type);
375c2c66affSColin Finck }
3769987f029SAmine Khaldi
3779987f029SAmine Khaldi checkGLcall("dump FBO attachment");
378c2c66affSColin Finck }
379c2c66affSColin Finck
380c2c66affSColin Finck /* Context activation is done by the caller. */
context_check_fbo_status(const struct wined3d_context * context,GLenum target)381c2c66affSColin Finck void context_check_fbo_status(const struct wined3d_context *context, GLenum target)
382c2c66affSColin Finck {
383c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
384c2c66affSColin Finck GLenum status;
385c2c66affSColin Finck
3869987f029SAmine Khaldi if (!FIXME_ON(d3d))
3879987f029SAmine Khaldi return;
388c2c66affSColin Finck
389c2c66affSColin Finck status = gl_info->fbo_ops.glCheckFramebufferStatus(target);
390c2c66affSColin Finck if (status == GL_FRAMEBUFFER_COMPLETE)
391c2c66affSColin Finck {
3929987f029SAmine Khaldi TRACE("FBO complete.\n");
393c2c66affSColin Finck }
394c2c66affSColin Finck else
395c2c66affSColin Finck {
396c2c66affSColin Finck unsigned int i;
397c2c66affSColin Finck
3989987f029SAmine Khaldi FIXME("FBO status %s (%#x).\n", debug_fbostatus(status), status);
399c2c66affSColin Finck
400c2c66affSColin Finck if (!context->current_fbo)
401c2c66affSColin Finck {
402c2c66affSColin Finck ERR("FBO 0 is incomplete, driver bug?\n");
403c2c66affSColin Finck return;
404c2c66affSColin Finck }
405c2c66affSColin Finck
406c2c66affSColin Finck context_dump_fbo_attachment(gl_info, target, GL_DEPTH_ATTACHMENT);
407c2c66affSColin Finck context_dump_fbo_attachment(gl_info, target, GL_STENCIL_ATTACHMENT);
408c2c66affSColin Finck
409c2c66affSColin Finck for (i = 0; i < gl_info->limits.buffers; ++i)
410c2c66affSColin Finck context_dump_fbo_attachment(gl_info, target, GL_COLOR_ATTACHMENT0 + i);
411c2c66affSColin Finck }
412c2c66affSColin Finck }
413c2c66affSColin Finck
context_generate_rt_mask(GLenum buffer)414c2c66affSColin Finck static inline DWORD context_generate_rt_mask(GLenum buffer)
415c2c66affSColin Finck {
416c2c66affSColin Finck /* Should take care of all the GL_FRONT/GL_BACK/GL_AUXi/GL_NONE... cases */
417c2c66affSColin Finck return buffer ? (1u << 31) | buffer : 0;
418c2c66affSColin Finck }
419c2c66affSColin Finck
context_generate_rt_mask_from_resource(struct wined3d_resource * resource)420c2c66affSColin Finck static inline DWORD context_generate_rt_mask_from_resource(struct wined3d_resource *resource)
421c2c66affSColin Finck {
422c2c66affSColin Finck if (resource->type != WINED3D_RTYPE_TEXTURE_2D)
423c2c66affSColin Finck {
424c2c66affSColin Finck FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
425c2c66affSColin Finck return 0;
426c2c66affSColin Finck }
427c2c66affSColin Finck
428c2c66affSColin Finck return (1u << 31) | wined3d_texture_get_gl_buffer(texture_from_resource(resource));
429c2c66affSColin Finck }
430c2c66affSColin Finck
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)431c2c66affSColin Finck static inline void context_set_fbo_key_for_render_target(const struct wined3d_context *context,
4329987f029SAmine Khaldi struct wined3d_fbo_entry_key *key, unsigned int idx, const struct wined3d_rendertarget_info *render_target,
433c2c66affSColin Finck DWORD location)
434c2c66affSColin Finck {
435c2c66affSColin Finck unsigned int sub_resource_idx = render_target->sub_resource_idx;
436c2c66affSColin Finck struct wined3d_resource *resource = render_target->resource;
437c2c66affSColin Finck struct wined3d_texture *texture;
438c2c66affSColin Finck
439c2c66affSColin Finck if (!resource || resource->format->id == WINED3DFMT_NULL || resource->type == WINED3D_RTYPE_BUFFER)
440c2c66affSColin Finck {
441c2c66affSColin Finck if (resource && resource->type == WINED3D_RTYPE_BUFFER)
442c2c66affSColin Finck FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
443c2c66affSColin Finck key->objects[idx].object = 0;
444c2c66affSColin Finck key->objects[idx].target = 0;
445c2c66affSColin Finck key->objects[idx].level = key->objects[idx].layer = 0;
446c2c66affSColin Finck return;
447c2c66affSColin Finck }
448c2c66affSColin Finck
449c2c66affSColin Finck if (render_target->gl_view.name)
450c2c66affSColin Finck {
451c2c66affSColin Finck key->objects[idx].object = render_target->gl_view.name;
452c2c66affSColin Finck key->objects[idx].target = render_target->gl_view.target;
453c2c66affSColin Finck key->objects[idx].level = 0;
454c2c66affSColin Finck key->objects[idx].layer = WINED3D_ALL_LAYERS;
455c2c66affSColin Finck return;
456c2c66affSColin Finck }
457c2c66affSColin Finck
458c2c66affSColin Finck texture = wined3d_texture_from_resource(resource);
459*81cffd76SJoachim Henze if (resource->type == WINED3D_RTYPE_TEXTURE_2D)
460c2c66affSColin Finck {
461*81cffd76SJoachim Henze struct wined3d_surface *surface = texture->sub_resources[sub_resource_idx].u.surface;
462*81cffd76SJoachim Henze
463*81cffd76SJoachim Henze if (surface->current_renderbuffer)
464*81cffd76SJoachim Henze {
465*81cffd76SJoachim Henze key->objects[idx].object = surface->current_renderbuffer->id;
466c2c66affSColin Finck key->objects[idx].target = 0;
467c2c66affSColin Finck key->objects[idx].level = key->objects[idx].layer = 0;
468c2c66affSColin Finck key->rb_namespace |= 1 << idx;
469c2c66affSColin Finck return;
470c2c66affSColin Finck }
471*81cffd76SJoachim Henze }
4729987f029SAmine Khaldi key->objects[idx].target = wined3d_texture_get_sub_resource_target(texture, sub_resource_idx);
473c2c66affSColin Finck key->objects[idx].level = sub_resource_idx % texture->level_count;
474c2c66affSColin Finck key->objects[idx].layer = sub_resource_idx / texture->level_count;
4759987f029SAmine Khaldi
476c2c66affSColin Finck if (render_target->layer_count != 1)
477c2c66affSColin Finck key->objects[idx].layer = WINED3D_ALL_LAYERS;
478c2c66affSColin Finck
479c2c66affSColin Finck switch (location)
480c2c66affSColin Finck {
481c2c66affSColin Finck case WINED3D_LOCATION_TEXTURE_RGB:
482c2c66affSColin Finck key->objects[idx].object = wined3d_texture_get_texture_name(texture, context, FALSE);
483c2c66affSColin Finck break;
484c2c66affSColin Finck
485c2c66affSColin Finck case WINED3D_LOCATION_TEXTURE_SRGB:
486c2c66affSColin Finck key->objects[idx].object = wined3d_texture_get_texture_name(texture, context, TRUE);
487c2c66affSColin Finck break;
488c2c66affSColin Finck
489c2c66affSColin Finck case WINED3D_LOCATION_RB_MULTISAMPLE:
490c2c66affSColin Finck key->objects[idx].object = texture->rb_multisample;
491c2c66affSColin Finck key->objects[idx].target = 0;
492c2c66affSColin Finck key->objects[idx].level = key->objects[idx].layer = 0;
493c2c66affSColin Finck key->rb_namespace |= 1 << idx;
494c2c66affSColin Finck break;
495c2c66affSColin Finck
496c2c66affSColin Finck case WINED3D_LOCATION_RB_RESOLVED:
497c2c66affSColin Finck key->objects[idx].object = texture->rb_resolved;
498c2c66affSColin Finck key->objects[idx].target = 0;
499c2c66affSColin Finck key->objects[idx].level = key->objects[idx].layer = 0;
500c2c66affSColin Finck key->rb_namespace |= 1 << idx;
501c2c66affSColin Finck break;
502c2c66affSColin Finck }
503c2c66affSColin Finck }
504c2c66affSColin Finck
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)505c2c66affSColin Finck static void context_generate_fbo_key(const struct wined3d_context *context,
5069987f029SAmine Khaldi struct wined3d_fbo_entry_key *key, const struct wined3d_rendertarget_info *render_targets,
5079987f029SAmine Khaldi const struct wined3d_rendertarget_info *depth_stencil, DWORD color_location, DWORD ds_location)
508c2c66affSColin Finck {
5099987f029SAmine Khaldi unsigned int buffers = context->gl_info->limits.buffers;
510c2c66affSColin Finck unsigned int i;
511c2c66affSColin Finck
512c2c66affSColin Finck key->rb_namespace = 0;
5139987f029SAmine Khaldi context_set_fbo_key_for_render_target(context, key, 0, depth_stencil, ds_location);
514c2c66affSColin Finck
5159987f029SAmine Khaldi for (i = 0; i < buffers; ++i)
516c2c66affSColin Finck context_set_fbo_key_for_render_target(context, key, i + 1, &render_targets[i], color_location);
5179987f029SAmine Khaldi
5189987f029SAmine Khaldi memset(&key->objects[buffers + 1], 0, (ARRAY_SIZE(key->objects) - buffers - 1) * sizeof(*key->objects));
519c2c66affSColin Finck }
520c2c66affSColin Finck
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)521c2c66affSColin Finck static struct fbo_entry *context_create_fbo_entry(const struct wined3d_context *context,
5229987f029SAmine Khaldi const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
523c2c66affSColin Finck DWORD color_location, DWORD ds_location)
524c2c66affSColin Finck {
525c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
526c2c66affSColin Finck struct fbo_entry *entry;
527c2c66affSColin Finck
5289987f029SAmine Khaldi entry = heap_alloc(sizeof(*entry));
529c2c66affSColin Finck context_generate_fbo_key(context, &entry->key, render_targets, depth_stencil, color_location, ds_location);
530c2c66affSColin Finck entry->flags = 0;
5319987f029SAmine Khaldi if (depth_stencil->resource)
532c2c66affSColin Finck {
5339987f029SAmine Khaldi if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_DEPTH)
534c2c66affSColin Finck entry->flags |= WINED3D_FBO_ENTRY_FLAG_DEPTH;
5359987f029SAmine Khaldi if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_STENCIL)
536c2c66affSColin Finck entry->flags |= WINED3D_FBO_ENTRY_FLAG_STENCIL;
537c2c66affSColin Finck }
538c2c66affSColin Finck entry->rt_mask = context_generate_rt_mask(GL_COLOR_ATTACHMENT0);
539c2c66affSColin Finck gl_info->fbo_ops.glGenFramebuffers(1, &entry->id);
540c2c66affSColin Finck checkGLcall("glGenFramebuffers()");
541c2c66affSColin Finck TRACE("Created FBO %u.\n", entry->id);
542c2c66affSColin Finck
543c2c66affSColin Finck return entry;
544c2c66affSColin Finck }
545c2c66affSColin Finck
546c2c66affSColin Finck /* 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)547c2c66affSColin Finck static void context_reuse_fbo_entry(struct wined3d_context *context, GLenum target,
5489987f029SAmine Khaldi const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
549c2c66affSColin Finck DWORD color_location, DWORD ds_location, struct fbo_entry *entry)
550c2c66affSColin Finck {
551c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
552c2c66affSColin Finck
553c2c66affSColin Finck context_bind_fbo(context, target, entry->id);
554c2c66affSColin Finck context_clean_fbo_attachments(gl_info, target);
555c2c66affSColin Finck
556c2c66affSColin Finck context_generate_fbo_key(context, &entry->key, render_targets, depth_stencil, color_location, ds_location);
557c2c66affSColin Finck entry->flags = 0;
5589987f029SAmine Khaldi if (depth_stencil->resource)
559c2c66affSColin Finck {
5609987f029SAmine Khaldi if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_DEPTH)
561c2c66affSColin Finck entry->flags |= WINED3D_FBO_ENTRY_FLAG_DEPTH;
5629987f029SAmine Khaldi if (depth_stencil->resource->format_flags & WINED3DFMT_FLAG_STENCIL)
563c2c66affSColin Finck entry->flags |= WINED3D_FBO_ENTRY_FLAG_STENCIL;
564c2c66affSColin Finck }
565c2c66affSColin Finck }
566c2c66affSColin Finck
567c2c66affSColin Finck /* Context activation is done by the caller. */
context_destroy_fbo_entry(struct wined3d_context * context,struct fbo_entry * entry)568c2c66affSColin Finck static void context_destroy_fbo_entry(struct wined3d_context *context, struct fbo_entry *entry)
569c2c66affSColin Finck {
570c2c66affSColin Finck if (entry->id)
571c2c66affSColin Finck {
572c2c66affSColin Finck TRACE("Destroy FBO %u.\n", entry->id);
573c2c66affSColin Finck context_destroy_fbo(context, entry->id);
574c2c66affSColin Finck }
575c2c66affSColin Finck --context->fbo_entry_count;
576c2c66affSColin Finck list_remove(&entry->entry);
5779987f029SAmine Khaldi heap_free(entry);
578c2c66affSColin Finck }
579c2c66affSColin Finck
580c2c66affSColin Finck /* 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)581c2c66affSColin Finck static struct fbo_entry *context_find_fbo_entry(struct wined3d_context *context, GLenum target,
5829987f029SAmine Khaldi const struct wined3d_rendertarget_info *render_targets, const struct wined3d_rendertarget_info *depth_stencil,
583c2c66affSColin Finck DWORD color_location, DWORD ds_location)
584c2c66affSColin Finck {
5859987f029SAmine Khaldi static const struct wined3d_rendertarget_info ds_null = {{0}};
586c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
587c2c66affSColin Finck struct wined3d_texture *rt_texture, *ds_texture;
5889987f029SAmine Khaldi struct wined3d_fbo_entry_key fbo_key;
5899987f029SAmine Khaldi unsigned int i, ds_level, rt_level;
590c2c66affSColin Finck struct fbo_entry *entry;
591c2c66affSColin Finck
5929987f029SAmine Khaldi if (depth_stencil->resource && depth_stencil->resource->type != WINED3D_RTYPE_BUFFER
5939987f029SAmine Khaldi && render_targets[0].resource && render_targets[0].resource->type != WINED3D_RTYPE_BUFFER)
594c2c66affSColin Finck {
595c2c66affSColin Finck rt_texture = wined3d_texture_from_resource(render_targets[0].resource);
5969987f029SAmine Khaldi rt_level = render_targets[0].sub_resource_idx % rt_texture->level_count;
5979987f029SAmine Khaldi ds_texture = wined3d_texture_from_resource(depth_stencil->resource);
5989987f029SAmine Khaldi ds_level = depth_stencil->sub_resource_idx % ds_texture->level_count;
599c2c66affSColin Finck
6009987f029SAmine Khaldi if (wined3d_texture_get_level_width(ds_texture, ds_level)
6019987f029SAmine Khaldi < wined3d_texture_get_level_width(rt_texture, rt_level)
6029987f029SAmine Khaldi || wined3d_texture_get_level_height(ds_texture, ds_level)
6039987f029SAmine Khaldi < wined3d_texture_get_level_height(rt_texture, rt_level))
604c2c66affSColin Finck {
605c2c66affSColin Finck WARN("Depth stencil is smaller than the primary color buffer, disabling.\n");
6069987f029SAmine Khaldi depth_stencil = &ds_null;
607c2c66affSColin Finck }
608c2c66affSColin Finck else if (ds_texture->resource.multisample_type != rt_texture->resource.multisample_type
609c2c66affSColin Finck || ds_texture->resource.multisample_quality != rt_texture->resource.multisample_quality)
610c2c66affSColin Finck {
611c2c66affSColin Finck WARN("Color multisample type %u and quality %u, depth stencil has %u and %u, disabling ds buffer.\n",
612c2c66affSColin Finck rt_texture->resource.multisample_type, rt_texture->resource.multisample_quality,
613c2c66affSColin Finck ds_texture->resource.multisample_type, ds_texture->resource.multisample_quality);
6149987f029SAmine Khaldi depth_stencil = &ds_null;
615c2c66affSColin Finck }
6169987f029SAmine Khaldi else if (depth_stencil->resource->type == WINED3D_RTYPE_TEXTURE_2D)
6179987f029SAmine Khaldi {
618*81cffd76SJoachim Henze struct wined3d_surface *surface;
619*81cffd76SJoachim Henze
620*81cffd76SJoachim Henze surface = ds_texture->sub_resources[depth_stencil->sub_resource_idx].u.surface;
621*81cffd76SJoachim Henze surface_set_compatible_renderbuffer(surface, &render_targets[0]);
6229987f029SAmine Khaldi }
623c2c66affSColin Finck }
624c2c66affSColin Finck
6259987f029SAmine Khaldi context_generate_fbo_key(context, &fbo_key, render_targets, depth_stencil, color_location, ds_location);
626c2c66affSColin Finck
627c2c66affSColin Finck if (TRACE_ON(d3d))
628c2c66affSColin Finck {
629c2c66affSColin Finck struct wined3d_resource *resource;
630c2c66affSColin Finck unsigned int width, height;
631c2c66affSColin Finck const char *resource_type;
632c2c66affSColin Finck
6339987f029SAmine Khaldi TRACE("Dumping FBO attachments:\n");
6349987f029SAmine Khaldi for (i = 0; i < gl_info->limits.buffers; ++i)
6359987f029SAmine Khaldi {
6369987f029SAmine Khaldi if ((resource = render_targets[i].resource))
6379987f029SAmine Khaldi {
638c2c66affSColin Finck if (resource->type == WINED3D_RTYPE_BUFFER)
639c2c66affSColin Finck {
640c2c66affSColin Finck width = resource->size;
641c2c66affSColin Finck height = 1;
642c2c66affSColin Finck resource_type = "buffer";
643c2c66affSColin Finck }
644c2c66affSColin Finck else
645c2c66affSColin Finck {
646c2c66affSColin Finck rt_texture = wined3d_texture_from_resource(resource);
6479987f029SAmine Khaldi rt_level = render_targets[i].sub_resource_idx % rt_texture->level_count;
6489987f029SAmine Khaldi width = wined3d_texture_get_level_pow2_width(rt_texture, rt_level);
6499987f029SAmine Khaldi height = wined3d_texture_get_level_pow2_height(rt_texture, rt_level);
650c2c66affSColin Finck resource_type = "texture";
651c2c66affSColin Finck }
652c2c66affSColin Finck
653c2c66affSColin Finck TRACE(" Color attachment %u: %p, %u format %s, %s %u, %ux%u, %u samples.\n",
654c2c66affSColin Finck i, resource, render_targets[i].sub_resource_idx, debug_d3dformat(resource->format->id),
6559987f029SAmine Khaldi fbo_key.rb_namespace & (1 << (i + 1)) ? "renderbuffer" : resource_type,
6569987f029SAmine Khaldi fbo_key.objects[i + 1].object, width, height, resource->multisample_type);
657c2c66affSColin Finck }
658c2c66affSColin Finck }
6599987f029SAmine Khaldi if ((resource = depth_stencil->resource))
660c2c66affSColin Finck {
6619987f029SAmine Khaldi if (resource->type == WINED3D_RTYPE_BUFFER)
6629987f029SAmine Khaldi {
6639987f029SAmine Khaldi width = resource->size;
6649987f029SAmine Khaldi height = 1;
6659987f029SAmine Khaldi resource_type = "buffer";
6669987f029SAmine Khaldi }
6679987f029SAmine Khaldi else
6689987f029SAmine Khaldi {
6699987f029SAmine Khaldi ds_texture = wined3d_texture_from_resource(resource);
6709987f029SAmine Khaldi ds_level = depth_stencil->sub_resource_idx % ds_texture->level_count;
6719987f029SAmine Khaldi width = wined3d_texture_get_level_pow2_width(ds_texture, ds_level);
6729987f029SAmine Khaldi height = wined3d_texture_get_level_pow2_height(ds_texture, ds_level);
6739987f029SAmine Khaldi resource_type = "texture";
6749987f029SAmine Khaldi }
6759987f029SAmine Khaldi
6769987f029SAmine Khaldi TRACE(" Depth attachment: %p, %u format %s, %s %u, %ux%u, %u samples.\n",
6779987f029SAmine Khaldi resource, depth_stencil->sub_resource_idx, debug_d3dformat(resource->format->id),
6789987f029SAmine Khaldi fbo_key.rb_namespace & (1 << 0) ? "renderbuffer" : resource_type,
6799987f029SAmine Khaldi fbo_key.objects[0].object, width, height, resource->multisample_type);
680c2c66affSColin Finck }
681c2c66affSColin Finck }
682c2c66affSColin Finck
683c2c66affSColin Finck LIST_FOR_EACH_ENTRY(entry, &context->fbo_list, struct fbo_entry, entry)
684c2c66affSColin Finck {
6859987f029SAmine Khaldi if (memcmp(&fbo_key, &entry->key, sizeof(fbo_key)))
686c2c66affSColin Finck continue;
687c2c66affSColin Finck
688c2c66affSColin Finck list_remove(&entry->entry);
689c2c66affSColin Finck list_add_head(&context->fbo_list, &entry->entry);
690c2c66affSColin Finck return entry;
691c2c66affSColin Finck }
692c2c66affSColin Finck
693c2c66affSColin Finck if (context->fbo_entry_count < WINED3D_MAX_FBO_ENTRIES)
694c2c66affSColin Finck {
695c2c66affSColin Finck entry = context_create_fbo_entry(context, render_targets, depth_stencil, color_location, ds_location);
696c2c66affSColin Finck list_add_head(&context->fbo_list, &entry->entry);
697c2c66affSColin Finck ++context->fbo_entry_count;
698c2c66affSColin Finck }
699c2c66affSColin Finck else
700c2c66affSColin Finck {
701c2c66affSColin Finck entry = LIST_ENTRY(list_tail(&context->fbo_list), struct fbo_entry, entry);
702c2c66affSColin Finck context_reuse_fbo_entry(context, target, render_targets, depth_stencil, color_location, ds_location, entry);
703c2c66affSColin Finck list_remove(&entry->entry);
704c2c66affSColin Finck list_add_head(&context->fbo_list, &entry->entry);
705c2c66affSColin Finck }
706c2c66affSColin Finck
707c2c66affSColin Finck return entry;
708c2c66affSColin Finck }
709c2c66affSColin Finck
710c2c66affSColin Finck /* Context activation is done by the caller. */
context_apply_fbo_entry(struct wined3d_context * context,GLenum target,struct fbo_entry * entry)711c2c66affSColin Finck static void context_apply_fbo_entry(struct wined3d_context *context, GLenum target, struct fbo_entry *entry)
712c2c66affSColin Finck {
713c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
714c2c66affSColin Finck GLuint read_binding, draw_binding;
7159987f029SAmine Khaldi unsigned int i;
716c2c66affSColin Finck
717c2c66affSColin Finck if (entry->flags & WINED3D_FBO_ENTRY_FLAG_ATTACHED)
718c2c66affSColin Finck {
719c2c66affSColin Finck context_bind_fbo(context, target, entry->id);
720c2c66affSColin Finck return;
721c2c66affSColin Finck }
722c2c66affSColin Finck
723c2c66affSColin Finck read_binding = context->fbo_read_binding;
724c2c66affSColin Finck draw_binding = context->fbo_draw_binding;
725c2c66affSColin Finck context_bind_fbo(context, GL_FRAMEBUFFER, entry->id);
726c2c66affSColin Finck
7279987f029SAmine Khaldi if (gl_info->supported[ARB_FRAMEBUFFER_NO_ATTACHMENTS])
7289987f029SAmine Khaldi {
7299987f029SAmine Khaldi GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER,
7309987f029SAmine Khaldi GL_FRAMEBUFFER_DEFAULT_WIDTH, gl_info->limits.framebuffer_width));
7319987f029SAmine Khaldi GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER,
7329987f029SAmine Khaldi GL_FRAMEBUFFER_DEFAULT_HEIGHT, gl_info->limits.framebuffer_height));
7339987f029SAmine Khaldi GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS, 1));
7349987f029SAmine Khaldi GL_EXTCALL(glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, 1));
7359987f029SAmine Khaldi }
7369987f029SAmine Khaldi
737c2c66affSColin Finck /* Apply render targets */
738c2c66affSColin Finck for (i = 0; i < gl_info->limits.buffers; ++i)
739c2c66affSColin Finck {
740c2c66affSColin Finck context_attach_surface_fbo(context, target, i, &entry->key.objects[i + 1],
741c2c66affSColin Finck entry->key.rb_namespace & (1 << (i + 1)));
742c2c66affSColin Finck }
743c2c66affSColin Finck
744c2c66affSColin Finck context_attach_depth_stencil_fbo(context, target, &entry->key.objects[0],
745c2c66affSColin Finck entry->key.rb_namespace & 0x1, entry->flags);
746c2c66affSColin Finck
747c2c66affSColin Finck /* Set valid read and draw buffer bindings to satisfy pedantic pre-ES2_compatibility
748c2c66affSColin Finck * GL contexts requirements. */
749c2c66affSColin Finck gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
750c2c66affSColin Finck context_set_draw_buffer(context, GL_NONE);
751c2c66affSColin Finck if (target != GL_FRAMEBUFFER)
752c2c66affSColin Finck {
753c2c66affSColin Finck if (target == GL_READ_FRAMEBUFFER)
754c2c66affSColin Finck context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, draw_binding);
755c2c66affSColin Finck else
756c2c66affSColin Finck context_bind_fbo(context, GL_READ_FRAMEBUFFER, read_binding);
757c2c66affSColin Finck }
758c2c66affSColin Finck
759c2c66affSColin Finck entry->flags |= WINED3D_FBO_ENTRY_FLAG_ATTACHED;
760c2c66affSColin Finck }
761c2c66affSColin Finck
762c2c66affSColin Finck /* 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)763c2c66affSColin Finck static void context_apply_fbo_state(struct wined3d_context *context, GLenum target,
764*81cffd76SJoachim Henze struct wined3d_rendertarget_info *render_targets, struct wined3d_surface *depth_stencil,
765*81cffd76SJoachim Henze DWORD color_location, DWORD ds_location)
766c2c66affSColin Finck {
767c2c66affSColin Finck struct fbo_entry *entry, *entry2;
768c2c66affSColin Finck
769c2c66affSColin Finck LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
770c2c66affSColin Finck {
771c2c66affSColin Finck context_destroy_fbo_entry(context, entry);
772c2c66affSColin Finck }
773c2c66affSColin Finck
774c2c66affSColin Finck if (context->rebind_fbo)
775c2c66affSColin Finck {
776c2c66affSColin Finck context_bind_fbo(context, GL_FRAMEBUFFER, 0);
777c2c66affSColin Finck context->rebind_fbo = FALSE;
778c2c66affSColin Finck }
779c2c66affSColin Finck
780c2c66affSColin Finck if (color_location == WINED3D_LOCATION_DRAWABLE)
781c2c66affSColin Finck {
782c2c66affSColin Finck context->current_fbo = NULL;
783c2c66affSColin Finck context_bind_fbo(context, target, 0);
784c2c66affSColin Finck }
785c2c66affSColin Finck else
786c2c66affSColin Finck {
787*81cffd76SJoachim Henze struct wined3d_rendertarget_info ds = {{0}};
788*81cffd76SJoachim Henze
789*81cffd76SJoachim Henze if (depth_stencil)
790*81cffd76SJoachim Henze {
791*81cffd76SJoachim Henze ds.resource = &depth_stencil->container->resource;
792*81cffd76SJoachim Henze ds.sub_resource_idx = surface_get_sub_resource_idx(depth_stencil);
793*81cffd76SJoachim Henze ds.layer_count = 1;
794*81cffd76SJoachim Henze }
7959987f029SAmine Khaldi context->current_fbo = context_find_fbo_entry(context, target,
796*81cffd76SJoachim Henze render_targets, &ds, color_location, ds_location);
797c2c66affSColin Finck context_apply_fbo_entry(context, target, context->current_fbo);
798c2c66affSColin Finck }
799c2c66affSColin Finck }
800c2c66affSColin Finck
801c2c66affSColin Finck /* 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)802c2c66affSColin Finck void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target,
803*81cffd76SJoachim Henze struct wined3d_surface *render_target, struct wined3d_surface *depth_stencil, DWORD location)
804c2c66affSColin Finck {
8059987f029SAmine Khaldi memset(context->blit_targets, 0, sizeof(context->blit_targets));
806*81cffd76SJoachim Henze if (render_target)
807c2c66affSColin Finck {
808*81cffd76SJoachim Henze context->blit_targets[0].resource = &render_target->container->resource;
809*81cffd76SJoachim Henze context->blit_targets[0].sub_resource_idx = surface_get_sub_resource_idx(render_target);
810c2c66affSColin Finck context->blit_targets[0].layer_count = 1;
811c2c66affSColin Finck }
812*81cffd76SJoachim Henze context_apply_fbo_state(context, target, context->blit_targets, depth_stencil, location, location);
813c2c66affSColin Finck }
814c2c66affSColin Finck
815c2c66affSColin Finck /* Context activation is done by the caller. */
context_alloc_occlusion_query(struct wined3d_context * context,struct wined3d_occlusion_query * query)816c2c66affSColin Finck void context_alloc_occlusion_query(struct wined3d_context *context, struct wined3d_occlusion_query *query)
817c2c66affSColin Finck {
818c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
819c2c66affSColin Finck
820c2c66affSColin Finck if (context->free_occlusion_query_count)
821c2c66affSColin Finck {
822c2c66affSColin Finck query->id = context->free_occlusion_queries[--context->free_occlusion_query_count];
823c2c66affSColin Finck }
824c2c66affSColin Finck else
825c2c66affSColin Finck {
826c2c66affSColin Finck if (gl_info->supported[ARB_OCCLUSION_QUERY])
827c2c66affSColin Finck {
828c2c66affSColin Finck GL_EXTCALL(glGenQueries(1, &query->id));
829c2c66affSColin Finck checkGLcall("glGenQueries");
830c2c66affSColin Finck
831c2c66affSColin Finck TRACE("Allocated occlusion query %u in context %p.\n", query->id, context);
832c2c66affSColin Finck }
833c2c66affSColin Finck else
834c2c66affSColin Finck {
835c2c66affSColin Finck WARN("Occlusion queries not supported, not allocating query id.\n");
836c2c66affSColin Finck query->id = 0;
837c2c66affSColin Finck }
838c2c66affSColin Finck }
839c2c66affSColin Finck
840c2c66affSColin Finck query->context = context;
841c2c66affSColin Finck list_add_head(&context->occlusion_queries, &query->entry);
842c2c66affSColin Finck }
843c2c66affSColin Finck
context_free_occlusion_query(struct wined3d_occlusion_query * query)844c2c66affSColin Finck void context_free_occlusion_query(struct wined3d_occlusion_query *query)
845c2c66affSColin Finck {
846c2c66affSColin Finck struct wined3d_context *context = query->context;
847c2c66affSColin Finck
848c2c66affSColin Finck list_remove(&query->entry);
849c2c66affSColin Finck query->context = NULL;
850c2c66affSColin Finck
851c2c66affSColin Finck if (!wined3d_array_reserve((void **)&context->free_occlusion_queries,
852c2c66affSColin Finck &context->free_occlusion_query_size, context->free_occlusion_query_count + 1,
853c2c66affSColin Finck sizeof(*context->free_occlusion_queries)))
854c2c66affSColin Finck {
855c2c66affSColin Finck ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
856c2c66affSColin Finck return;
857c2c66affSColin Finck }
858c2c66affSColin Finck
859c2c66affSColin Finck context->free_occlusion_queries[context->free_occlusion_query_count++] = query->id;
860c2c66affSColin Finck }
861c2c66affSColin Finck
862c2c66affSColin Finck /* Context activation is done by the caller. */
context_alloc_fence(struct wined3d_context * context,struct wined3d_fence * fence)863c2c66affSColin Finck void context_alloc_fence(struct wined3d_context *context, struct wined3d_fence *fence)
864c2c66affSColin Finck {
865c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
866c2c66affSColin Finck
867c2c66affSColin Finck if (context->free_fence_count)
868c2c66affSColin Finck {
869c2c66affSColin Finck fence->object = context->free_fences[--context->free_fence_count];
870c2c66affSColin Finck }
871c2c66affSColin Finck else
872c2c66affSColin Finck {
873c2c66affSColin Finck if (gl_info->supported[ARB_SYNC])
874c2c66affSColin Finck {
875c2c66affSColin Finck /* Using ARB_sync, not much to do here. */
876c2c66affSColin Finck fence->object.sync = NULL;
877c2c66affSColin Finck TRACE("Allocated sync object in context %p.\n", context);
878c2c66affSColin Finck }
879c2c66affSColin Finck else if (gl_info->supported[APPLE_FENCE])
880c2c66affSColin Finck {
881c2c66affSColin Finck GL_EXTCALL(glGenFencesAPPLE(1, &fence->object.id));
882c2c66affSColin Finck checkGLcall("glGenFencesAPPLE");
883c2c66affSColin Finck
884c2c66affSColin Finck TRACE("Allocated fence %u in context %p.\n", fence->object.id, context);
885c2c66affSColin Finck }
886c2c66affSColin Finck else if(gl_info->supported[NV_FENCE])
887c2c66affSColin Finck {
888c2c66affSColin Finck GL_EXTCALL(glGenFencesNV(1, &fence->object.id));
889c2c66affSColin Finck checkGLcall("glGenFencesNV");
890c2c66affSColin Finck
891c2c66affSColin Finck TRACE("Allocated fence %u in context %p.\n", fence->object.id, context);
892c2c66affSColin Finck }
893c2c66affSColin Finck else
894c2c66affSColin Finck {
895c2c66affSColin Finck WARN("Fences not supported, not allocating fence.\n");
896c2c66affSColin Finck fence->object.id = 0;
897c2c66affSColin Finck }
898c2c66affSColin Finck }
899c2c66affSColin Finck
900c2c66affSColin Finck fence->context = context;
901c2c66affSColin Finck list_add_head(&context->fences, &fence->entry);
902c2c66affSColin Finck }
903c2c66affSColin Finck
context_free_fence(struct wined3d_fence * fence)904c2c66affSColin Finck void context_free_fence(struct wined3d_fence *fence)
905c2c66affSColin Finck {
906c2c66affSColin Finck struct wined3d_context *context = fence->context;
907c2c66affSColin Finck
908c2c66affSColin Finck list_remove(&fence->entry);
909c2c66affSColin Finck fence->context = NULL;
910c2c66affSColin Finck
911c2c66affSColin Finck if (!wined3d_array_reserve((void **)&context->free_fences,
912c2c66affSColin Finck &context->free_fence_size, context->free_fence_count + 1,
913c2c66affSColin Finck sizeof(*context->free_fences)))
914c2c66affSColin Finck {
915c2c66affSColin Finck ERR("Failed to grow free list, leaking fence %u in context %p.\n", fence->object.id, context);
916c2c66affSColin Finck return;
917c2c66affSColin Finck }
918c2c66affSColin Finck
919c2c66affSColin Finck context->free_fences[context->free_fence_count++] = fence->object;
920c2c66affSColin Finck }
921c2c66affSColin Finck
922c2c66affSColin Finck /* Context activation is done by the caller. */
context_alloc_timestamp_query(struct wined3d_context * context,struct wined3d_timestamp_query * query)923c2c66affSColin Finck void context_alloc_timestamp_query(struct wined3d_context *context, struct wined3d_timestamp_query *query)
924c2c66affSColin Finck {
925c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
926c2c66affSColin Finck
927c2c66affSColin Finck if (context->free_timestamp_query_count)
928c2c66affSColin Finck {
929c2c66affSColin Finck query->id = context->free_timestamp_queries[--context->free_timestamp_query_count];
930c2c66affSColin Finck }
931c2c66affSColin Finck else
932c2c66affSColin Finck {
933c2c66affSColin Finck GL_EXTCALL(glGenQueries(1, &query->id));
934c2c66affSColin Finck checkGLcall("glGenQueries");
935c2c66affSColin Finck
936c2c66affSColin Finck TRACE("Allocated timestamp query %u in context %p.\n", query->id, context);
937c2c66affSColin Finck }
938c2c66affSColin Finck
939c2c66affSColin Finck query->context = context;
940c2c66affSColin Finck list_add_head(&context->timestamp_queries, &query->entry);
941c2c66affSColin Finck }
942c2c66affSColin Finck
context_free_timestamp_query(struct wined3d_timestamp_query * query)943c2c66affSColin Finck void context_free_timestamp_query(struct wined3d_timestamp_query *query)
944c2c66affSColin Finck {
945c2c66affSColin Finck struct wined3d_context *context = query->context;
946c2c66affSColin Finck
947c2c66affSColin Finck list_remove(&query->entry);
948c2c66affSColin Finck query->context = NULL;
949c2c66affSColin Finck
950c2c66affSColin Finck if (!wined3d_array_reserve((void **)&context->free_timestamp_queries,
951c2c66affSColin Finck &context->free_timestamp_query_size, context->free_timestamp_query_count + 1,
952c2c66affSColin Finck sizeof(*context->free_timestamp_queries)))
953c2c66affSColin Finck {
954c2c66affSColin Finck ERR("Failed to grow free list, leaking query %u in context %p.\n", query->id, context);
955c2c66affSColin Finck return;
956c2c66affSColin Finck }
957c2c66affSColin Finck
958c2c66affSColin Finck context->free_timestamp_queries[context->free_timestamp_query_count++] = query->id;
959c2c66affSColin Finck }
960c2c66affSColin Finck
context_alloc_so_statistics_query(struct wined3d_context * context,struct wined3d_so_statistics_query * query)961c2c66affSColin Finck void context_alloc_so_statistics_query(struct wined3d_context *context,
962c2c66affSColin Finck struct wined3d_so_statistics_query *query)
963c2c66affSColin Finck {
964c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
965c2c66affSColin Finck
966c2c66affSColin Finck if (context->free_so_statistics_query_count)
967c2c66affSColin Finck {
968c2c66affSColin Finck query->u = context->free_so_statistics_queries[--context->free_so_statistics_query_count];
969c2c66affSColin Finck }
970c2c66affSColin Finck else
971c2c66affSColin Finck {
972c2c66affSColin Finck GL_EXTCALL(glGenQueries(ARRAY_SIZE(query->u.id), query->u.id));
973c2c66affSColin Finck checkGLcall("glGenQueries");
974c2c66affSColin Finck
975c2c66affSColin Finck TRACE("Allocated SO statistics queries %u, %u in context %p.\n",
976c2c66affSColin Finck query->u.id[0], query->u.id[1], context);
977c2c66affSColin Finck }
978c2c66affSColin Finck
979c2c66affSColin Finck query->context = context;
980c2c66affSColin Finck list_add_head(&context->so_statistics_queries, &query->entry);
981c2c66affSColin Finck }
982c2c66affSColin Finck
context_free_so_statistics_query(struct wined3d_so_statistics_query * query)983c2c66affSColin Finck void context_free_so_statistics_query(struct wined3d_so_statistics_query *query)
984c2c66affSColin Finck {
985c2c66affSColin Finck struct wined3d_context *context = query->context;
986c2c66affSColin Finck
987c2c66affSColin Finck list_remove(&query->entry);
988c2c66affSColin Finck query->context = NULL;
989c2c66affSColin Finck
990c2c66affSColin Finck if (!wined3d_array_reserve((void **)&context->free_so_statistics_queries,
991c2c66affSColin Finck &context->free_so_statistics_query_size, context->free_so_statistics_query_count + 1,
992c2c66affSColin Finck sizeof(*context->free_so_statistics_queries)))
993c2c66affSColin Finck {
994c2c66affSColin Finck ERR("Failed to grow free list, leaking GL queries %u, %u in context %p.\n",
995c2c66affSColin Finck query->u.id[0], query->u.id[1], context);
996c2c66affSColin Finck return;
997c2c66affSColin Finck }
998c2c66affSColin Finck
999c2c66affSColin Finck context->free_so_statistics_queries[context->free_so_statistics_query_count++] = query->u;
1000c2c66affSColin Finck }
1001c2c66affSColin Finck
context_alloc_pipeline_statistics_query(struct wined3d_context * context,struct wined3d_pipeline_statistics_query * query)1002c2c66affSColin Finck void context_alloc_pipeline_statistics_query(struct wined3d_context *context,
1003c2c66affSColin Finck struct wined3d_pipeline_statistics_query *query)
1004c2c66affSColin Finck {
1005c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
1006c2c66affSColin Finck
1007c2c66affSColin Finck if (context->free_pipeline_statistics_query_count)
1008c2c66affSColin Finck {
1009c2c66affSColin Finck query->u = context->free_pipeline_statistics_queries[--context->free_pipeline_statistics_query_count];
1010c2c66affSColin Finck }
1011c2c66affSColin Finck else
1012c2c66affSColin Finck {
1013c2c66affSColin Finck GL_EXTCALL(glGenQueries(ARRAY_SIZE(query->u.id), query->u.id));
1014c2c66affSColin Finck checkGLcall("glGenQueries");
1015c2c66affSColin Finck }
1016c2c66affSColin Finck
1017c2c66affSColin Finck query->context = context;
1018c2c66affSColin Finck list_add_head(&context->pipeline_statistics_queries, &query->entry);
1019c2c66affSColin Finck }
1020c2c66affSColin Finck
context_free_pipeline_statistics_query(struct wined3d_pipeline_statistics_query * query)1021c2c66affSColin Finck void context_free_pipeline_statistics_query(struct wined3d_pipeline_statistics_query *query)
1022c2c66affSColin Finck {
1023c2c66affSColin Finck struct wined3d_context *context = query->context;
1024c2c66affSColin Finck
1025c2c66affSColin Finck list_remove(&query->entry);
1026c2c66affSColin Finck query->context = NULL;
1027c2c66affSColin Finck
1028c2c66affSColin Finck if (!wined3d_array_reserve((void **)&context->free_pipeline_statistics_queries,
1029c2c66affSColin Finck &context->free_pipeline_statistics_query_size, context->free_pipeline_statistics_query_count + 1,
1030c2c66affSColin Finck sizeof(*context->free_pipeline_statistics_queries)))
1031c2c66affSColin Finck {
1032c2c66affSColin Finck ERR("Failed to grow free list, leaking GL queries in context %p.\n", context);
1033c2c66affSColin Finck return;
1034c2c66affSColin Finck }
1035c2c66affSColin Finck
1036c2c66affSColin Finck context->free_pipeline_statistics_queries[context->free_pipeline_statistics_query_count++] = query->u;
1037c2c66affSColin Finck }
1038c2c66affSColin Finck
1039c2c66affSColin Finck typedef void (context_fbo_entry_func_t)(struct wined3d_context *context, struct fbo_entry *entry);
1040c2c66affSColin Finck
context_enum_fbo_entries(const struct wined3d_device * device,GLuint name,BOOL rb_namespace,context_fbo_entry_func_t * callback)1041c2c66affSColin Finck static void context_enum_fbo_entries(const struct wined3d_device *device,
1042c2c66affSColin Finck GLuint name, BOOL rb_namespace, context_fbo_entry_func_t *callback)
1043c2c66affSColin Finck {
10449987f029SAmine Khaldi unsigned int i, j;
1045c2c66affSColin Finck
1046c2c66affSColin Finck for (i = 0; i < device->context_count; ++i)
1047c2c66affSColin Finck {
1048c2c66affSColin Finck struct wined3d_context *context = device->contexts[i];
1049c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
1050c2c66affSColin Finck struct fbo_entry *entry, *entry2;
1051c2c66affSColin Finck
1052c2c66affSColin Finck LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
1053c2c66affSColin Finck {
1054c2c66affSColin Finck for (j = 0; j < gl_info->limits.buffers + 1; ++j)
1055c2c66affSColin Finck {
1056c2c66affSColin Finck if (entry->key.objects[j].object == name
1057c2c66affSColin Finck && !(entry->key.rb_namespace & (1 << j)) == !rb_namespace)
1058c2c66affSColin Finck {
1059c2c66affSColin Finck callback(context, entry);
1060c2c66affSColin Finck break;
1061c2c66affSColin Finck }
1062c2c66affSColin Finck }
1063c2c66affSColin Finck }
1064c2c66affSColin Finck }
1065c2c66affSColin Finck }
1066c2c66affSColin Finck
context_queue_fbo_entry_destruction(struct wined3d_context * context,struct fbo_entry * entry)1067c2c66affSColin Finck static void context_queue_fbo_entry_destruction(struct wined3d_context *context, struct fbo_entry *entry)
1068c2c66affSColin Finck {
1069c2c66affSColin Finck list_remove(&entry->entry);
1070c2c66affSColin Finck list_add_head(&context->fbo_destroy_list, &entry->entry);
1071c2c66affSColin Finck }
1072c2c66affSColin Finck
context_resource_released(const struct wined3d_device * device,struct wined3d_resource * resource,enum wined3d_resource_type type)1073*81cffd76SJoachim Henze void context_resource_released(const struct wined3d_device *device,
1074*81cffd76SJoachim Henze struct wined3d_resource *resource, enum wined3d_resource_type type)
1075c2c66affSColin Finck {
1076*81cffd76SJoachim Henze struct wined3d_texture *texture;
1077*81cffd76SJoachim Henze UINT i;
1078c2c66affSColin Finck
1079c2c66affSColin Finck if (!device->d3d_initialized)
1080c2c66affSColin Finck return;
1081c2c66affSColin Finck
1082*81cffd76SJoachim Henze switch (type)
1083*81cffd76SJoachim Henze {
1084*81cffd76SJoachim Henze case WINED3D_RTYPE_TEXTURE_2D:
1085*81cffd76SJoachim Henze case WINED3D_RTYPE_TEXTURE_3D:
1086*81cffd76SJoachim Henze texture = texture_from_resource(resource);
1087*81cffd76SJoachim Henze
1088c2c66affSColin Finck for (i = 0; i < device->context_count; ++i)
1089c2c66affSColin Finck {
1090c2c66affSColin Finck struct wined3d_context *context = device->contexts[i];
1091*81cffd76SJoachim Henze if (context->current_rt.texture == texture)
1092c2c66affSColin Finck {
1093c2c66affSColin Finck context->current_rt.texture = NULL;
1094c2c66affSColin Finck context->current_rt.sub_resource_idx = 0;
1095c2c66affSColin Finck }
1096c2c66affSColin Finck }
1097*81cffd76SJoachim Henze break;
1098*81cffd76SJoachim Henze
1099*81cffd76SJoachim Henze default:
1100*81cffd76SJoachim Henze break;
1101*81cffd76SJoachim Henze }
1102c2c66affSColin Finck }
1103c2c66affSColin Finck
context_gl_resource_released(struct wined3d_device * device,GLuint name,BOOL rb_namespace)1104c2c66affSColin Finck void context_gl_resource_released(struct wined3d_device *device,
1105c2c66affSColin Finck GLuint name, BOOL rb_namespace)
1106c2c66affSColin Finck {
1107c2c66affSColin Finck context_enum_fbo_entries(device, name, rb_namespace, context_queue_fbo_entry_destruction);
1108c2c66affSColin Finck }
1109c2c66affSColin Finck
context_surface_update(struct wined3d_context * context,const struct wined3d_surface * surface)1110*81cffd76SJoachim Henze void context_surface_update(struct wined3d_context *context, const struct wined3d_surface *surface)
1111c2c66affSColin Finck {
1112c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
1113c2c66affSColin Finck struct fbo_entry *entry = context->current_fbo;
1114c2c66affSColin Finck unsigned int i;
1115c2c66affSColin Finck
1116c2c66affSColin Finck if (!entry || context->rebind_fbo) return;
1117c2c66affSColin Finck
1118c2c66affSColin Finck for (i = 0; i < gl_info->limits.buffers + 1; ++i)
1119c2c66affSColin Finck {
1120*81cffd76SJoachim Henze if (surface->container->texture_rgb.name == entry->key.objects[i].object
1121*81cffd76SJoachim Henze || surface->container->texture_srgb.name == entry->key.objects[i].object)
1122c2c66affSColin Finck {
1123*81cffd76SJoachim Henze TRACE("Updated surface %p is bound as attachment %u to the current FBO.\n", surface, i);
1124c2c66affSColin Finck context->rebind_fbo = TRUE;
1125c2c66affSColin Finck return;
1126c2c66affSColin Finck }
1127c2c66affSColin Finck }
1128c2c66affSColin Finck }
1129c2c66affSColin Finck
context_restore_pixel_format(struct wined3d_context * ctx)1130c2c66affSColin Finck static BOOL context_restore_pixel_format(struct wined3d_context *ctx)
1131c2c66affSColin Finck {
1132c2c66affSColin Finck const struct wined3d_gl_info *gl_info = ctx->gl_info;
1133c2c66affSColin Finck BOOL ret = FALSE;
1134c2c66affSColin Finck
1135c2c66affSColin Finck if (ctx->restore_pf && IsWindow(ctx->restore_pf_win))
1136c2c66affSColin Finck {
1137c2c66affSColin Finck if (ctx->gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
1138c2c66affSColin Finck {
1139c2c66affSColin Finck HDC dc = GetDCEx(ctx->restore_pf_win, 0, DCX_USESTYLE | DCX_CACHE);
1140c2c66affSColin Finck if (dc)
1141c2c66affSColin Finck {
1142c2c66affSColin Finck if (!(ret = GL_EXTCALL(wglSetPixelFormatWINE(dc, ctx->restore_pf))))
1143c2c66affSColin Finck {
1144c2c66affSColin Finck ERR("wglSetPixelFormatWINE failed to restore pixel format %d on window %p.\n",
1145c2c66affSColin Finck ctx->restore_pf, ctx->restore_pf_win);
1146c2c66affSColin Finck }
1147c2c66affSColin Finck ReleaseDC(ctx->restore_pf_win, dc);
1148c2c66affSColin Finck }
1149c2c66affSColin Finck }
1150c2c66affSColin Finck else
1151c2c66affSColin Finck {
1152c2c66affSColin Finck ERR("can't restore pixel format %d on window %p\n", ctx->restore_pf, ctx->restore_pf_win);
1153c2c66affSColin Finck }
1154c2c66affSColin Finck }
1155c2c66affSColin Finck
1156c2c66affSColin Finck ctx->restore_pf = 0;
1157c2c66affSColin Finck ctx->restore_pf_win = NULL;
1158c2c66affSColin Finck return ret;
1159c2c66affSColin Finck }
1160c2c66affSColin Finck
context_set_pixel_format(struct wined3d_context * context)1161c2c66affSColin Finck static BOOL context_set_pixel_format(struct wined3d_context *context)
1162c2c66affSColin Finck {
1163c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
1164c2c66affSColin Finck BOOL private = context->hdc_is_private;
1165c2c66affSColin Finck int format = context->pixel_format;
1166c2c66affSColin Finck HDC dc = context->hdc;
1167c2c66affSColin Finck int current;
1168c2c66affSColin Finck
1169c2c66affSColin Finck if (private && context->hdc_has_format)
1170c2c66affSColin Finck return TRUE;
1171c2c66affSColin Finck
1172c2c66affSColin Finck if (!private && WindowFromDC(dc) != context->win_handle)
1173c2c66affSColin Finck return FALSE;
1174c2c66affSColin Finck
1175c2c66affSColin Finck current = gl_info->gl_ops.wgl.p_wglGetPixelFormat(dc);
1176c2c66affSColin Finck if (current == format) goto success;
1177c2c66affSColin Finck
1178c2c66affSColin Finck if (!current)
1179c2c66affSColin Finck {
1180c2c66affSColin Finck if (!SetPixelFormat(dc, format, NULL))
1181c2c66affSColin Finck {
1182c2c66affSColin Finck /* This may also happen if the dc belongs to a destroyed window. */
1183c2c66affSColin Finck WARN("Failed to set pixel format %d on device context %p, last error %#x.\n",
1184c2c66affSColin Finck format, dc, GetLastError());
1185c2c66affSColin Finck return FALSE;
1186c2c66affSColin Finck }
1187c2c66affSColin Finck
1188c2c66affSColin Finck context->restore_pf = 0;
1189c2c66affSColin Finck context->restore_pf_win = private ? NULL : WindowFromDC(dc);
1190c2c66affSColin Finck goto success;
1191c2c66affSColin Finck }
1192c2c66affSColin Finck
1193c2c66affSColin Finck /* By default WGL doesn't allow pixel format adjustments but we need it
1194c2c66affSColin Finck * here. For this reason there's a Wine specific wglSetPixelFormat()
1195c2c66affSColin Finck * which allows us to set the pixel format multiple times. Only use it
1196c2c66affSColin Finck * when really needed. */
1197c2c66affSColin Finck if (gl_info->supported[WGL_WINE_PIXEL_FORMAT_PASSTHROUGH])
1198c2c66affSColin Finck {
1199c2c66affSColin Finck HWND win;
1200c2c66affSColin Finck
1201c2c66affSColin Finck if (!GL_EXTCALL(wglSetPixelFormatWINE(dc, format)))
1202c2c66affSColin Finck {
1203c2c66affSColin Finck ERR("wglSetPixelFormatWINE failed to set pixel format %d on device context %p.\n",
1204c2c66affSColin Finck format, dc);
1205c2c66affSColin Finck return FALSE;
1206c2c66affSColin Finck }
1207c2c66affSColin Finck
1208c2c66affSColin Finck win = private ? NULL : WindowFromDC(dc);
1209c2c66affSColin Finck if (win != context->restore_pf_win)
1210c2c66affSColin Finck {
1211c2c66affSColin Finck context_restore_pixel_format(context);
1212c2c66affSColin Finck
1213c2c66affSColin Finck context->restore_pf = private ? 0 : current;
1214c2c66affSColin Finck context->restore_pf_win = win;
1215c2c66affSColin Finck }
1216c2c66affSColin Finck
1217c2c66affSColin Finck goto success;
1218c2c66affSColin Finck }
1219c2c66affSColin Finck
1220c2c66affSColin Finck /* OpenGL doesn't allow pixel format adjustments. Print an error and
1221c2c66affSColin Finck * continue using the old format. There's a big chance that the old
1222c2c66affSColin Finck * format works although with a performance hit and perhaps rendering
1223c2c66affSColin Finck * errors. */
1224c2c66affSColin Finck ERR("Unable to set pixel format %d on device context %p. Already using format %d.\n",
1225c2c66affSColin Finck format, dc, current);
1226c2c66affSColin Finck return TRUE;
1227c2c66affSColin Finck
1228c2c66affSColin Finck success:
1229c2c66affSColin Finck if (private)
1230c2c66affSColin Finck context->hdc_has_format = TRUE;
1231c2c66affSColin Finck return TRUE;
1232c2c66affSColin Finck }
1233c2c66affSColin Finck
context_set_gl_context(struct wined3d_context * ctx)1234c2c66affSColin Finck static BOOL context_set_gl_context(struct wined3d_context *ctx)
1235c2c66affSColin Finck {
1236c2c66affSColin Finck struct wined3d_swapchain *swapchain = ctx->swapchain;
1237c2c66affSColin Finck BOOL backup = FALSE;
1238c2c66affSColin Finck
1239c2c66affSColin Finck if (!context_set_pixel_format(ctx))
1240c2c66affSColin Finck {
1241c2c66affSColin Finck WARN("Failed to set pixel format %d on device context %p.\n",
1242c2c66affSColin Finck ctx->pixel_format, ctx->hdc);
1243c2c66affSColin Finck backup = TRUE;
1244c2c66affSColin Finck }
1245c2c66affSColin Finck
1246c2c66affSColin Finck if (backup || !wglMakeCurrent(ctx->hdc, ctx->glCtx))
1247c2c66affSColin Finck {
1248c2c66affSColin Finck WARN("Failed to make GL context %p current on device context %p, last error %#x.\n",
1249c2c66affSColin Finck ctx->glCtx, ctx->hdc, GetLastError());
1250c2c66affSColin Finck ctx->valid = 0;
1251c2c66affSColin Finck WARN("Trying fallback to the backup window.\n");
1252c2c66affSColin Finck
1253c2c66affSColin Finck /* FIXME: If the context is destroyed it's no longer associated with
1254c2c66affSColin Finck * a swapchain, so we can't use the swapchain to get a backup dc. To
1255c2c66affSColin Finck * make this work windowless contexts would need to be handled by the
1256c2c66affSColin Finck * device. */
1257c2c66affSColin Finck if (ctx->destroyed || !swapchain)
1258c2c66affSColin Finck {
1259c2c66affSColin Finck FIXME("Unable to get backup dc for destroyed context %p.\n", ctx);
1260c2c66affSColin Finck context_set_current(NULL);
1261c2c66affSColin Finck return FALSE;
1262c2c66affSColin Finck }
1263c2c66affSColin Finck
1264c2c66affSColin Finck if (!(ctx->hdc = swapchain_get_backup_dc(swapchain)))
1265c2c66affSColin Finck {
1266c2c66affSColin Finck context_set_current(NULL);
1267c2c66affSColin Finck return FALSE;
1268c2c66affSColin Finck }
1269c2c66affSColin Finck
1270c2c66affSColin Finck ctx->hdc_is_private = TRUE;
1271c2c66affSColin Finck ctx->hdc_has_format = FALSE;
1272c2c66affSColin Finck
1273c2c66affSColin Finck if (!context_set_pixel_format(ctx))
1274c2c66affSColin Finck {
1275c2c66affSColin Finck ERR("Failed to set pixel format %d on device context %p.\n",
1276c2c66affSColin Finck ctx->pixel_format, ctx->hdc);
1277c2c66affSColin Finck context_set_current(NULL);
1278c2c66affSColin Finck return FALSE;
1279c2c66affSColin Finck }
1280c2c66affSColin Finck
1281c2c66affSColin Finck if (!wglMakeCurrent(ctx->hdc, ctx->glCtx))
1282c2c66affSColin Finck {
1283c2c66affSColin Finck ERR("Fallback to backup window (dc %p) failed too, last error %#x.\n",
1284c2c66affSColin Finck ctx->hdc, GetLastError());
1285c2c66affSColin Finck context_set_current(NULL);
1286c2c66affSColin Finck return FALSE;
1287c2c66affSColin Finck }
1288c2c66affSColin Finck
1289c2c66affSColin Finck ctx->valid = 1;
1290c2c66affSColin Finck }
1291c2c66affSColin Finck ctx->needs_set = 0;
1292c2c66affSColin Finck return TRUE;
1293c2c66affSColin Finck }
1294c2c66affSColin Finck
context_restore_gl_context(const struct wined3d_gl_info * gl_info,HDC dc,HGLRC gl_ctx)1295c2c66affSColin Finck static void context_restore_gl_context(const struct wined3d_gl_info *gl_info, HDC dc, HGLRC gl_ctx)
1296c2c66affSColin Finck {
1297c2c66affSColin Finck if (!wglMakeCurrent(dc, gl_ctx))
1298c2c66affSColin Finck {
1299c2c66affSColin Finck ERR("Failed to restore GL context %p on device context %p, last error %#x.\n",
1300c2c66affSColin Finck gl_ctx, dc, GetLastError());
1301c2c66affSColin Finck context_set_current(NULL);
1302c2c66affSColin Finck }
1303c2c66affSColin Finck }
1304c2c66affSColin Finck
context_update_window(struct wined3d_context * context)1305c2c66affSColin Finck static void context_update_window(struct wined3d_context *context)
1306c2c66affSColin Finck {
1307c2c66affSColin Finck if (!context->swapchain)
1308c2c66affSColin Finck return;
1309c2c66affSColin Finck
1310c2c66affSColin Finck if (context->win_handle == context->swapchain->win_handle)
1311c2c66affSColin Finck return;
1312c2c66affSColin Finck
1313c2c66affSColin Finck TRACE("Updating context %p window from %p to %p.\n",
1314c2c66affSColin Finck context, context->win_handle, context->swapchain->win_handle);
1315c2c66affSColin Finck
1316c2c66affSColin Finck if (context->hdc)
1317c2c66affSColin Finck wined3d_release_dc(context->win_handle, context->hdc);
1318c2c66affSColin Finck
1319c2c66affSColin Finck context->win_handle = context->swapchain->win_handle;
1320c2c66affSColin Finck context->hdc_is_private = FALSE;
1321c2c66affSColin Finck context->hdc_has_format = FALSE;
1322c2c66affSColin Finck context->needs_set = 1;
1323c2c66affSColin Finck context->valid = 1;
1324c2c66affSColin Finck
1325c2c66affSColin Finck if (!(context->hdc = GetDCEx(context->win_handle, 0, DCX_USESTYLE | DCX_CACHE)))
1326c2c66affSColin Finck {
1327c2c66affSColin Finck ERR("Failed to get a device context for window %p.\n", context->win_handle);
1328c2c66affSColin Finck context->valid = 0;
1329c2c66affSColin Finck }
1330c2c66affSColin Finck }
1331c2c66affSColin Finck
context_destroy_gl_resources(struct wined3d_context * context)1332c2c66affSColin Finck static void context_destroy_gl_resources(struct wined3d_context *context)
1333c2c66affSColin Finck {
1334c2c66affSColin Finck struct wined3d_pipeline_statistics_query *pipeline_statistics_query;
1335c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
1336c2c66affSColin Finck struct wined3d_so_statistics_query *so_statistics_query;
1337c2c66affSColin Finck struct wined3d_timestamp_query *timestamp_query;
1338c2c66affSColin Finck struct wined3d_occlusion_query *occlusion_query;
1339c2c66affSColin Finck struct fbo_entry *entry, *entry2;
1340c2c66affSColin Finck struct wined3d_fence *fence;
1341c2c66affSColin Finck HGLRC restore_ctx;
1342c2c66affSColin Finck HDC restore_dc;
1343c2c66affSColin Finck unsigned int i;
1344c2c66affSColin Finck
1345c2c66affSColin Finck restore_ctx = wglGetCurrentContext();
1346c2c66affSColin Finck restore_dc = wglGetCurrentDC();
1347c2c66affSColin Finck
1348c2c66affSColin Finck if (restore_ctx == context->glCtx)
1349c2c66affSColin Finck restore_ctx = NULL;
1350c2c66affSColin Finck else if (context->valid)
1351c2c66affSColin Finck context_set_gl_context(context);
1352c2c66affSColin Finck
1353c2c66affSColin Finck LIST_FOR_EACH_ENTRY(so_statistics_query, &context->so_statistics_queries,
1354c2c66affSColin Finck struct wined3d_so_statistics_query, entry)
1355c2c66affSColin Finck {
1356c2c66affSColin Finck if (context->valid)
1357c2c66affSColin Finck GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(so_statistics_query->u.id), so_statistics_query->u.id));
1358c2c66affSColin Finck so_statistics_query->context = NULL;
1359c2c66affSColin Finck }
1360c2c66affSColin Finck
1361c2c66affSColin Finck LIST_FOR_EACH_ENTRY(pipeline_statistics_query, &context->pipeline_statistics_queries,
1362c2c66affSColin Finck struct wined3d_pipeline_statistics_query, entry)
1363c2c66affSColin Finck {
1364c2c66affSColin Finck if (context->valid)
1365c2c66affSColin Finck GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(pipeline_statistics_query->u.id), pipeline_statistics_query->u.id));
1366c2c66affSColin Finck pipeline_statistics_query->context = NULL;
1367c2c66affSColin Finck }
1368c2c66affSColin Finck
1369c2c66affSColin Finck LIST_FOR_EACH_ENTRY(timestamp_query, &context->timestamp_queries, struct wined3d_timestamp_query, entry)
1370c2c66affSColin Finck {
1371c2c66affSColin Finck if (context->valid)
1372c2c66affSColin Finck GL_EXTCALL(glDeleteQueries(1, ×tamp_query->id));
1373c2c66affSColin Finck timestamp_query->context = NULL;
1374c2c66affSColin Finck }
1375c2c66affSColin Finck
1376c2c66affSColin Finck LIST_FOR_EACH_ENTRY(occlusion_query, &context->occlusion_queries, struct wined3d_occlusion_query, entry)
1377c2c66affSColin Finck {
1378c2c66affSColin Finck if (context->valid && gl_info->supported[ARB_OCCLUSION_QUERY])
1379c2c66affSColin Finck GL_EXTCALL(glDeleteQueries(1, &occlusion_query->id));
1380c2c66affSColin Finck occlusion_query->context = NULL;
1381c2c66affSColin Finck }
1382c2c66affSColin Finck
1383c2c66affSColin Finck LIST_FOR_EACH_ENTRY(fence, &context->fences, struct wined3d_fence, entry)
1384c2c66affSColin Finck {
1385c2c66affSColin Finck if (context->valid)
1386c2c66affSColin Finck {
1387c2c66affSColin Finck if (gl_info->supported[ARB_SYNC])
1388c2c66affSColin Finck {
1389c2c66affSColin Finck if (fence->object.sync)
1390c2c66affSColin Finck GL_EXTCALL(glDeleteSync(fence->object.sync));
1391c2c66affSColin Finck }
1392c2c66affSColin Finck else if (gl_info->supported[APPLE_FENCE])
1393c2c66affSColin Finck {
1394c2c66affSColin Finck GL_EXTCALL(glDeleteFencesAPPLE(1, &fence->object.id));
1395c2c66affSColin Finck }
1396c2c66affSColin Finck else if (gl_info->supported[NV_FENCE])
1397c2c66affSColin Finck {
1398c2c66affSColin Finck GL_EXTCALL(glDeleteFencesNV(1, &fence->object.id));
1399c2c66affSColin Finck }
1400c2c66affSColin Finck }
1401c2c66affSColin Finck fence->context = NULL;
1402c2c66affSColin Finck }
1403c2c66affSColin Finck
1404c2c66affSColin Finck LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_destroy_list, struct fbo_entry, entry)
1405c2c66affSColin Finck {
1406c2c66affSColin Finck if (!context->valid) entry->id = 0;
1407c2c66affSColin Finck context_destroy_fbo_entry(context, entry);
1408c2c66affSColin Finck }
1409c2c66affSColin Finck
1410c2c66affSColin Finck LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &context->fbo_list, struct fbo_entry, entry)
1411c2c66affSColin Finck {
1412c2c66affSColin Finck if (!context->valid) entry->id = 0;
1413c2c66affSColin Finck context_destroy_fbo_entry(context, entry);
1414c2c66affSColin Finck }
1415c2c66affSColin Finck
1416c2c66affSColin Finck if (context->valid)
1417c2c66affSColin Finck {
1418c2c66affSColin Finck if (context->dummy_arbfp_prog)
1419c2c66affSColin Finck {
1420c2c66affSColin Finck GL_EXTCALL(glDeleteProgramsARB(1, &context->dummy_arbfp_prog));
1421c2c66affSColin Finck }
1422c2c66affSColin Finck
1423c2c66affSColin Finck if (gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1424c2c66affSColin Finck {
1425c2c66affSColin Finck for (i = 0; i < context->free_so_statistics_query_count; ++i)
1426c2c66affSColin Finck {
1427c2c66affSColin Finck union wined3d_gl_so_statistics_query *q = &context->free_so_statistics_queries[i];
1428c2c66affSColin Finck GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(q->id), q->id));
1429c2c66affSColin Finck }
1430c2c66affSColin Finck }
1431c2c66affSColin Finck
1432c2c66affSColin Finck if (gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1433c2c66affSColin Finck {
1434c2c66affSColin Finck for (i = 0; i < context->free_pipeline_statistics_query_count; ++i)
1435c2c66affSColin Finck {
1436c2c66affSColin Finck union wined3d_gl_pipeline_statistics_query *q = &context->free_pipeline_statistics_queries[i];
1437c2c66affSColin Finck GL_EXTCALL(glDeleteQueries(ARRAY_SIZE(q->id), q->id));
1438c2c66affSColin Finck }
1439c2c66affSColin Finck }
1440c2c66affSColin Finck
1441c2c66affSColin Finck if (gl_info->supported[ARB_TIMER_QUERY])
1442c2c66affSColin Finck GL_EXTCALL(glDeleteQueries(context->free_timestamp_query_count, context->free_timestamp_queries));
1443c2c66affSColin Finck
1444c2c66affSColin Finck if (gl_info->supported[ARB_OCCLUSION_QUERY])
1445c2c66affSColin Finck GL_EXTCALL(glDeleteQueries(context->free_occlusion_query_count, context->free_occlusion_queries));
1446c2c66affSColin Finck
1447c2c66affSColin Finck if (gl_info->supported[ARB_SYNC])
1448c2c66affSColin Finck {
1449c2c66affSColin Finck for (i = 0; i < context->free_fence_count; ++i)
1450c2c66affSColin Finck {
1451c2c66affSColin Finck GL_EXTCALL(glDeleteSync(context->free_fences[i].sync));
1452c2c66affSColin Finck }
1453c2c66affSColin Finck }
1454c2c66affSColin Finck else if (gl_info->supported[APPLE_FENCE])
1455c2c66affSColin Finck {
1456c2c66affSColin Finck for (i = 0; i < context->free_fence_count; ++i)
1457c2c66affSColin Finck {
1458c2c66affSColin Finck GL_EXTCALL(glDeleteFencesAPPLE(1, &context->free_fences[i].id));
1459c2c66affSColin Finck }
1460c2c66affSColin Finck }
1461c2c66affSColin Finck else if (gl_info->supported[NV_FENCE])
1462c2c66affSColin Finck {
1463c2c66affSColin Finck for (i = 0; i < context->free_fence_count; ++i)
1464c2c66affSColin Finck {
1465c2c66affSColin Finck GL_EXTCALL(glDeleteFencesNV(1, &context->free_fences[i].id));
1466c2c66affSColin Finck }
1467c2c66affSColin Finck }
1468c2c66affSColin Finck
1469c2c66affSColin Finck checkGLcall("context cleanup");
1470c2c66affSColin Finck }
1471c2c66affSColin Finck
14729987f029SAmine Khaldi heap_free(context->free_so_statistics_queries);
14739987f029SAmine Khaldi heap_free(context->free_pipeline_statistics_queries);
14749987f029SAmine Khaldi heap_free(context->free_timestamp_queries);
14759987f029SAmine Khaldi heap_free(context->free_occlusion_queries);
14769987f029SAmine Khaldi heap_free(context->free_fences);
1477c2c66affSColin Finck
1478c2c66affSColin Finck context_restore_pixel_format(context);
1479c2c66affSColin Finck if (restore_ctx)
1480c2c66affSColin Finck {
1481c2c66affSColin Finck context_restore_gl_context(gl_info, restore_dc, restore_ctx);
1482c2c66affSColin Finck }
1483c2c66affSColin Finck else if (wglGetCurrentContext() && !wglMakeCurrent(NULL, NULL))
1484c2c66affSColin Finck {
1485c2c66affSColin Finck ERR("Failed to disable GL context.\n");
1486c2c66affSColin Finck }
1487c2c66affSColin Finck
1488c2c66affSColin Finck wined3d_release_dc(context->win_handle, context->hdc);
1489c2c66affSColin Finck
1490c2c66affSColin Finck if (!wglDeleteContext(context->glCtx))
1491c2c66affSColin Finck {
1492c2c66affSColin Finck DWORD err = GetLastError();
1493c2c66affSColin Finck ERR("wglDeleteContext(%p) failed, last error %#x.\n", context->glCtx, err);
1494c2c66affSColin Finck }
1495c2c66affSColin Finck }
1496c2c66affSColin Finck
context_get_tls_idx(void)1497c2c66affSColin Finck DWORD context_get_tls_idx(void)
1498c2c66affSColin Finck {
1499c2c66affSColin Finck return wined3d_context_tls_idx;
1500c2c66affSColin Finck }
1501c2c66affSColin Finck
context_set_tls_idx(DWORD idx)1502c2c66affSColin Finck void context_set_tls_idx(DWORD idx)
1503c2c66affSColin Finck {
1504c2c66affSColin Finck wined3d_context_tls_idx = idx;
1505c2c66affSColin Finck }
1506c2c66affSColin Finck
context_get_current(void)1507c2c66affSColin Finck struct wined3d_context *context_get_current(void)
1508c2c66affSColin Finck {
1509c2c66affSColin Finck return TlsGetValue(wined3d_context_tls_idx);
1510c2c66affSColin Finck }
1511c2c66affSColin Finck
context_set_current(struct wined3d_context * ctx)1512c2c66affSColin Finck BOOL context_set_current(struct wined3d_context *ctx)
1513c2c66affSColin Finck {
1514c2c66affSColin Finck struct wined3d_context *old = context_get_current();
1515c2c66affSColin Finck
1516c2c66affSColin Finck if (old == ctx)
1517c2c66affSColin Finck {
1518c2c66affSColin Finck TRACE("Already using D3D context %p.\n", ctx);
1519c2c66affSColin Finck return TRUE;
1520c2c66affSColin Finck }
1521c2c66affSColin Finck
1522c2c66affSColin Finck if (old)
1523c2c66affSColin Finck {
1524c2c66affSColin Finck if (old->destroyed)
1525c2c66affSColin Finck {
1526c2c66affSColin Finck TRACE("Switching away from destroyed context %p.\n", old);
1527c2c66affSColin Finck context_destroy_gl_resources(old);
15289987f029SAmine Khaldi heap_free((void *)old->gl_info);
15299987f029SAmine Khaldi heap_free(old);
1530c2c66affSColin Finck }
1531c2c66affSColin Finck else
1532c2c66affSColin Finck {
1533c2c66affSColin Finck if (wglGetCurrentContext())
1534c2c66affSColin Finck {
1535c2c66affSColin Finck const struct wined3d_gl_info *gl_info = old->gl_info;
1536c2c66affSColin Finck TRACE("Flushing context %p before switching to %p.\n", old, ctx);
1537c2c66affSColin Finck gl_info->gl_ops.gl.p_glFlush();
1538c2c66affSColin Finck }
1539c2c66affSColin Finck old->current = 0;
1540c2c66affSColin Finck }
1541c2c66affSColin Finck }
1542c2c66affSColin Finck
1543c2c66affSColin Finck if (ctx)
1544c2c66affSColin Finck {
1545c2c66affSColin Finck if (!ctx->valid)
1546c2c66affSColin Finck {
1547c2c66affSColin Finck ERR("Trying to make invalid context %p current\n", ctx);
1548c2c66affSColin Finck return FALSE;
1549c2c66affSColin Finck }
1550c2c66affSColin Finck
1551c2c66affSColin Finck TRACE("Switching to D3D context %p, GL context %p, device context %p.\n", ctx, ctx->glCtx, ctx->hdc);
1552c2c66affSColin Finck if (!context_set_gl_context(ctx))
1553c2c66affSColin Finck return FALSE;
1554c2c66affSColin Finck ctx->current = 1;
1555c2c66affSColin Finck }
1556c2c66affSColin Finck else if (wglGetCurrentContext())
1557c2c66affSColin Finck {
1558c2c66affSColin Finck TRACE("Clearing current D3D context.\n");
1559c2c66affSColin Finck if (!wglMakeCurrent(NULL, NULL))
1560c2c66affSColin Finck {
1561c2c66affSColin Finck DWORD err = GetLastError();
1562c2c66affSColin Finck ERR("Failed to clear current GL context, last error %#x.\n", err);
1563c2c66affSColin Finck TlsSetValue(wined3d_context_tls_idx, NULL);
1564c2c66affSColin Finck return FALSE;
1565c2c66affSColin Finck }
1566c2c66affSColin Finck }
1567c2c66affSColin Finck
1568c2c66affSColin Finck return TlsSetValue(wined3d_context_tls_idx, ctx);
1569c2c66affSColin Finck }
1570c2c66affSColin Finck
context_release(struct wined3d_context * context)1571c2c66affSColin Finck void context_release(struct wined3d_context *context)
1572c2c66affSColin Finck {
1573c2c66affSColin Finck TRACE("Releasing context %p, level %u.\n", context, context->level);
1574c2c66affSColin Finck
1575c2c66affSColin Finck if (WARN_ON(d3d))
1576c2c66affSColin Finck {
1577c2c66affSColin Finck if (!context->level)
1578c2c66affSColin Finck WARN("Context %p is not active.\n", context);
1579c2c66affSColin Finck else if (context != context_get_current())
1580c2c66affSColin Finck WARN("Context %p is not the current context.\n", context);
1581c2c66affSColin Finck }
1582c2c66affSColin Finck
1583c2c66affSColin Finck if (!--context->level)
1584c2c66affSColin Finck {
1585c2c66affSColin Finck if (context_restore_pixel_format(context))
1586c2c66affSColin Finck context->needs_set = 1;
1587c2c66affSColin Finck if (context->restore_ctx)
1588c2c66affSColin Finck {
1589c2c66affSColin Finck TRACE("Restoring GL context %p on device context %p.\n", context->restore_ctx, context->restore_dc);
1590c2c66affSColin Finck context_restore_gl_context(context->gl_info, context->restore_dc, context->restore_ctx);
1591c2c66affSColin Finck context->restore_ctx = NULL;
1592c2c66affSColin Finck context->restore_dc = NULL;
1593c2c66affSColin Finck }
1594c2c66affSColin Finck
1595c2c66affSColin Finck if (context->destroy_delayed)
1596c2c66affSColin Finck {
1597c2c66affSColin Finck TRACE("Destroying context %p.\n", context);
1598c2c66affSColin Finck context_destroy(context->device, context);
1599c2c66affSColin Finck }
1600c2c66affSColin Finck }
1601c2c66affSColin Finck }
1602c2c66affSColin Finck
1603c2c66affSColin Finck /* This is used when a context for render target A is active, but a separate context is
1604c2c66affSColin Finck * needed to access the WGL framebuffer for render target B. Re-acquire a context for rt
1605c2c66affSColin Finck * A to avoid breaking caller code. */
context_restore(struct wined3d_context * context,struct wined3d_surface * restore)1606*81cffd76SJoachim Henze void context_restore(struct wined3d_context *context, struct wined3d_surface *restore)
1607c2c66affSColin Finck {
1608*81cffd76SJoachim Henze if (context->current_rt.texture != restore->container
1609*81cffd76SJoachim Henze || context->current_rt.sub_resource_idx != surface_get_sub_resource_idx(restore))
1610c2c66affSColin Finck {
1611c2c66affSColin Finck context_release(context);
1612*81cffd76SJoachim Henze context = context_acquire(restore->container->resource.device,
1613*81cffd76SJoachim Henze restore->container, surface_get_sub_resource_idx(restore));
1614c2c66affSColin Finck }
1615c2c66affSColin Finck
1616c2c66affSColin Finck context_release(context);
1617c2c66affSColin Finck }
1618c2c66affSColin Finck
context_enter(struct wined3d_context * context)1619c2c66affSColin Finck static void context_enter(struct wined3d_context *context)
1620c2c66affSColin Finck {
1621c2c66affSColin Finck TRACE("Entering context %p, level %u.\n", context, context->level + 1);
1622c2c66affSColin Finck
1623c2c66affSColin Finck if (!context->level++)
1624c2c66affSColin Finck {
1625c2c66affSColin Finck const struct wined3d_context *current_context = context_get_current();
1626c2c66affSColin Finck HGLRC current_gl = wglGetCurrentContext();
1627c2c66affSColin Finck
1628c2c66affSColin Finck if (current_gl && (!current_context || current_context->glCtx != current_gl))
1629c2c66affSColin Finck {
1630c2c66affSColin Finck TRACE("Another GL context (%p on device context %p) is already current.\n",
1631c2c66affSColin Finck current_gl, wglGetCurrentDC());
1632c2c66affSColin Finck context->restore_ctx = current_gl;
1633c2c66affSColin Finck context->restore_dc = wglGetCurrentDC();
1634c2c66affSColin Finck context->needs_set = 1;
1635c2c66affSColin Finck }
1636c2c66affSColin Finck else if (!context->needs_set && !(context->hdc_is_private && context->hdc_has_format)
1637c2c66affSColin Finck && context->pixel_format != context->gl_info->gl_ops.wgl.p_wglGetPixelFormat(context->hdc))
1638c2c66affSColin Finck context->needs_set = 1;
1639c2c66affSColin Finck }
1640c2c66affSColin Finck }
1641c2c66affSColin Finck
context_invalidate_compute_state(struct wined3d_context * context,DWORD state_id)1642c2c66affSColin Finck void context_invalidate_compute_state(struct wined3d_context *context, DWORD state_id)
1643c2c66affSColin Finck {
1644c2c66affSColin Finck DWORD representative = context->state_table[state_id].representative - STATE_COMPUTE_OFFSET;
1645c2c66affSColin Finck unsigned int index, shift;
1646c2c66affSColin Finck
1647c2c66affSColin Finck index = representative / (sizeof(*context->dirty_compute_states) * CHAR_BIT);
1648c2c66affSColin Finck shift = representative & (sizeof(*context->dirty_compute_states) * CHAR_BIT - 1);
1649c2c66affSColin Finck context->dirty_compute_states[index] |= (1u << shift);
1650c2c66affSColin Finck }
1651c2c66affSColin Finck
context_invalidate_state(struct wined3d_context * context,DWORD state)1652c2c66affSColin Finck void context_invalidate_state(struct wined3d_context *context, DWORD state)
1653c2c66affSColin Finck {
1654c2c66affSColin Finck DWORD rep = context->state_table[state].representative;
1655c2c66affSColin Finck DWORD idx;
1656c2c66affSColin Finck BYTE shift;
1657c2c66affSColin Finck
1658c2c66affSColin Finck if (isStateDirty(context, rep)) return;
1659c2c66affSColin Finck
1660c2c66affSColin Finck context->dirtyArray[context->numDirtyEntries++] = rep;
1661c2c66affSColin Finck idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
1662c2c66affSColin Finck shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
1663c2c66affSColin Finck context->isStateDirty[idx] |= (1u << shift);
1664c2c66affSColin Finck }
1665c2c66affSColin Finck
1666c2c66affSColin Finck /* 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)1667c2c66affSColin Finck static int context_choose_pixel_format(const struct wined3d_device *device, HDC hdc,
1668c2c66affSColin Finck const struct wined3d_format *color_format, const struct wined3d_format *ds_format,
1669c2c66affSColin Finck BOOL auxBuffers)
1670c2c66affSColin Finck {
1671c2c66affSColin Finck unsigned int cfg_count = device->adapter->cfg_count;
1672c2c66affSColin Finck unsigned int current_value;
1673c2c66affSColin Finck PIXELFORMATDESCRIPTOR pfd;
1674c2c66affSColin Finck int iPixelFormat = 0;
1675c2c66affSColin Finck unsigned int i;
1676c2c66affSColin Finck
1677c2c66affSColin Finck TRACE("device %p, dc %p, color_format %s, ds_format %s, aux_buffers %#x.\n",
1678c2c66affSColin Finck device, hdc, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id),
1679c2c66affSColin Finck auxBuffers);
1680c2c66affSColin Finck
1681c2c66affSColin Finck current_value = 0;
1682c2c66affSColin Finck for (i = 0; i < cfg_count; ++i)
1683c2c66affSColin Finck {
1684c2c66affSColin Finck const struct wined3d_pixel_format *cfg = &device->adapter->cfgs[i];
1685c2c66affSColin Finck unsigned int value;
1686c2c66affSColin Finck
1687c2c66affSColin Finck /* For now only accept RGBA formats. Perhaps some day we will
1688c2c66affSColin Finck * allow floating point formats for pbuffers. */
1689c2c66affSColin Finck if (cfg->iPixelType != WGL_TYPE_RGBA_ARB)
1690c2c66affSColin Finck continue;
1691c2c66affSColin Finck /* In window mode we need a window drawable format and double buffering. */
1692c2c66affSColin Finck if (!(cfg->windowDrawable && cfg->doubleBuffer))
1693c2c66affSColin Finck continue;
1694c2c66affSColin Finck if (cfg->redSize < color_format->red_size)
1695c2c66affSColin Finck continue;
1696c2c66affSColin Finck if (cfg->greenSize < color_format->green_size)
1697c2c66affSColin Finck continue;
1698c2c66affSColin Finck if (cfg->blueSize < color_format->blue_size)
1699c2c66affSColin Finck continue;
1700c2c66affSColin Finck if (cfg->alphaSize < color_format->alpha_size)
1701c2c66affSColin Finck continue;
1702c2c66affSColin Finck if (cfg->depthSize < ds_format->depth_size)
1703c2c66affSColin Finck continue;
1704c2c66affSColin Finck if (ds_format->stencil_size && cfg->stencilSize != ds_format->stencil_size)
1705c2c66affSColin Finck continue;
1706c2c66affSColin Finck /* Check multisampling support. */
1707c2c66affSColin Finck if (cfg->numSamples)
1708c2c66affSColin Finck continue;
1709c2c66affSColin Finck
1710c2c66affSColin Finck value = 1;
1711c2c66affSColin Finck /* We try to locate a format which matches our requirements exactly. In case of
1712c2c66affSColin Finck * depth it is no problem to emulate 16-bit using e.g. 24-bit, so accept that. */
1713c2c66affSColin Finck if (cfg->depthSize == ds_format->depth_size)
1714c2c66affSColin Finck value += 1;
1715c2c66affSColin Finck if (cfg->stencilSize == ds_format->stencil_size)
1716c2c66affSColin Finck value += 2;
1717c2c66affSColin Finck if (cfg->alphaSize == color_format->alpha_size)
1718c2c66affSColin Finck value += 4;
1719c2c66affSColin Finck /* We like to have aux buffers in backbuffer mode */
1720c2c66affSColin Finck if (auxBuffers && cfg->auxBuffers)
1721c2c66affSColin Finck value += 8;
1722c2c66affSColin Finck if (cfg->redSize == color_format->red_size
1723c2c66affSColin Finck && cfg->greenSize == color_format->green_size
1724c2c66affSColin Finck && cfg->blueSize == color_format->blue_size)
1725c2c66affSColin Finck value += 16;
1726c2c66affSColin Finck
1727c2c66affSColin Finck if (value > current_value)
1728c2c66affSColin Finck {
1729c2c66affSColin Finck iPixelFormat = cfg->iPixelFormat;
1730c2c66affSColin Finck current_value = value;
1731c2c66affSColin Finck }
1732c2c66affSColin Finck }
1733c2c66affSColin Finck
1734c2c66affSColin Finck if (!iPixelFormat)
1735c2c66affSColin Finck {
1736c2c66affSColin Finck ERR("Trying to locate a compatible pixel format because an exact match failed.\n");
1737c2c66affSColin Finck
1738c2c66affSColin Finck memset(&pfd, 0, sizeof(pfd));
1739c2c66affSColin Finck pfd.nSize = sizeof(pfd);
1740c2c66affSColin Finck pfd.nVersion = 1;
1741c2c66affSColin Finck pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/
1742c2c66affSColin Finck pfd.iPixelType = PFD_TYPE_RGBA;
1743c2c66affSColin Finck pfd.cAlphaBits = color_format->alpha_size;
1744c2c66affSColin Finck pfd.cColorBits = color_format->red_size + color_format->green_size
1745c2c66affSColin Finck + color_format->blue_size + color_format->alpha_size;
1746c2c66affSColin Finck pfd.cDepthBits = ds_format->depth_size;
1747c2c66affSColin Finck pfd.cStencilBits = ds_format->stencil_size;
1748c2c66affSColin Finck pfd.iLayerType = PFD_MAIN_PLANE;
1749c2c66affSColin Finck
1750c2c66affSColin Finck if (!(iPixelFormat = ChoosePixelFormat(hdc, &pfd)))
1751c2c66affSColin Finck {
1752c2c66affSColin Finck /* Something is very wrong as ChoosePixelFormat() barely fails. */
1753c2c66affSColin Finck ERR("Can't find a suitable pixel format.\n");
1754c2c66affSColin Finck return 0;
1755c2c66affSColin Finck }
1756c2c66affSColin Finck }
1757c2c66affSColin Finck
1758c2c66affSColin Finck TRACE("Found iPixelFormat=%d for ColorFormat=%s, DepthStencilFormat=%s.\n",
1759c2c66affSColin Finck iPixelFormat, debug_d3dformat(color_format->id), debug_d3dformat(ds_format->id));
1760c2c66affSColin Finck return iPixelFormat;
1761c2c66affSColin Finck }
1762c2c66affSColin Finck
1763c2c66affSColin Finck /* Context activation is done by the caller. */
context_bind_dummy_textures(const struct wined3d_device * device,const struct wined3d_context * context)1764c2c66affSColin Finck void context_bind_dummy_textures(const struct wined3d_device *device, const struct wined3d_context *context)
1765c2c66affSColin Finck {
17669987f029SAmine Khaldi const struct wined3d_dummy_textures *textures = &context->device->dummy_textures;
1767c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
1768c2c66affSColin Finck unsigned int i;
1769c2c66affSColin Finck
1770c2c66affSColin Finck for (i = 0; i < gl_info->limits.combined_samplers; ++i)
1771c2c66affSColin Finck {
1772c2c66affSColin Finck GL_EXTCALL(glActiveTexture(GL_TEXTURE0 + i));
1773c2c66affSColin Finck
17749987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, textures->tex_1d);
17759987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, textures->tex_2d);
1776c2c66affSColin Finck
1777c2c66affSColin Finck if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
17789987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textures->tex_rect);
1779c2c66affSColin Finck
1780c2c66affSColin Finck if (gl_info->supported[EXT_TEXTURE3D])
17819987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, textures->tex_3d);
1782c2c66affSColin Finck
1783c2c66affSColin Finck if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
17849987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, textures->tex_cube);
1785c2c66affSColin Finck
1786c2c66affSColin Finck if (gl_info->supported[ARB_TEXTURE_CUBE_MAP_ARRAY])
17879987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, textures->tex_cube_array);
1788c2c66affSColin Finck
1789c2c66affSColin Finck if (gl_info->supported[EXT_TEXTURE_ARRAY])
17909987f029SAmine Khaldi {
17919987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D_ARRAY, textures->tex_1d_array);
17929987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_ARRAY, textures->tex_2d_array);
1793c2c66affSColin Finck }
17949987f029SAmine Khaldi if (gl_info->supported[ARB_TEXTURE_BUFFER_OBJECT])
17959987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_BUFFER, textures->tex_buffer);
17969987f029SAmine Khaldi
17979987f029SAmine Khaldi if (gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
17989987f029SAmine Khaldi {
17999987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textures->tex_2d_ms);
18009987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, textures->tex_2d_ms_array);
18019987f029SAmine Khaldi }
18029987f029SAmine Khaldi }
18039987f029SAmine Khaldi
18049987f029SAmine Khaldi checkGLcall("bind dummy textures");
1805c2c66affSColin Finck }
1806c2c66affSColin Finck
wined3d_check_gl_call(const struct wined3d_gl_info * gl_info,const char * file,unsigned int line,const char * name)1807c2c66affSColin Finck void wined3d_check_gl_call(const struct wined3d_gl_info *gl_info,
1808c2c66affSColin Finck const char *file, unsigned int line, const char *name)
1809c2c66affSColin Finck {
1810c2c66affSColin Finck GLint err;
1811c2c66affSColin Finck
1812c2c66affSColin Finck if (gl_info->supported[ARB_DEBUG_OUTPUT] || (err = gl_info->gl_ops.gl.p_glGetError()) == GL_NO_ERROR)
1813c2c66affSColin Finck {
1814c2c66affSColin Finck TRACE("%s call ok %s / %u.\n", name, file, line);
1815c2c66affSColin Finck return;
1816c2c66affSColin Finck }
1817c2c66affSColin Finck
1818c2c66affSColin Finck do
1819c2c66affSColin Finck {
1820c2c66affSColin Finck ERR(">>>>>>> %s (%#x) from %s @ %s / %u.\n",
1821c2c66affSColin Finck debug_glerror(err), err, name, file,line);
1822c2c66affSColin Finck err = gl_info->gl_ops.gl.p_glGetError();
1823c2c66affSColin Finck } while (err != GL_NO_ERROR);
1824c2c66affSColin Finck }
1825c2c66affSColin Finck
context_debug_output_enabled(const struct wined3d_gl_info * gl_info)1826c2c66affSColin Finck static BOOL context_debug_output_enabled(const struct wined3d_gl_info *gl_info)
1827c2c66affSColin Finck {
1828c2c66affSColin Finck return gl_info->supported[ARB_DEBUG_OUTPUT]
1829c2c66affSColin Finck && (ERR_ON(d3d) || FIXME_ON(d3d) || WARN_ON(d3d_perf));
1830c2c66affSColin Finck }
1831c2c66affSColin Finck
wined3d_debug_callback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const char * message,void * ctx)1832c2c66affSColin Finck static void WINE_GLAPI wined3d_debug_callback(GLenum source, GLenum type, GLuint id,
1833c2c66affSColin Finck GLenum severity, GLsizei length, const char *message, void *ctx)
1834c2c66affSColin Finck {
1835c2c66affSColin Finck switch (type)
1836c2c66affSColin Finck {
1837c2c66affSColin Finck case GL_DEBUG_TYPE_ERROR_ARB:
1838c2c66affSColin Finck ERR("%p: %s.\n", ctx, debugstr_an(message, length));
1839c2c66affSColin Finck break;
1840c2c66affSColin Finck
1841c2c66affSColin Finck case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
1842c2c66affSColin Finck case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
1843c2c66affSColin Finck case GL_DEBUG_TYPE_PORTABILITY_ARB:
1844c2c66affSColin Finck FIXME("%p: %s.\n", ctx, debugstr_an(message, length));
1845c2c66affSColin Finck break;
1846c2c66affSColin Finck
1847c2c66affSColin Finck case GL_DEBUG_TYPE_PERFORMANCE_ARB:
1848c2c66affSColin Finck WARN_(d3d_perf)("%p: %s.\n", ctx, debugstr_an(message, length));
1849c2c66affSColin Finck break;
1850c2c66affSColin Finck
1851c2c66affSColin Finck default:
1852c2c66affSColin Finck FIXME("ctx %p, type %#x: %s.\n", ctx, type, debugstr_an(message, length));
1853c2c66affSColin Finck break;
1854c2c66affSColin Finck }
1855c2c66affSColin Finck }
1856c2c66affSColin Finck
context_create_wgl_attribs(const struct wined3d_gl_info * gl_info,HDC hdc,HGLRC share_ctx)1857c2c66affSColin Finck HGLRC context_create_wgl_attribs(const struct wined3d_gl_info *gl_info, HDC hdc, HGLRC share_ctx)
1858c2c66affSColin Finck {
1859c2c66affSColin Finck HGLRC ctx;
1860c2c66affSColin Finck unsigned int ctx_attrib_idx = 0;
1861c2c66affSColin Finck GLint ctx_attribs[7], ctx_flags = 0;
1862c2c66affSColin Finck
1863c2c66affSColin Finck if (context_debug_output_enabled(gl_info))
1864c2c66affSColin Finck ctx_flags = WGL_CONTEXT_DEBUG_BIT_ARB;
1865c2c66affSColin Finck ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
1866c2c66affSColin Finck ctx_attribs[ctx_attrib_idx++] = gl_info->selected_gl_version >> 16;
1867c2c66affSColin Finck ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MINOR_VERSION_ARB;
1868c2c66affSColin Finck ctx_attribs[ctx_attrib_idx++] = gl_info->selected_gl_version & 0xffff;
1869*81cffd76SJoachim Henze if (gl_info->selected_gl_version >= MAKEDWORD_VERSION(3, 2))
1870*81cffd76SJoachim Henze ctx_flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
1871c2c66affSColin Finck if (ctx_flags)
1872c2c66affSColin Finck {
1873c2c66affSColin Finck ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_FLAGS_ARB;
1874c2c66affSColin Finck ctx_attribs[ctx_attrib_idx++] = ctx_flags;
1875c2c66affSColin Finck }
1876c2c66affSColin Finck ctx_attribs[ctx_attrib_idx] = 0;
1877c2c66affSColin Finck
1878c2c66affSColin Finck if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
1879c2c66affSColin Finck {
1880*81cffd76SJoachim Henze if (ctx_flags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
1881c2c66affSColin Finck {
1882*81cffd76SJoachim Henze ctx_attribs[ctx_attrib_idx - 1] &= ~WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
1883c2c66affSColin Finck if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
1884c2c66affSColin Finck WARN("Failed to create a WGL context with wglCreateContextAttribsARB, last error %#x.\n",
1885c2c66affSColin Finck GetLastError());
1886c2c66affSColin Finck }
1887c2c66affSColin Finck }
1888c2c66affSColin Finck return ctx;
1889c2c66affSColin Finck }
1890c2c66affSColin Finck
context_create(struct wined3d_swapchain * swapchain,struct wined3d_texture * target,const struct wined3d_format * ds_format)1891c2c66affSColin Finck struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
1892c2c66affSColin Finck struct wined3d_texture *target, const struct wined3d_format *ds_format)
1893c2c66affSColin Finck {
1894c2c66affSColin Finck struct wined3d_device *device = swapchain->device;
1895c2c66affSColin Finck const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
1896c2c66affSColin Finck const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1897c2c66affSColin Finck const struct wined3d_format *color_format;
1898c2c66affSColin Finck struct wined3d_context *ret;
1899c2c66affSColin Finck BOOL auxBuffers = FALSE;
1900c2c66affSColin Finck HGLRC ctx, share_ctx;
1901c2c66affSColin Finck DWORD target_usage;
1902c2c66affSColin Finck unsigned int i;
1903c2c66affSColin Finck DWORD state;
1904c2c66affSColin Finck
1905c2c66affSColin Finck TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
1906c2c66affSColin Finck
1907c2c66affSColin Finck wined3d_from_cs(device->cs);
1908c2c66affSColin Finck
19099987f029SAmine Khaldi if (!(ret = heap_alloc_zero(sizeof(*ret))))
1910c2c66affSColin Finck return NULL;
1911c2c66affSColin Finck
1912c2c66affSColin Finck ret->free_timestamp_query_size = 4;
19139987f029SAmine Khaldi if (!(ret->free_timestamp_queries = heap_calloc(ret->free_timestamp_query_size,
1914c2c66affSColin Finck sizeof(*ret->free_timestamp_queries))))
1915c2c66affSColin Finck goto out;
1916c2c66affSColin Finck list_init(&ret->timestamp_queries);
1917c2c66affSColin Finck
1918c2c66affSColin Finck ret->free_occlusion_query_size = 4;
19199987f029SAmine Khaldi if (!(ret->free_occlusion_queries = heap_calloc(ret->free_occlusion_query_size,
1920c2c66affSColin Finck sizeof(*ret->free_occlusion_queries))))
1921c2c66affSColin Finck goto out;
1922c2c66affSColin Finck list_init(&ret->occlusion_queries);
1923c2c66affSColin Finck
1924c2c66affSColin Finck ret->free_fence_size = 4;
19259987f029SAmine Khaldi if (!(ret->free_fences = heap_calloc(ret->free_fence_size, sizeof(*ret->free_fences))))
1926c2c66affSColin Finck goto out;
1927c2c66affSColin Finck list_init(&ret->fences);
1928c2c66affSColin Finck
1929c2c66affSColin Finck list_init(&ret->so_statistics_queries);
1930c2c66affSColin Finck
1931c2c66affSColin Finck list_init(&ret->pipeline_statistics_queries);
1932c2c66affSColin Finck
1933c2c66affSColin Finck list_init(&ret->fbo_list);
1934c2c66affSColin Finck list_init(&ret->fbo_destroy_list);
1935c2c66affSColin Finck
1936c2c66affSColin Finck if (!device->shader_backend->shader_allocate_context_data(ret))
1937c2c66affSColin Finck {
1938c2c66affSColin Finck ERR("Failed to allocate shader backend context data.\n");
1939c2c66affSColin Finck goto out;
1940c2c66affSColin Finck }
1941c2c66affSColin Finck if (!device->adapter->fragment_pipe->allocate_context_data(ret))
1942c2c66affSColin Finck {
1943c2c66affSColin Finck ERR("Failed to allocate fragment pipeline context data.\n");
1944c2c66affSColin Finck goto out;
1945c2c66affSColin Finck }
1946c2c66affSColin Finck
1947c2c66affSColin Finck for (i = 0; i < ARRAY_SIZE(ret->tex_unit_map); ++i)
1948c2c66affSColin Finck ret->tex_unit_map[i] = WINED3D_UNMAPPED_STAGE;
1949c2c66affSColin Finck for (i = 0; i < ARRAY_SIZE(ret->rev_tex_unit_map); ++i)
1950c2c66affSColin Finck ret->rev_tex_unit_map[i] = WINED3D_UNMAPPED_STAGE;
1951c2c66affSColin Finck if (gl_info->limits.graphics_samplers >= MAX_COMBINED_SAMPLERS)
1952c2c66affSColin Finck {
1953c2c66affSColin Finck /* Initialize the texture unit mapping to a 1:1 mapping. */
1954c2c66affSColin Finck unsigned int base, count;
1955c2c66affSColin Finck
1956c2c66affSColin Finck wined3d_gl_limits_get_texture_unit_range(&gl_info->limits, WINED3D_SHADER_TYPE_PIXEL, &base, &count);
1957c2c66affSColin Finck if (base + MAX_FRAGMENT_SAMPLERS > ARRAY_SIZE(ret->rev_tex_unit_map))
1958c2c66affSColin Finck {
1959c2c66affSColin Finck ERR("Unexpected texture unit base index %u.\n", base);
1960c2c66affSColin Finck goto out;
1961c2c66affSColin Finck }
1962c2c66affSColin Finck for (i = 0; i < min(count, MAX_FRAGMENT_SAMPLERS); ++i)
1963c2c66affSColin Finck {
1964c2c66affSColin Finck ret->tex_unit_map[i] = base + i;
1965c2c66affSColin Finck ret->rev_tex_unit_map[base + i] = i;
1966c2c66affSColin Finck }
1967c2c66affSColin Finck
1968c2c66affSColin Finck wined3d_gl_limits_get_texture_unit_range(&gl_info->limits, WINED3D_SHADER_TYPE_VERTEX, &base, &count);
1969c2c66affSColin Finck if (base + MAX_VERTEX_SAMPLERS > ARRAY_SIZE(ret->rev_tex_unit_map))
1970c2c66affSColin Finck {
1971c2c66affSColin Finck ERR("Unexpected texture unit base index %u.\n", base);
1972c2c66affSColin Finck goto out;
1973c2c66affSColin Finck }
1974c2c66affSColin Finck for (i = 0; i < min(count, MAX_VERTEX_SAMPLERS); ++i)
1975c2c66affSColin Finck {
1976c2c66affSColin Finck ret->tex_unit_map[MAX_FRAGMENT_SAMPLERS + i] = base + i;
1977c2c66affSColin Finck ret->rev_tex_unit_map[base + i] = MAX_FRAGMENT_SAMPLERS + i;
1978c2c66affSColin Finck }
1979c2c66affSColin Finck }
1980c2c66affSColin Finck
19819987f029SAmine Khaldi if (!(ret->texture_type = heap_calloc(gl_info->limits.combined_samplers,
1982c2c66affSColin Finck sizeof(*ret->texture_type))))
1983c2c66affSColin Finck goto out;
1984c2c66affSColin Finck
1985c2c66affSColin Finck if (!(ret->hdc = GetDCEx(swapchain->win_handle, 0, DCX_USESTYLE | DCX_CACHE)))
1986c2c66affSColin Finck {
1987c2c66affSColin Finck WARN("Failed to retrieve device context, trying swapchain backup.\n");
1988c2c66affSColin Finck
1989c2c66affSColin Finck if ((ret->hdc = swapchain_get_backup_dc(swapchain)))
1990c2c66affSColin Finck ret->hdc_is_private = TRUE;
1991c2c66affSColin Finck else
1992c2c66affSColin Finck {
1993c2c66affSColin Finck ERR("Failed to retrieve a device context.\n");
1994c2c66affSColin Finck goto out;
1995c2c66affSColin Finck }
1996c2c66affSColin Finck }
1997c2c66affSColin Finck
1998c2c66affSColin Finck color_format = target->resource.format;
1999c2c66affSColin Finck target_usage = target->resource.usage;
2000c2c66affSColin Finck
2001c2c66affSColin Finck /* In case of ORM_BACKBUFFER, make sure to request an alpha component for
2002c2c66affSColin Finck * X4R4G4B4/X8R8G8B8 as we might need it for the backbuffer. */
2003c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
2004c2c66affSColin Finck {
2005c2c66affSColin Finck auxBuffers = TRUE;
2006c2c66affSColin Finck
2007c2c66affSColin Finck if (color_format->id == WINED3DFMT_B4G4R4X4_UNORM)
2008c2c66affSColin Finck color_format = wined3d_get_format(gl_info, WINED3DFMT_B4G4R4A4_UNORM, target_usage);
2009c2c66affSColin Finck else if (color_format->id == WINED3DFMT_B8G8R8X8_UNORM)
2010c2c66affSColin Finck color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2011c2c66affSColin Finck }
2012c2c66affSColin Finck
2013c2c66affSColin Finck /* DirectDraw supports 8bit paletted render targets and these are used by
2014c2c66affSColin Finck * old games like StarCraft and C&C. Most modern hardware doesn't support
2015c2c66affSColin Finck * 8bit natively so we perform some form of 8bit -> 32bit conversion. The
2016c2c66affSColin Finck * conversion (ab)uses the alpha component for storing the palette index.
2017c2c66affSColin Finck * For this reason we require a format with 8bit alpha, so request
2018c2c66affSColin Finck * A8R8G8B8. */
2019c2c66affSColin Finck if (color_format->id == WINED3DFMT_P8_UINT)
2020c2c66affSColin Finck color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2021c2c66affSColin Finck
2022c2c66affSColin Finck /* When using FBOs for off-screen rendering, we only use the drawable for
2023c2c66affSColin Finck * presentation blits, and don't do any rendering to it. That means we
2024c2c66affSColin Finck * don't need depth or stencil buffers, and can mostly ignore the render
2025c2c66affSColin Finck * target format. This wouldn't necessarily be quite correct for 10bpc
2026c2c66affSColin Finck * display modes, but we don't currently support those.
2027c2c66affSColin Finck * Using the same format regardless of the color/depth/stencil targets
2028c2c66affSColin Finck * makes it much less likely that different wined3d instances will set
2029c2c66affSColin Finck * conflicting pixel formats. */
2030c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode != ORM_BACKBUFFER)
2031c2c66affSColin Finck {
2032c2c66affSColin Finck color_format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM, target_usage);
2033c2c66affSColin Finck ds_format = wined3d_get_format(gl_info, WINED3DFMT_UNKNOWN, WINED3DUSAGE_DEPTHSTENCIL);
2034c2c66affSColin Finck }
2035c2c66affSColin Finck
2036c2c66affSColin Finck /* Try to find a pixel format which matches our requirements. */
2037c2c66affSColin Finck if (!(ret->pixel_format = context_choose_pixel_format(device, ret->hdc, color_format, ds_format, auxBuffers)))
2038c2c66affSColin Finck goto out;
2039c2c66affSColin Finck
2040c2c66affSColin Finck ret->gl_info = gl_info;
2041c2c66affSColin Finck ret->win_handle = swapchain->win_handle;
2042c2c66affSColin Finck
2043c2c66affSColin Finck context_enter(ret);
2044c2c66affSColin Finck
2045c2c66affSColin Finck if (!context_set_pixel_format(ret))
2046c2c66affSColin Finck {
2047c2c66affSColin Finck ERR("Failed to set pixel format %d on device context %p.\n", ret->pixel_format, ret->hdc);
2048c2c66affSColin Finck context_release(ret);
2049c2c66affSColin Finck goto out;
2050c2c66affSColin Finck }
2051c2c66affSColin Finck
2052c2c66affSColin Finck share_ctx = device->context_count ? device->contexts[0]->glCtx : NULL;
2053c2c66affSColin Finck if (gl_info->p_wglCreateContextAttribsARB)
2054c2c66affSColin Finck {
2055c2c66affSColin Finck if (!(ctx = context_create_wgl_attribs(gl_info, ret->hdc, share_ctx)))
2056c2c66affSColin Finck goto out;
2057c2c66affSColin Finck }
2058c2c66affSColin Finck else
2059c2c66affSColin Finck {
2060c2c66affSColin Finck if (!(ctx = wglCreateContext(ret->hdc)))
2061c2c66affSColin Finck {
2062c2c66affSColin Finck ERR("Failed to create a WGL context.\n");
2063c2c66affSColin Finck context_release(ret);
2064c2c66affSColin Finck goto out;
2065c2c66affSColin Finck }
2066c2c66affSColin Finck
2067c2c66affSColin Finck if (share_ctx && !wglShareLists(share_ctx, ctx))
2068c2c66affSColin Finck {
2069c2c66affSColin Finck ERR("wglShareLists(%p, %p) failed, last error %#x.\n", share_ctx, ctx, GetLastError());
2070c2c66affSColin Finck context_release(ret);
2071c2c66affSColin Finck if (!wglDeleteContext(ctx))
2072c2c66affSColin Finck ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2073c2c66affSColin Finck goto out;
2074c2c66affSColin Finck }
2075c2c66affSColin Finck }
2076c2c66affSColin Finck
2077c2c66affSColin Finck if (!device_context_add(device, ret))
2078c2c66affSColin Finck {
2079c2c66affSColin Finck ERR("Failed to add the newly created context to the context list\n");
2080c2c66affSColin Finck context_release(ret);
2081c2c66affSColin Finck if (!wglDeleteContext(ctx))
2082c2c66affSColin Finck ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2083c2c66affSColin Finck goto out;
2084c2c66affSColin Finck }
2085c2c66affSColin Finck
2086c2c66affSColin Finck ret->d3d_info = d3d_info;
2087c2c66affSColin Finck ret->state_table = device->StateTable;
2088c2c66affSColin Finck
2089c2c66affSColin Finck /* Mark all states dirty to force a proper initialization of the states on
2090c2c66affSColin Finck * the first use of the context. Compute states do not need initialization. */
2091c2c66affSColin Finck for (state = 0; state <= STATE_HIGHEST; ++state)
2092c2c66affSColin Finck {
2093c2c66affSColin Finck if (ret->state_table[state].representative && !STATE_IS_COMPUTE(state))
2094c2c66affSColin Finck context_invalidate_state(ret, state);
2095c2c66affSColin Finck }
2096c2c66affSColin Finck
2097c2c66affSColin Finck ret->device = device;
2098c2c66affSColin Finck ret->swapchain = swapchain;
2099c2c66affSColin Finck ret->current_rt.texture = target;
2100c2c66affSColin Finck ret->current_rt.sub_resource_idx = 0;
2101c2c66affSColin Finck ret->tid = GetCurrentThreadId();
2102c2c66affSColin Finck
2103c2c66affSColin Finck ret->render_offscreen = wined3d_resource_is_offscreen(&target->resource);
2104c2c66affSColin Finck ret->draw_buffers_mask = context_generate_rt_mask(GL_BACK);
2105c2c66affSColin Finck ret->valid = 1;
2106c2c66affSColin Finck
2107c2c66affSColin Finck ret->glCtx = ctx;
2108c2c66affSColin Finck ret->hdc_has_format = TRUE;
2109c2c66affSColin Finck ret->needs_set = 1;
2110c2c66affSColin Finck
2111c2c66affSColin Finck /* Set up the context defaults */
2112c2c66affSColin Finck if (!context_set_current(ret))
2113c2c66affSColin Finck {
2114c2c66affSColin Finck ERR("Cannot activate context to set up defaults.\n");
2115c2c66affSColin Finck device_context_remove(device, ret);
2116c2c66affSColin Finck context_release(ret);
2117c2c66affSColin Finck if (!wglDeleteContext(ctx))
2118c2c66affSColin Finck ERR("wglDeleteContext(%p) failed, last error %#x.\n", ctx, GetLastError());
2119c2c66affSColin Finck goto out;
2120c2c66affSColin Finck }
2121c2c66affSColin Finck
2122c2c66affSColin Finck if (context_debug_output_enabled(gl_info))
2123c2c66affSColin Finck {
2124c2c66affSColin Finck GL_EXTCALL(glDebugMessageCallback(wined3d_debug_callback, ret));
2125c2c66affSColin Finck if (TRACE_ON(d3d_synchronous))
2126c2c66affSColin Finck gl_info->gl_ops.gl.p_glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
2127c2c66affSColin Finck GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE));
2128c2c66affSColin Finck if (ERR_ON(d3d))
2129c2c66affSColin Finck {
2130c2c66affSColin Finck GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR,
2131c2c66affSColin Finck GL_DONT_CARE, 0, NULL, GL_TRUE));
2132c2c66affSColin Finck }
2133c2c66affSColin Finck if (FIXME_ON(d3d))
2134c2c66affSColin Finck {
2135c2c66affSColin Finck GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR,
2136c2c66affSColin Finck GL_DONT_CARE, 0, NULL, GL_TRUE));
2137c2c66affSColin Finck GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR,
2138c2c66affSColin Finck GL_DONT_CARE, 0, NULL, GL_TRUE));
2139c2c66affSColin Finck GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_PORTABILITY,
2140c2c66affSColin Finck GL_DONT_CARE, 0, NULL, GL_TRUE));
2141c2c66affSColin Finck }
2142c2c66affSColin Finck if (WARN_ON(d3d_perf))
2143c2c66affSColin Finck {
2144c2c66affSColin Finck GL_EXTCALL(glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE,
2145c2c66affSColin Finck GL_DONT_CARE, 0, NULL, GL_TRUE));
2146c2c66affSColin Finck }
2147c2c66affSColin Finck }
2148c2c66affSColin Finck
2149c2c66affSColin Finck if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2150c2c66affSColin Finck gl_info->gl_ops.gl.p_glGetIntegerv(GL_AUX_BUFFERS, &ret->aux_buffers);
2151c2c66affSColin Finck
2152c2c66affSColin Finck TRACE("Setting up the screen\n");
2153c2c66affSColin Finck
2154c2c66affSColin Finck if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2155c2c66affSColin Finck {
2156c2c66affSColin Finck gl_info->gl_ops.gl.p_glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
2157c2c66affSColin Finck checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);");
2158c2c66affSColin Finck
2159c2c66affSColin Finck gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
2160c2c66affSColin Finck checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);");
2161c2c66affSColin Finck
2162c2c66affSColin Finck gl_info->gl_ops.gl.p_glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
2163c2c66affSColin Finck checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);");
2164c2c66affSColin Finck }
2165c2c66affSColin Finck else
2166c2c66affSColin Finck {
2167c2c66affSColin Finck GLuint vao;
2168c2c66affSColin Finck
2169c2c66affSColin Finck GL_EXTCALL(glGenVertexArrays(1, &vao));
2170c2c66affSColin Finck GL_EXTCALL(glBindVertexArray(vao));
2171c2c66affSColin Finck checkGLcall("creating VAO");
2172c2c66affSColin Finck }
2173c2c66affSColin Finck
2174c2c66affSColin Finck gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);
2175c2c66affSColin Finck checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, device->surface_alignment);");
2176c2c66affSColin Finck gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2177c2c66affSColin Finck checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, 1);");
2178c2c66affSColin Finck
2179*81cffd76SJoachim Henze if (gl_info->supported[ARB_VERTEX_BLEND])
2180*81cffd76SJoachim Henze {
2181*81cffd76SJoachim Henze /* Direct3D always uses n-1 weights for n world matrices and uses
2182*81cffd76SJoachim Henze * 1 - sum for the last one this is equal to GL_WEIGHT_SUM_UNITY_ARB.
2183*81cffd76SJoachim Henze * Enabling it doesn't do anything unless GL_VERTEX_BLEND_ARB isn't
2184*81cffd76SJoachim Henze * enabled as well. */
2185*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glEnable(GL_WEIGHT_SUM_UNITY_ARB);
2186*81cffd76SJoachim Henze checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)");
2187*81cffd76SJoachim Henze }
2188c2c66affSColin Finck if (gl_info->supported[NV_TEXTURE_SHADER2])
2189c2c66affSColin Finck {
2190c2c66affSColin Finck /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d
2191c2c66affSColin Finck * the previous texture where to source the offset from is always unit - 1.
2192c2c66affSColin Finck */
2193c2c66affSColin Finck for (i = 1; i < gl_info->limits.textures; ++i)
2194c2c66affSColin Finck {
2195c2c66affSColin Finck context_active_texture(ret, gl_info, i);
2196c2c66affSColin Finck gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_SHADER_NV,
2197c2c66affSColin Finck GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + i - 1);
2198c2c66affSColin Finck checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...");
2199c2c66affSColin Finck }
2200c2c66affSColin Finck }
2201c2c66affSColin Finck if (gl_info->supported[ARB_FRAGMENT_PROGRAM])
2202c2c66affSColin Finck {
2203c2c66affSColin Finck /* MacOS(radeon X1600 at least, but most likely others too) refuses to draw if GLSL and ARBFP are
2204c2c66affSColin Finck * enabled, but the currently bound arbfp program is 0. Enabling ARBFP with prog 0 is invalid, but
2205c2c66affSColin Finck * GLSL should bypass this. This causes problems in programs that never use the fixed function pipeline,
2206c2c66affSColin Finck * because the ARBFP extension is enabled by the ARBFP pipeline at context creation, but no program
2207c2c66affSColin Finck * is ever assigned.
2208c2c66affSColin Finck *
2209c2c66affSColin Finck * So make sure a program is assigned to each context. The first real ARBFP use will set a different
2210c2c66affSColin Finck * program and the dummy program is destroyed when the context is destroyed.
2211c2c66affSColin Finck */
2212c2c66affSColin Finck static const char dummy_program[] =
2213c2c66affSColin Finck "!!ARBfp1.0\n"
2214c2c66affSColin Finck "MOV result.color, fragment.color.primary;\n"
2215c2c66affSColin Finck "END\n";
2216c2c66affSColin Finck GL_EXTCALL(glGenProgramsARB(1, &ret->dummy_arbfp_prog));
2217c2c66affSColin Finck GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret->dummy_arbfp_prog));
2218c2c66affSColin Finck GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(dummy_program), dummy_program));
2219c2c66affSColin Finck }
2220c2c66affSColin Finck
2221c2c66affSColin Finck if (gl_info->supported[ARB_POINT_SPRITE])
2222c2c66affSColin Finck {
2223c2c66affSColin Finck for (i = 0; i < gl_info->limits.textures; ++i)
2224c2c66affSColin Finck {
2225c2c66affSColin Finck context_active_texture(ret, gl_info, i);
2226c2c66affSColin Finck gl_info->gl_ops.gl.p_glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
2227c2c66affSColin Finck checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)");
2228c2c66affSColin Finck }
2229c2c66affSColin Finck }
2230c2c66affSColin Finck
2231c2c66affSColin Finck if (gl_info->supported[ARB_PROVOKING_VERTEX])
2232c2c66affSColin Finck {
2233c2c66affSColin Finck GL_EXTCALL(glProvokingVertex(GL_FIRST_VERTEX_CONVENTION));
2234c2c66affSColin Finck }
2235c2c66affSColin Finck else if (gl_info->supported[EXT_PROVOKING_VERTEX])
2236c2c66affSColin Finck {
2237c2c66affSColin Finck GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT));
2238c2c66affSColin Finck }
2239c2c66affSColin Finck if (!(d3d_info->wined3d_creation_flags & WINED3D_NO_PRIMITIVE_RESTART))
2240c2c66affSColin Finck {
2241c2c66affSColin Finck if (gl_info->supported[ARB_ES3_COMPATIBILITY])
2242c2c66affSColin Finck {
2243c2c66affSColin Finck gl_info->gl_ops.gl.p_glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
2244c2c66affSColin Finck checkGLcall("enable GL_PRIMITIVE_RESTART_FIXED_INDEX");
2245c2c66affSColin Finck }
2246c2c66affSColin Finck else
2247c2c66affSColin Finck {
2248c2c66affSColin Finck FIXME("OpenGL implementation does not support GL_PRIMITIVE_RESTART_FIXED_INDEX.\n");
2249c2c66affSColin Finck }
2250c2c66affSColin Finck }
2251c2c66affSColin Finck if (!(d3d_info->wined3d_creation_flags & WINED3D_LEGACY_CUBEMAP_FILTERING)
2252c2c66affSColin Finck && gl_info->supported[ARB_SEAMLESS_CUBE_MAP])
2253c2c66affSColin Finck {
2254c2c66affSColin Finck gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
2255c2c66affSColin Finck checkGLcall("enable seamless cube map filtering");
2256c2c66affSColin Finck }
2257c2c66affSColin Finck if (gl_info->supported[ARB_CLIP_CONTROL])
2258c2c66affSColin Finck GL_EXTCALL(glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT));
2259c2c66affSColin Finck device->shader_backend->shader_init_context_state(ret);
2260c2c66affSColin Finck ret->shader_update_mask = (1u << WINED3D_SHADER_TYPE_PIXEL)
2261c2c66affSColin Finck | (1u << WINED3D_SHADER_TYPE_VERTEX)
2262c2c66affSColin Finck | (1u << WINED3D_SHADER_TYPE_GEOMETRY)
2263c2c66affSColin Finck | (1u << WINED3D_SHADER_TYPE_HULL)
2264c2c66affSColin Finck | (1u << WINED3D_SHADER_TYPE_DOMAIN)
2265c2c66affSColin Finck | (1u << WINED3D_SHADER_TYPE_COMPUTE);
2266c2c66affSColin Finck
2267c2c66affSColin Finck /* If this happens to be the first context for the device, dummy textures
2268c2c66affSColin Finck * are not created yet. In that case, they will be created (and bound) by
2269c2c66affSColin Finck * create_dummy_textures right after this context is initialized. */
2270c2c66affSColin Finck if (device->dummy_textures.tex_2d)
2271c2c66affSColin Finck context_bind_dummy_textures(device, ret);
2272c2c66affSColin Finck
2273c2c66affSColin Finck TRACE("Created context %p.\n", ret);
2274c2c66affSColin Finck
2275c2c66affSColin Finck return ret;
2276c2c66affSColin Finck
2277c2c66affSColin Finck out:
2278c2c66affSColin Finck if (ret->hdc)
2279c2c66affSColin Finck wined3d_release_dc(swapchain->win_handle, ret->hdc);
2280c2c66affSColin Finck device->shader_backend->shader_free_context_data(ret);
2281c2c66affSColin Finck device->adapter->fragment_pipe->free_context_data(ret);
22829987f029SAmine Khaldi heap_free(ret->texture_type);
22839987f029SAmine Khaldi heap_free(ret->free_fences);
22849987f029SAmine Khaldi heap_free(ret->free_occlusion_queries);
22859987f029SAmine Khaldi heap_free(ret->free_timestamp_queries);
22869987f029SAmine Khaldi heap_free(ret);
2287c2c66affSColin Finck return NULL;
2288c2c66affSColin Finck }
2289c2c66affSColin Finck
context_destroy(struct wined3d_device * device,struct wined3d_context * context)2290c2c66affSColin Finck void context_destroy(struct wined3d_device *device, struct wined3d_context *context)
2291c2c66affSColin Finck {
2292c2c66affSColin Finck BOOL destroy;
2293c2c66affSColin Finck
2294c2c66affSColin Finck TRACE("Destroying ctx %p\n", context);
2295c2c66affSColin Finck
2296c2c66affSColin Finck wined3d_from_cs(device->cs);
2297c2c66affSColin Finck
2298c2c66affSColin Finck /* We delay destroying a context when it is active. The context_release()
2299c2c66affSColin Finck * function invokes context_destroy() again while leaving the last level. */
2300c2c66affSColin Finck if (context->level)
2301c2c66affSColin Finck {
2302c2c66affSColin Finck TRACE("Delaying destruction of context %p.\n", context);
2303c2c66affSColin Finck context->destroy_delayed = 1;
2304c2c66affSColin Finck /* FIXME: Get rid of a pointer to swapchain from wined3d_context. */
2305c2c66affSColin Finck context->swapchain = NULL;
2306c2c66affSColin Finck return;
2307c2c66affSColin Finck }
2308c2c66affSColin Finck
2309c2c66affSColin Finck if (context->tid == GetCurrentThreadId() || !context->current)
2310c2c66affSColin Finck {
2311c2c66affSColin Finck context_destroy_gl_resources(context);
2312c2c66affSColin Finck TlsSetValue(wined3d_context_tls_idx, NULL);
2313c2c66affSColin Finck destroy = TRUE;
2314c2c66affSColin Finck }
2315c2c66affSColin Finck else
2316c2c66affSColin Finck {
2317c2c66affSColin Finck /* Make a copy of gl_info for context_destroy_gl_resources use, the one
2318c2c66affSColin Finck in wined3d_adapter may go away in the meantime */
23199987f029SAmine Khaldi struct wined3d_gl_info *gl_info = heap_alloc(sizeof(*gl_info));
2320c2c66affSColin Finck *gl_info = *context->gl_info;
2321c2c66affSColin Finck context->gl_info = gl_info;
2322c2c66affSColin Finck context->destroyed = 1;
2323c2c66affSColin Finck destroy = FALSE;
2324c2c66affSColin Finck }
2325c2c66affSColin Finck
2326c2c66affSColin Finck device->shader_backend->shader_free_context_data(context);
2327c2c66affSColin Finck device->adapter->fragment_pipe->free_context_data(context);
23289987f029SAmine Khaldi heap_free(context->texture_type);
2329c2c66affSColin Finck device_context_remove(device, context);
23309987f029SAmine Khaldi if (destroy)
23319987f029SAmine Khaldi heap_free(context);
2332c2c66affSColin Finck }
2333c2c66affSColin Finck
context_get_tex_unit_mapping(const struct wined3d_context * context,const struct wined3d_shader_version * shader_version,unsigned int * base,unsigned int * count)2334c2c66affSColin Finck const DWORD *context_get_tex_unit_mapping(const struct wined3d_context *context,
2335c2c66affSColin Finck const struct wined3d_shader_version *shader_version, unsigned int *base, unsigned int *count)
2336c2c66affSColin Finck {
2337c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
2338c2c66affSColin Finck
2339c2c66affSColin Finck if (!shader_version)
2340c2c66affSColin Finck {
2341c2c66affSColin Finck *base = 0;
2342c2c66affSColin Finck *count = MAX_TEXTURES;
2343c2c66affSColin Finck return context->tex_unit_map;
2344c2c66affSColin Finck }
2345c2c66affSColin Finck
2346c2c66affSColin Finck if (shader_version->major >= 4)
2347c2c66affSColin Finck {
2348c2c66affSColin Finck wined3d_gl_limits_get_texture_unit_range(&gl_info->limits, shader_version->type, base, count);
2349c2c66affSColin Finck return NULL;
2350c2c66affSColin Finck }
2351c2c66affSColin Finck
2352c2c66affSColin Finck switch (shader_version->type)
2353c2c66affSColin Finck {
2354c2c66affSColin Finck case WINED3D_SHADER_TYPE_PIXEL:
2355c2c66affSColin Finck *base = 0;
2356c2c66affSColin Finck *count = MAX_FRAGMENT_SAMPLERS;
2357c2c66affSColin Finck break;
2358c2c66affSColin Finck case WINED3D_SHADER_TYPE_VERTEX:
2359c2c66affSColin Finck *base = MAX_FRAGMENT_SAMPLERS;
2360c2c66affSColin Finck *count = MAX_VERTEX_SAMPLERS;
2361c2c66affSColin Finck break;
2362c2c66affSColin Finck default:
2363c2c66affSColin Finck ERR("Unhandled shader type %#x.\n", shader_version->type);
2364c2c66affSColin Finck *base = 0;
2365c2c66affSColin Finck *count = 0;
2366c2c66affSColin Finck }
2367c2c66affSColin Finck
2368c2c66affSColin Finck return context->tex_unit_map;
2369c2c66affSColin Finck }
2370c2c66affSColin Finck
2371*81cffd76SJoachim Henze /* Context activation is done by the caller. */
set_blit_dimension(const struct wined3d_gl_info * gl_info,UINT width,UINT height)2372*81cffd76SJoachim Henze static void set_blit_dimension(const struct wined3d_gl_info *gl_info, UINT width, UINT height)
2373*81cffd76SJoachim Henze {
2374*81cffd76SJoachim Henze const GLdouble projection[] =
2375*81cffd76SJoachim Henze {
2376*81cffd76SJoachim Henze 2.0 / width, 0.0, 0.0, 0.0,
2377*81cffd76SJoachim Henze 0.0, 2.0 / height, 0.0, 0.0,
2378*81cffd76SJoachim Henze 0.0, 0.0, 2.0, 0.0,
2379*81cffd76SJoachim Henze -1.0, -1.0, -1.0, 1.0,
2380*81cffd76SJoachim Henze };
2381*81cffd76SJoachim Henze
2382*81cffd76SJoachim Henze if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2383*81cffd76SJoachim Henze {
2384*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glMatrixMode(GL_PROJECTION);
2385*81cffd76SJoachim Henze checkGLcall("glMatrixMode(GL_PROJECTION)");
2386*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glLoadMatrixd(projection);
2387*81cffd76SJoachim Henze checkGLcall("glLoadMatrixd");
2388*81cffd76SJoachim Henze }
2389*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glViewport(0, 0, width, height);
2390*81cffd76SJoachim Henze checkGLcall("glViewport");
2391*81cffd76SJoachim Henze }
2392*81cffd76SJoachim Henze
context_get_rt_size(const struct wined3d_context * context,SIZE * size)2393c2c66affSColin Finck static void context_get_rt_size(const struct wined3d_context *context, SIZE *size)
2394c2c66affSColin Finck {
2395c2c66affSColin Finck const struct wined3d_texture *rt = context->current_rt.texture;
2396c2c66affSColin Finck unsigned int level;
2397c2c66affSColin Finck
2398c2c66affSColin Finck if (rt->swapchain)
2399c2c66affSColin Finck {
2400c2c66affSColin Finck RECT window_size;
2401c2c66affSColin Finck
2402c2c66affSColin Finck GetClientRect(context->win_handle, &window_size);
2403c2c66affSColin Finck size->cx = window_size.right - window_size.left;
2404c2c66affSColin Finck size->cy = window_size.bottom - window_size.top;
2405c2c66affSColin Finck
2406c2c66affSColin Finck return;
2407c2c66affSColin Finck }
2408c2c66affSColin Finck
2409c2c66affSColin Finck level = context->current_rt.sub_resource_idx % rt->level_count;
2410c2c66affSColin Finck size->cx = wined3d_texture_get_level_width(rt, level);
2411c2c66affSColin Finck size->cy = wined3d_texture_get_level_height(rt, level);
2412c2c66affSColin Finck }
2413c2c66affSColin Finck
context_enable_clip_distances(struct wined3d_context * context,unsigned int enable_mask)2414d6ac0a71SAmine Khaldi void context_enable_clip_distances(struct wined3d_context *context, unsigned int enable_mask)
2415d6ac0a71SAmine Khaldi {
2416d6ac0a71SAmine Khaldi const struct wined3d_gl_info *gl_info = context->gl_info;
2417d6ac0a71SAmine Khaldi unsigned int clip_distance_count = gl_info->limits.user_clip_distances;
2418d6ac0a71SAmine Khaldi unsigned int i, disable_mask, current_mask;
2419d6ac0a71SAmine Khaldi
2420d6ac0a71SAmine Khaldi disable_mask = ~enable_mask;
2421d6ac0a71SAmine Khaldi enable_mask &= (1u << clip_distance_count) - 1;
2422d6ac0a71SAmine Khaldi disable_mask &= (1u << clip_distance_count) - 1;
2423d6ac0a71SAmine Khaldi current_mask = context->clip_distance_mask;
2424d6ac0a71SAmine Khaldi context->clip_distance_mask = enable_mask;
2425d6ac0a71SAmine Khaldi
2426d6ac0a71SAmine Khaldi enable_mask &= ~current_mask;
24279987f029SAmine Khaldi while (enable_mask)
2428d6ac0a71SAmine Khaldi {
24299987f029SAmine Khaldi i = wined3d_bit_scan(&enable_mask);
2430d6ac0a71SAmine Khaldi gl_info->gl_ops.gl.p_glEnable(GL_CLIP_DISTANCE0 + i);
2431d6ac0a71SAmine Khaldi }
2432d6ac0a71SAmine Khaldi disable_mask &= current_mask;
24339987f029SAmine Khaldi while (disable_mask)
2434d6ac0a71SAmine Khaldi {
24359987f029SAmine Khaldi i = wined3d_bit_scan(&disable_mask);
2436d6ac0a71SAmine Khaldi gl_info->gl_ops.gl.p_glDisable(GL_CLIP_DISTANCE0 + i);
2437d6ac0a71SAmine Khaldi }
2438d6ac0a71SAmine Khaldi checkGLcall("toggle clip distances");
2439d6ac0a71SAmine Khaldi }
2440d6ac0a71SAmine Khaldi
2441*81cffd76SJoachim Henze /*****************************************************************************
2442*81cffd76SJoachim Henze * SetupForBlit
2443*81cffd76SJoachim Henze *
2444*81cffd76SJoachim Henze * Sets up a context for DirectDraw blitting.
2445*81cffd76SJoachim Henze * All texture units are disabled, texture unit 0 is set as current unit
2446*81cffd76SJoachim Henze * fog, lighting, blending, alpha test, z test, scissor test, culling disabled
2447*81cffd76SJoachim Henze * color writing enabled for all channels
2448*81cffd76SJoachim Henze * register combiners disabled, shaders disabled
2449*81cffd76SJoachim Henze * world matrix is set to identity, texture matrix 0 too
2450*81cffd76SJoachim Henze * projection matrix is setup for drawing screen coordinates
2451*81cffd76SJoachim Henze *
2452*81cffd76SJoachim Henze * Params:
2453*81cffd76SJoachim Henze * This: Device to activate the context for
2454*81cffd76SJoachim Henze * context: Context to setup
2455*81cffd76SJoachim Henze *
2456*81cffd76SJoachim Henze *****************************************************************************/
2457*81cffd76SJoachim Henze /* Context activation is done by the caller. */
SetupForBlit(const struct wined3d_device * device,struct wined3d_context * context)2458*81cffd76SJoachim Henze static void SetupForBlit(const struct wined3d_device *device, struct wined3d_context *context)
2459*81cffd76SJoachim Henze {
2460*81cffd76SJoachim Henze const struct wined3d_gl_info *gl_info = context->gl_info;
2461*81cffd76SJoachim Henze DWORD sampler;
2462*81cffd76SJoachim Henze SIZE rt_size;
2463*81cffd76SJoachim Henze int i;
2464*81cffd76SJoachim Henze
2465*81cffd76SJoachim Henze TRACE("Setting up context %p for blitting\n", context);
2466*81cffd76SJoachim Henze
2467*81cffd76SJoachim Henze context_get_rt_size(context, &rt_size);
2468*81cffd76SJoachim Henze
2469*81cffd76SJoachim Henze if (context->last_was_blit)
2470*81cffd76SJoachim Henze {
2471*81cffd76SJoachim Henze if (context->blit_w != rt_size.cx || context->blit_h != rt_size.cy)
2472*81cffd76SJoachim Henze {
2473*81cffd76SJoachim Henze set_blit_dimension(gl_info, rt_size.cx, rt_size.cy);
2474*81cffd76SJoachim Henze context->blit_w = rt_size.cx;
2475*81cffd76SJoachim Henze context->blit_h = rt_size.cy;
2476*81cffd76SJoachim Henze /* No need to dirtify here, the states are still dirtified because
2477*81cffd76SJoachim Henze * they weren't applied since the last SetupForBlit() call. */
2478*81cffd76SJoachim Henze }
2479*81cffd76SJoachim Henze TRACE("Context is already set up for blitting, nothing to do\n");
2480*81cffd76SJoachim Henze return;
2481*81cffd76SJoachim Henze }
2482*81cffd76SJoachim Henze context->last_was_blit = TRUE;
2483*81cffd76SJoachim Henze
2484*81cffd76SJoachim Henze if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
2485*81cffd76SJoachim Henze {
2486*81cffd76SJoachim Henze /* Disable all textures. The caller can then bind a texture it wants to blit
2487*81cffd76SJoachim Henze * from
2488*81cffd76SJoachim Henze *
2489*81cffd76SJoachim Henze * The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed
2490*81cffd76SJoachim Henze * function texture unit. No need to care for higher samplers
2491*81cffd76SJoachim Henze */
2492*81cffd76SJoachim Henze for (i = gl_info->limits.textures - 1; i > 0 ; --i)
2493*81cffd76SJoachim Henze {
2494*81cffd76SJoachim Henze sampler = context->rev_tex_unit_map[i];
2495*81cffd76SJoachim Henze context_active_texture(context, gl_info, i);
2496*81cffd76SJoachim Henze
2497*81cffd76SJoachim Henze if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2498*81cffd76SJoachim Henze {
2499*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2500*81cffd76SJoachim Henze checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
2501*81cffd76SJoachim Henze }
2502*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_3D);
2503*81cffd76SJoachim Henze checkGLcall("glDisable GL_TEXTURE_3D");
2504*81cffd76SJoachim Henze if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2505*81cffd76SJoachim Henze {
2506*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2507*81cffd76SJoachim Henze checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
2508*81cffd76SJoachim Henze }
2509*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2510*81cffd76SJoachim Henze checkGLcall("glDisable GL_TEXTURE_2D");
2511*81cffd76SJoachim Henze
2512*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2513*81cffd76SJoachim Henze checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);");
2514*81cffd76SJoachim Henze
2515*81cffd76SJoachim Henze if (sampler != WINED3D_UNMAPPED_STAGE)
2516*81cffd76SJoachim Henze {
2517*81cffd76SJoachim Henze if (sampler < MAX_TEXTURES)
2518*81cffd76SJoachim Henze context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3D_TSS_COLOR_OP));
2519*81cffd76SJoachim Henze context_invalidate_state(context, STATE_SAMPLER(sampler));
2520*81cffd76SJoachim Henze }
2521*81cffd76SJoachim Henze }
2522*81cffd76SJoachim Henze
2523*81cffd76SJoachim Henze context_active_texture(context, gl_info, 0);
2524*81cffd76SJoachim Henze if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
2525*81cffd76SJoachim Henze {
2526*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
2527*81cffd76SJoachim Henze checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB");
2528*81cffd76SJoachim Henze }
2529*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_3D);
2530*81cffd76SJoachim Henze checkGLcall("glDisable GL_TEXTURE_3D");
2531*81cffd76SJoachim Henze if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
2532*81cffd76SJoachim Henze {
2533*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
2534*81cffd76SJoachim Henze checkGLcall("glDisable GL_TEXTURE_RECTANGLE_ARB");
2535*81cffd76SJoachim Henze }
2536*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
2537*81cffd76SJoachim Henze checkGLcall("glDisable GL_TEXTURE_2D");
2538*81cffd76SJoachim Henze
2539*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2540*81cffd76SJoachim Henze
2541*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glMatrixMode(GL_TEXTURE);
2542*81cffd76SJoachim Henze checkGLcall("glMatrixMode(GL_TEXTURE)");
2543*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glLoadIdentity();
2544*81cffd76SJoachim Henze checkGLcall("glLoadIdentity()");
2545*81cffd76SJoachim Henze
2546*81cffd76SJoachim Henze if (gl_info->supported[EXT_TEXTURE_LOD_BIAS])
2547*81cffd76SJoachim Henze {
2548*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT,
2549*81cffd76SJoachim Henze GL_TEXTURE_LOD_BIAS_EXT, 0.0f);
2550*81cffd76SJoachim Henze checkGLcall("glTexEnvf GL_TEXTURE_LOD_BIAS_EXT ...");
2551*81cffd76SJoachim Henze }
2552*81cffd76SJoachim Henze
2553*81cffd76SJoachim Henze /* Setup transforms */
2554*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glMatrixMode(GL_MODELVIEW);
2555*81cffd76SJoachim Henze checkGLcall("glMatrixMode(GL_MODELVIEW)");
2556*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glLoadIdentity();
2557*81cffd76SJoachim Henze checkGLcall("glLoadIdentity()");
2558*81cffd76SJoachim Henze context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_WORLD_MATRIX(0)));
2559*81cffd76SJoachim Henze
2560*81cffd76SJoachim Henze /* Other misc states */
2561*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2562*81cffd76SJoachim Henze checkGLcall("glDisable(GL_ALPHA_TEST)");
2563*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHATESTENABLE));
2564*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_LIGHTING);
2565*81cffd76SJoachim Henze checkGLcall("glDisable GL_LIGHTING");
2566*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_LIGHTING));
2567*81cffd76SJoachim Henze glDisableWINE(GL_FOG);
2568*81cffd76SJoachim Henze checkGLcall("glDisable GL_FOG");
2569*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_FOGENABLE));
2570*81cffd76SJoachim Henze }
2571*81cffd76SJoachim Henze
2572*81cffd76SJoachim Henze if (gl_info->supported[ARB_SAMPLER_OBJECTS])
2573*81cffd76SJoachim Henze GL_EXTCALL(glBindSampler(0, 0));
2574*81cffd76SJoachim Henze context_active_texture(context, gl_info, 0);
2575*81cffd76SJoachim Henze
2576*81cffd76SJoachim Henze sampler = context->rev_tex_unit_map[0];
2577*81cffd76SJoachim Henze if (sampler != WINED3D_UNMAPPED_STAGE)
2578*81cffd76SJoachim Henze {
2579*81cffd76SJoachim Henze if (sampler < MAX_TEXTURES)
2580*81cffd76SJoachim Henze {
2581*81cffd76SJoachim Henze context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_TEXTURE0 + sampler));
2582*81cffd76SJoachim Henze context_invalidate_state(context, STATE_TEXTURESTAGE(sampler, WINED3D_TSS_COLOR_OP));
2583*81cffd76SJoachim Henze }
2584*81cffd76SJoachim Henze context_invalidate_state(context, STATE_SAMPLER(sampler));
2585*81cffd76SJoachim Henze }
2586*81cffd76SJoachim Henze
2587*81cffd76SJoachim Henze /* Other misc states */
2588*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_DEPTH_TEST);
2589*81cffd76SJoachim Henze checkGLcall("glDisable GL_DEPTH_TEST");
2590*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZENABLE));
2591*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2592*81cffd76SJoachim Henze checkGLcall("glDisable GL_BLEND");
2593*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
2594*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2595*81cffd76SJoachim Henze checkGLcall("glDisable GL_CULL_FACE");
2596*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CULLMODE));
2597*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2598*81cffd76SJoachim Henze checkGLcall("glDisable GL_STENCIL_TEST");
2599*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILENABLE));
2600*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2601*81cffd76SJoachim Henze checkGLcall("glDisable GL_SCISSOR_TEST");
2602*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
2603*81cffd76SJoachim Henze if (gl_info->supported[ARB_POINT_SPRITE])
2604*81cffd76SJoachim Henze {
2605*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_POINT_SPRITE_ARB);
2606*81cffd76SJoachim Henze checkGLcall("glDisable GL_POINT_SPRITE_ARB");
2607*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_POINTSPRITEENABLE));
2608*81cffd76SJoachim Henze }
2609*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE);
2610*81cffd76SJoachim Henze checkGLcall("glColorMask");
2611*81cffd76SJoachim Henze for (i = 0; i < MAX_RENDER_TARGETS; ++i)
2612*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITE(i)));
2613*81cffd76SJoachim Henze if (gl_info->supported[EXT_SECONDARY_COLOR])
2614*81cffd76SJoachim Henze {
2615*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glDisable(GL_COLOR_SUM_EXT);
2616*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SPECULARENABLE));
2617*81cffd76SJoachim Henze checkGLcall("glDisable(GL_COLOR_SUM_EXT)");
2618*81cffd76SJoachim Henze }
2619*81cffd76SJoachim Henze
2620*81cffd76SJoachim Henze context->last_was_rhw = TRUE;
2621*81cffd76SJoachim Henze context_invalidate_state(context, STATE_VDECL); /* because of last_was_rhw = TRUE */
2622*81cffd76SJoachim Henze
2623*81cffd76SJoachim Henze context_enable_clip_distances(context, 0);
2624*81cffd76SJoachim Henze context_invalidate_state(context, STATE_RENDER(WINED3D_RS_CLIPPING));
2625*81cffd76SJoachim Henze
2626*81cffd76SJoachim Henze /* FIXME: Make draw_textured_quad() able to work with a upper left origin. */
2627*81cffd76SJoachim Henze if (gl_info->supported[ARB_CLIP_CONTROL])
2628*81cffd76SJoachim Henze GL_EXTCALL(glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE));
2629*81cffd76SJoachim Henze
2630*81cffd76SJoachim Henze set_blit_dimension(gl_info, rt_size.cx, rt_size.cy);
2631*81cffd76SJoachim Henze
2632*81cffd76SJoachim Henze /* Disable shaders */
2633*81cffd76SJoachim Henze device->shader_backend->shader_disable(device->shader_priv, context);
2634*81cffd76SJoachim Henze
2635*81cffd76SJoachim Henze context->blit_w = rt_size.cx;
2636*81cffd76SJoachim Henze context->blit_h = rt_size.cy;
2637*81cffd76SJoachim Henze context_invalidate_state(context, STATE_VIEWPORT);
2638*81cffd76SJoachim Henze context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
2639*81cffd76SJoachim Henze }
2640*81cffd76SJoachim Henze
is_rt_mask_onscreen(DWORD rt_mask)2641c2c66affSColin Finck static inline BOOL is_rt_mask_onscreen(DWORD rt_mask)
2642c2c66affSColin Finck {
2643c2c66affSColin Finck return rt_mask & (1u << 31);
2644c2c66affSColin Finck }
2645c2c66affSColin Finck
draw_buffer_from_rt_mask(DWORD rt_mask)2646c2c66affSColin Finck static inline GLenum draw_buffer_from_rt_mask(DWORD rt_mask)
2647c2c66affSColin Finck {
2648c2c66affSColin Finck return rt_mask & ~(1u << 31);
2649c2c66affSColin Finck }
2650c2c66affSColin Finck
2651c2c66affSColin Finck /* Context activation is done by the caller. */
context_apply_draw_buffers(struct wined3d_context * context,DWORD rt_mask)2652c2c66affSColin Finck static void context_apply_draw_buffers(struct wined3d_context *context, DWORD rt_mask)
2653c2c66affSColin Finck {
2654c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
26559987f029SAmine Khaldi GLenum draw_buffers[MAX_RENDER_TARGET_VIEWS];
2656c2c66affSColin Finck
2657c2c66affSColin Finck if (!rt_mask)
2658c2c66affSColin Finck {
2659c2c66affSColin Finck gl_info->gl_ops.gl.p_glDrawBuffer(GL_NONE);
2660c2c66affSColin Finck }
2661c2c66affSColin Finck else if (is_rt_mask_onscreen(rt_mask))
2662c2c66affSColin Finck {
2663c2c66affSColin Finck gl_info->gl_ops.gl.p_glDrawBuffer(draw_buffer_from_rt_mask(rt_mask));
2664c2c66affSColin Finck }
2665c2c66affSColin Finck else
2666c2c66affSColin Finck {
2667c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2668c2c66affSColin Finck {
2669c2c66affSColin Finck unsigned int i = 0;
2670c2c66affSColin Finck
2671c2c66affSColin Finck while (rt_mask)
2672c2c66affSColin Finck {
2673c2c66affSColin Finck if (rt_mask & 1)
26749987f029SAmine Khaldi draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i;
2675c2c66affSColin Finck else
26769987f029SAmine Khaldi draw_buffers[i] = GL_NONE;
2677c2c66affSColin Finck
2678c2c66affSColin Finck rt_mask >>= 1;
2679c2c66affSColin Finck ++i;
2680c2c66affSColin Finck }
2681c2c66affSColin Finck
2682c2c66affSColin Finck if (gl_info->supported[ARB_DRAW_BUFFERS])
2683c2c66affSColin Finck {
26849987f029SAmine Khaldi GL_EXTCALL(glDrawBuffers(i, draw_buffers));
2685c2c66affSColin Finck }
2686c2c66affSColin Finck else
2687c2c66affSColin Finck {
26889987f029SAmine Khaldi gl_info->gl_ops.gl.p_glDrawBuffer(draw_buffers[0]);
2689c2c66affSColin Finck }
2690c2c66affSColin Finck }
2691c2c66affSColin Finck else
2692c2c66affSColin Finck {
2693c2c66affSColin Finck ERR("Unexpected draw buffers mask with backbuffer ORM.\n");
2694c2c66affSColin Finck }
2695c2c66affSColin Finck }
26969987f029SAmine Khaldi
26979987f029SAmine Khaldi checkGLcall("apply draw buffers");
2698c2c66affSColin Finck }
2699c2c66affSColin Finck
2700c2c66affSColin Finck /* Context activation is done by the caller. */
context_set_draw_buffer(struct wined3d_context * context,GLenum buffer)2701c2c66affSColin Finck void context_set_draw_buffer(struct wined3d_context *context, GLenum buffer)
2702c2c66affSColin Finck {
2703c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
2704c2c66affSColin Finck DWORD *current_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
2705c2c66affSColin Finck DWORD new_mask = context_generate_rt_mask(buffer);
2706c2c66affSColin Finck
2707c2c66affSColin Finck if (new_mask == *current_mask)
2708c2c66affSColin Finck return;
2709c2c66affSColin Finck
2710c2c66affSColin Finck gl_info->gl_ops.gl.p_glDrawBuffer(buffer);
2711c2c66affSColin Finck checkGLcall("glDrawBuffer()");
2712c2c66affSColin Finck
2713c2c66affSColin Finck *current_mask = new_mask;
2714c2c66affSColin Finck }
2715c2c66affSColin Finck
2716c2c66affSColin Finck /* Context activation is done by the caller. */
context_active_texture(struct wined3d_context * context,const struct wined3d_gl_info * gl_info,unsigned int unit)2717c2c66affSColin Finck void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info, unsigned int unit)
2718c2c66affSColin Finck {
2719c2c66affSColin Finck GL_EXTCALL(glActiveTexture(GL_TEXTURE0 + unit));
2720c2c66affSColin Finck checkGLcall("glActiveTexture");
2721c2c66affSColin Finck context->active_texture = unit;
2722c2c66affSColin Finck }
2723c2c66affSColin Finck
context_bind_bo(struct wined3d_context * context,GLenum binding,GLuint name)2724c2c66affSColin Finck void context_bind_bo(struct wined3d_context *context, GLenum binding, GLuint name)
2725c2c66affSColin Finck {
2726c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
2727c2c66affSColin Finck
2728c2c66affSColin Finck if (binding == GL_ELEMENT_ARRAY_BUFFER)
2729c2c66affSColin Finck context_invalidate_state(context, STATE_INDEXBUFFER);
2730c2c66affSColin Finck
2731c2c66affSColin Finck GL_EXTCALL(glBindBuffer(binding, name));
2732c2c66affSColin Finck }
2733c2c66affSColin Finck
context_bind_texture(struct wined3d_context * context,GLenum target,GLuint name)2734c2c66affSColin Finck void context_bind_texture(struct wined3d_context *context, GLenum target, GLuint name)
2735c2c66affSColin Finck {
27369987f029SAmine Khaldi const struct wined3d_dummy_textures *textures = &context->device->dummy_textures;
2737c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
2738c2c66affSColin Finck DWORD unit = context->active_texture;
2739c2c66affSColin Finck DWORD old_texture_type = context->texture_type[unit];
2740c2c66affSColin Finck
2741c2c66affSColin Finck if (name)
2742c2c66affSColin Finck {
2743c2c66affSColin Finck gl_info->gl_ops.gl.p_glBindTexture(target, name);
2744c2c66affSColin Finck }
2745c2c66affSColin Finck else
2746c2c66affSColin Finck {
2747c2c66affSColin Finck target = GL_NONE;
2748c2c66affSColin Finck }
2749c2c66affSColin Finck
2750c2c66affSColin Finck if (old_texture_type != target)
2751c2c66affSColin Finck {
2752c2c66affSColin Finck switch (old_texture_type)
2753c2c66affSColin Finck {
2754c2c66affSColin Finck case GL_NONE:
2755c2c66affSColin Finck /* nothing to do */
2756c2c66affSColin Finck break;
27579987f029SAmine Khaldi case GL_TEXTURE_1D:
27589987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, textures->tex_1d);
2759*81cffd76SJoachim Henze checkGLcall("glBindTexture");
2760c2c66affSColin Finck break;
27619987f029SAmine Khaldi case GL_TEXTURE_1D_ARRAY:
27629987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D_ARRAY, textures->tex_1d_array);
2763*81cffd76SJoachim Henze checkGLcall("glBindTexture");
27649987f029SAmine Khaldi break;
27659987f029SAmine Khaldi case GL_TEXTURE_2D:
27669987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, textures->tex_2d);
27679987f029SAmine Khaldi break;
2768c2c66affSColin Finck case GL_TEXTURE_2D_ARRAY:
27699987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_ARRAY, textures->tex_2d_array);
2770c2c66affSColin Finck break;
2771c2c66affSColin Finck case GL_TEXTURE_RECTANGLE_ARB:
27729987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textures->tex_rect);
2773c2c66affSColin Finck break;
2774c2c66affSColin Finck case GL_TEXTURE_CUBE_MAP:
27759987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, textures->tex_cube);
2776c2c66affSColin Finck break;
2777c2c66affSColin Finck case GL_TEXTURE_CUBE_MAP_ARRAY:
27789987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, textures->tex_cube_array);
2779c2c66affSColin Finck break;
2780c2c66affSColin Finck case GL_TEXTURE_3D:
27819987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, textures->tex_3d);
2782c2c66affSColin Finck break;
2783c2c66affSColin Finck case GL_TEXTURE_BUFFER:
27849987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_BUFFER, textures->tex_buffer);
27859987f029SAmine Khaldi break;
27869987f029SAmine Khaldi case GL_TEXTURE_2D_MULTISAMPLE:
27879987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textures->tex_2d_ms);
27889987f029SAmine Khaldi break;
27899987f029SAmine Khaldi case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
27909987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, textures->tex_2d_ms_array);
2791c2c66affSColin Finck break;
2792c2c66affSColin Finck default:
2793c2c66affSColin Finck ERR("Unexpected texture target %#x.\n", old_texture_type);
2794c2c66affSColin Finck }
2795c2c66affSColin Finck
2796c2c66affSColin Finck context->texture_type[unit] = target;
2797c2c66affSColin Finck }
27989987f029SAmine Khaldi
27999987f029SAmine Khaldi checkGLcall("bind texture");
2800c2c66affSColin Finck }
2801c2c66affSColin Finck
context_map_bo_address(struct wined3d_context * context,const struct wined3d_bo_address * data,size_t size,GLenum binding,DWORD flags)2802c2c66affSColin Finck void *context_map_bo_address(struct wined3d_context *context,
2803c2c66affSColin Finck const struct wined3d_bo_address *data, size_t size, GLenum binding, DWORD flags)
2804c2c66affSColin Finck {
2805c2c66affSColin Finck const struct wined3d_gl_info *gl_info;
2806c2c66affSColin Finck BYTE *memory;
2807c2c66affSColin Finck
2808c2c66affSColin Finck if (!data->buffer_object)
2809c2c66affSColin Finck return data->addr;
2810c2c66affSColin Finck
2811c2c66affSColin Finck gl_info = context->gl_info;
2812c2c66affSColin Finck context_bind_bo(context, binding, data->buffer_object);
2813c2c66affSColin Finck
2814c2c66affSColin Finck if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
2815c2c66affSColin Finck {
2816c2c66affSColin Finck GLbitfield map_flags = wined3d_resource_gl_map_flags(flags) & ~GL_MAP_FLUSH_EXPLICIT_BIT;
2817c2c66affSColin Finck memory = GL_EXTCALL(glMapBufferRange(binding, (INT_PTR)data->addr, size, map_flags));
2818c2c66affSColin Finck }
2819c2c66affSColin Finck else
2820c2c66affSColin Finck {
2821c2c66affSColin Finck memory = GL_EXTCALL(glMapBuffer(binding, wined3d_resource_gl_legacy_map_flags(flags)));
2822c2c66affSColin Finck memory += (INT_PTR)data->addr;
2823c2c66affSColin Finck }
2824c2c66affSColin Finck
2825c2c66affSColin Finck context_bind_bo(context, binding, 0);
2826c2c66affSColin Finck checkGLcall("Map buffer object");
2827c2c66affSColin Finck
2828c2c66affSColin Finck return memory;
2829c2c66affSColin Finck }
2830c2c66affSColin Finck
context_unmap_bo_address(struct wined3d_context * context,const struct wined3d_bo_address * data,GLenum binding)2831c2c66affSColin Finck void context_unmap_bo_address(struct wined3d_context *context,
2832c2c66affSColin Finck const struct wined3d_bo_address *data, GLenum binding)
2833c2c66affSColin Finck {
2834c2c66affSColin Finck const struct wined3d_gl_info *gl_info;
2835c2c66affSColin Finck
2836c2c66affSColin Finck if (!data->buffer_object)
2837c2c66affSColin Finck return;
2838c2c66affSColin Finck
2839c2c66affSColin Finck gl_info = context->gl_info;
2840c2c66affSColin Finck context_bind_bo(context, binding, data->buffer_object);
2841c2c66affSColin Finck GL_EXTCALL(glUnmapBuffer(binding));
2842c2c66affSColin Finck context_bind_bo(context, binding, 0);
2843c2c66affSColin Finck checkGLcall("Unmap buffer object");
2844c2c66affSColin Finck }
2845c2c66affSColin Finck
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)2846c2c66affSColin Finck void context_copy_bo_address(struct wined3d_context *context,
2847c2c66affSColin Finck const struct wined3d_bo_address *dst, GLenum dst_binding,
2848c2c66affSColin Finck const struct wined3d_bo_address *src, GLenum src_binding, size_t size)
2849c2c66affSColin Finck {
2850c2c66affSColin Finck const struct wined3d_gl_info *gl_info;
2851c2c66affSColin Finck BYTE *dst_ptr, *src_ptr;
2852c2c66affSColin Finck
2853c2c66affSColin Finck gl_info = context->gl_info;
2854c2c66affSColin Finck
2855c2c66affSColin Finck if (dst->buffer_object && src->buffer_object)
2856c2c66affSColin Finck {
2857c2c66affSColin Finck if (gl_info->supported[ARB_COPY_BUFFER])
2858c2c66affSColin Finck {
2859c2c66affSColin Finck GL_EXTCALL(glBindBuffer(GL_COPY_READ_BUFFER, src->buffer_object));
2860c2c66affSColin Finck GL_EXTCALL(glBindBuffer(GL_COPY_WRITE_BUFFER, dst->buffer_object));
2861c2c66affSColin Finck GL_EXTCALL(glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
2862c2c66affSColin Finck (GLintptr)src->addr, (GLintptr)dst->addr, size));
2863c2c66affSColin Finck checkGLcall("direct buffer copy");
2864c2c66affSColin Finck }
2865c2c66affSColin Finck else
2866c2c66affSColin Finck {
28679987f029SAmine Khaldi src_ptr = context_map_bo_address(context, src, size, src_binding, WINED3D_MAP_READ);
28689987f029SAmine Khaldi dst_ptr = context_map_bo_address(context, dst, size, dst_binding, WINED3D_MAP_WRITE);
2869c2c66affSColin Finck
2870c2c66affSColin Finck memcpy(dst_ptr, src_ptr, size);
2871c2c66affSColin Finck
2872c2c66affSColin Finck context_unmap_bo_address(context, dst, dst_binding);
2873c2c66affSColin Finck context_unmap_bo_address(context, src, src_binding);
2874c2c66affSColin Finck }
2875c2c66affSColin Finck }
2876c2c66affSColin Finck else if (!dst->buffer_object && src->buffer_object)
2877c2c66affSColin Finck {
2878c2c66affSColin Finck context_bind_bo(context, src_binding, src->buffer_object);
2879c2c66affSColin Finck GL_EXTCALL(glGetBufferSubData(src_binding, (GLintptr)src->addr, size, dst->addr));
2880c2c66affSColin Finck checkGLcall("buffer download");
2881c2c66affSColin Finck }
2882c2c66affSColin Finck else if (dst->buffer_object && !src->buffer_object)
2883c2c66affSColin Finck {
2884c2c66affSColin Finck context_bind_bo(context, dst_binding, dst->buffer_object);
2885c2c66affSColin Finck GL_EXTCALL(glBufferSubData(dst_binding, (GLintptr)dst->addr, size, src->addr));
2886c2c66affSColin Finck checkGLcall("buffer upload");
2887c2c66affSColin Finck }
2888c2c66affSColin Finck else
2889c2c66affSColin Finck {
2890c2c66affSColin Finck memcpy(dst->addr, src->addr, size);
2891c2c66affSColin Finck }
2892c2c66affSColin Finck }
2893c2c66affSColin Finck
context_set_render_offscreen(struct wined3d_context * context,BOOL offscreen)2894c2c66affSColin Finck static void context_set_render_offscreen(struct wined3d_context *context, BOOL offscreen)
2895c2c66affSColin Finck {
2896c2c66affSColin Finck if (context->render_offscreen == offscreen)
2897c2c66affSColin Finck return;
2898c2c66affSColin Finck
2899c2c66affSColin Finck context_invalidate_state(context, STATE_VIEWPORT);
2900c2c66affSColin Finck context_invalidate_state(context, STATE_SCISSORRECT);
2901c2c66affSColin Finck if (!context->gl_info->supported[ARB_CLIP_CONTROL])
2902c2c66affSColin Finck {
2903*81cffd76SJoachim Henze context_invalidate_state(context, STATE_FRONTFACE);
2904c2c66affSColin Finck context_invalidate_state(context, STATE_POINTSPRITECOORDORIGIN);
2905c2c66affSColin Finck context_invalidate_state(context, STATE_TRANSFORM(WINED3D_TS_PROJECTION));
2906c2c66affSColin Finck }
2907c2c66affSColin Finck context_invalidate_state(context, STATE_SHADER(WINED3D_SHADER_TYPE_DOMAIN));
2908c2c66affSColin Finck if (context->gl_info->supported[ARB_FRAGMENT_COORD_CONVENTIONS])
2909c2c66affSColin Finck context_invalidate_state(context, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
2910c2c66affSColin Finck context->render_offscreen = offscreen;
2911c2c66affSColin Finck }
2912c2c66affSColin Finck
match_depth_stencil_format(const struct wined3d_format * existing,const struct wined3d_format * required)2913c2c66affSColin Finck static BOOL match_depth_stencil_format(const struct wined3d_format *existing,
2914c2c66affSColin Finck const struct wined3d_format *required)
2915c2c66affSColin Finck {
2916c2c66affSColin Finck if (existing == required)
2917c2c66affSColin Finck return TRUE;
2918c2c66affSColin Finck if ((existing->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FLOAT)
2919c2c66affSColin Finck != (required->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FLOAT))
2920c2c66affSColin Finck return FALSE;
2921c2c66affSColin Finck if (existing->depth_size < required->depth_size)
2922c2c66affSColin Finck return FALSE;
2923c2c66affSColin Finck /* If stencil bits are used the exact amount is required - otherwise
2924c2c66affSColin Finck * wrapping won't work correctly. */
2925c2c66affSColin Finck if (required->stencil_size && required->stencil_size != existing->stencil_size)
2926c2c66affSColin Finck return FALSE;
2927c2c66affSColin Finck return TRUE;
2928c2c66affSColin Finck }
2929c2c66affSColin Finck
2930c2c66affSColin Finck /* Context activation is done by the caller. */
context_validate_onscreen_formats(struct wined3d_context * context,const struct wined3d_rendertarget_view * depth_stencil)2931c2c66affSColin Finck static void context_validate_onscreen_formats(struct wined3d_context *context,
2932c2c66affSColin Finck const struct wined3d_rendertarget_view *depth_stencil)
2933c2c66affSColin Finck {
2934c2c66affSColin Finck /* Onscreen surfaces are always in a swapchain */
2935c2c66affSColin Finck struct wined3d_swapchain *swapchain = context->current_rt.texture->swapchain;
2936c2c66affSColin Finck
2937c2c66affSColin Finck if (context->render_offscreen || !depth_stencil) return;
2938c2c66affSColin Finck if (match_depth_stencil_format(swapchain->ds_format, depth_stencil->format)) return;
2939c2c66affSColin Finck
2940c2c66affSColin Finck /* TODO: If the requested format would satisfy the needs of the existing one(reverse match),
2941c2c66affSColin Finck * or no onscreen depth buffer was created, the OpenGL drawable could be changed to the new
2942c2c66affSColin Finck * format. */
2943c2c66affSColin Finck WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
2944c2c66affSColin Finck
2945c2c66affSColin Finck /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
2946c2c66affSColin Finck if (!(wined3d_texture_load_location(context->current_rt.texture, context->current_rt.sub_resource_idx,
2947c2c66affSColin Finck context, WINED3D_LOCATION_TEXTURE_RGB)))
2948c2c66affSColin Finck ERR("Failed to load location.\n");
2949c2c66affSColin Finck swapchain->render_to_fbo = TRUE;
2950c2c66affSColin Finck swapchain_update_draw_bindings(swapchain);
2951c2c66affSColin Finck context_set_render_offscreen(context, TRUE);
2952c2c66affSColin Finck }
2953c2c66affSColin Finck
context_get_offscreen_gl_buffer(const struct wined3d_context * context)2954c2c66affSColin Finck GLenum context_get_offscreen_gl_buffer(const struct wined3d_context *context)
2955c2c66affSColin Finck {
2956c2c66affSColin Finck switch (wined3d_settings.offscreen_rendering_mode)
2957c2c66affSColin Finck {
2958c2c66affSColin Finck case ORM_FBO:
2959c2c66affSColin Finck return GL_COLOR_ATTACHMENT0;
2960c2c66affSColin Finck
2961c2c66affSColin Finck case ORM_BACKBUFFER:
2962c2c66affSColin Finck return context->aux_buffers > 0 ? GL_AUX0 : GL_BACK;
2963c2c66affSColin Finck
2964c2c66affSColin Finck default:
2965c2c66affSColin Finck FIXME("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
2966c2c66affSColin Finck return GL_BACK;
2967c2c66affSColin Finck }
2968c2c66affSColin Finck }
2969c2c66affSColin Finck
context_generate_rt_mask_no_fbo(const struct wined3d_context * context,struct wined3d_texture * rt)2970*81cffd76SJoachim Henze static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_context *context, struct wined3d_texture *rt)
2971c2c66affSColin Finck {
2972*81cffd76SJoachim Henze if (!rt || rt->resource.format->id == WINED3DFMT_NULL)
2973c2c66affSColin Finck return 0;
2974*81cffd76SJoachim Henze else if (rt->swapchain)
2975*81cffd76SJoachim Henze return context_generate_rt_mask_from_resource(&rt->resource);
2976c2c66affSColin Finck else
2977c2c66affSColin Finck return context_generate_rt_mask(context_get_offscreen_gl_buffer(context));
2978c2c66affSColin Finck }
2979c2c66affSColin Finck
2980c2c66affSColin Finck /* Context activation is done by the caller. */
context_apply_blit_state(struct wined3d_context * context,const struct wined3d_device * device)2981c2c66affSColin Finck void context_apply_blit_state(struct wined3d_context *context, const struct wined3d_device *device)
2982c2c66affSColin Finck {
2983c2c66affSColin Finck struct wined3d_texture *rt = context->current_rt.texture;
2984*81cffd76SJoachim Henze struct wined3d_surface *surface;
2985c2c66affSColin Finck DWORD rt_mask, *cur_mask;
2986c2c66affSColin Finck
2987c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
2988c2c66affSColin Finck {
2989c2c66affSColin Finck if (context->render_offscreen)
2990c2c66affSColin Finck {
2991c2c66affSColin Finck wined3d_texture_load(rt, context, FALSE);
2992c2c66affSColin Finck
2993*81cffd76SJoachim Henze surface = rt->sub_resources[context->current_rt.sub_resource_idx].u.surface;
2994*81cffd76SJoachim Henze context_apply_fbo_state_blit(context, GL_FRAMEBUFFER, surface, NULL, rt->resource.draw_binding);
2995c2c66affSColin Finck if (rt->resource.format->id != WINED3DFMT_NULL)
2996c2c66affSColin Finck rt_mask = 1;
2997c2c66affSColin Finck else
2998c2c66affSColin Finck rt_mask = 0;
2999c2c66affSColin Finck }
3000c2c66affSColin Finck else
3001c2c66affSColin Finck {
3002c2c66affSColin Finck context->current_fbo = NULL;
3003c2c66affSColin Finck context_bind_fbo(context, GL_FRAMEBUFFER, 0);
3004c2c66affSColin Finck rt_mask = context_generate_rt_mask_from_resource(&rt->resource);
3005c2c66affSColin Finck }
3006c2c66affSColin Finck }
3007c2c66affSColin Finck else
3008c2c66affSColin Finck {
3009*81cffd76SJoachim Henze rt_mask = context_generate_rt_mask_no_fbo(context, rt);
3010c2c66affSColin Finck }
3011c2c66affSColin Finck
3012c2c66affSColin Finck cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3013c2c66affSColin Finck
3014c2c66affSColin Finck if (rt_mask != *cur_mask)
3015c2c66affSColin Finck {
3016c2c66affSColin Finck context_apply_draw_buffers(context, rt_mask);
3017c2c66affSColin Finck *cur_mask = rt_mask;
3018c2c66affSColin Finck }
3019c2c66affSColin Finck
3020c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3021c2c66affSColin Finck {
3022c2c66affSColin Finck context_check_fbo_status(context, GL_FRAMEBUFFER);
3023c2c66affSColin Finck }
3024*81cffd76SJoachim Henze
3025*81cffd76SJoachim Henze SetupForBlit(device, context);
3026c2c66affSColin Finck context_invalidate_state(context, STATE_FRAMEBUFFER);
3027c2c66affSColin Finck }
3028c2c66affSColin Finck
have_framebuffer_attachment(unsigned int rt_count,struct wined3d_rendertarget_view * const * rts,const struct wined3d_rendertarget_view * ds)30299987f029SAmine Khaldi static BOOL have_framebuffer_attachment(unsigned int rt_count, struct wined3d_rendertarget_view * const *rts,
3030c2c66affSColin Finck const struct wined3d_rendertarget_view *ds)
3031c2c66affSColin Finck {
3032c2c66affSColin Finck unsigned int i;
3033c2c66affSColin Finck
30349987f029SAmine Khaldi if (ds)
30359987f029SAmine Khaldi return TRUE;
3036c2c66affSColin Finck
3037c2c66affSColin Finck for (i = 0; i < rt_count; ++i)
3038c2c66affSColin Finck {
3039c2c66affSColin Finck if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
3040c2c66affSColin Finck return TRUE;
3041c2c66affSColin Finck }
3042c2c66affSColin Finck
3043c2c66affSColin Finck return FALSE;
3044c2c66affSColin Finck }
3045c2c66affSColin Finck
3046c2c66affSColin Finck /* 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)3047c2c66affSColin Finck BOOL context_apply_clear_state(struct wined3d_context *context, const struct wined3d_state *state,
3048c2c66affSColin Finck UINT rt_count, const struct wined3d_fb_state *fb)
3049c2c66affSColin Finck {
30509987f029SAmine Khaldi struct wined3d_rendertarget_view * const *rts = fb->render_targets;
3051c2c66affSColin Finck struct wined3d_rendertarget_view *dsv = fb->depth_stencil;
3052c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
3053c2c66affSColin Finck DWORD rt_mask = 0, *cur_mask;
3054c2c66affSColin Finck unsigned int i;
3055c2c66affSColin Finck
3056c2c66affSColin Finck if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != state->fb
3057c2c66affSColin Finck || rt_count != gl_info->limits.buffers)
3058c2c66affSColin Finck {
30599987f029SAmine Khaldi if (!have_framebuffer_attachment(rt_count, rts, dsv))
30609987f029SAmine Khaldi {
30619987f029SAmine Khaldi WARN("Invalid render target config, need at least one attachment.\n");
3062c2c66affSColin Finck return FALSE;
30639987f029SAmine Khaldi }
3064c2c66affSColin Finck
3065c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3066c2c66affSColin Finck {
3067c2c66affSColin Finck context_validate_onscreen_formats(context, dsv);
3068c2c66affSColin Finck
3069c2c66affSColin Finck if (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource))
3070c2c66affSColin Finck {
30719987f029SAmine Khaldi memset(context->blit_targets, 0, sizeof(context->blit_targets));
3072c2c66affSColin Finck for (i = 0; i < rt_count; ++i)
3073c2c66affSColin Finck {
3074c2c66affSColin Finck if (rts[i])
3075c2c66affSColin Finck {
3076c2c66affSColin Finck context->blit_targets[i].gl_view = rts[i]->gl_view;
3077c2c66affSColin Finck context->blit_targets[i].resource = rts[i]->resource;
3078c2c66affSColin Finck context->blit_targets[i].sub_resource_idx = rts[i]->sub_resource_idx;
3079c2c66affSColin Finck context->blit_targets[i].layer_count = rts[i]->layer_count;
3080c2c66affSColin Finck }
3081c2c66affSColin Finck if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
3082c2c66affSColin Finck rt_mask |= (1u << i);
3083c2c66affSColin Finck }
3084*81cffd76SJoachim Henze context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets,
3085*81cffd76SJoachim Henze wined3d_rendertarget_view_get_surface(dsv),
3086c2c66affSColin Finck rt_count ? rts[0]->resource->draw_binding : 0,
3087c2c66affSColin Finck dsv ? dsv->resource->draw_binding : 0);
3088c2c66affSColin Finck }
3089c2c66affSColin Finck else
3090c2c66affSColin Finck {
3091*81cffd76SJoachim Henze context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL,
3092c2c66affSColin Finck WINED3D_LOCATION_DRAWABLE, WINED3D_LOCATION_DRAWABLE);
3093c2c66affSColin Finck rt_mask = context_generate_rt_mask_from_resource(rts[0]->resource);
3094c2c66affSColin Finck }
3095c2c66affSColin Finck
3096c2c66affSColin Finck /* If the framebuffer is not the device's fb the device's fb has to be reapplied
3097c2c66affSColin Finck * next draw. Otherwise we could mark the framebuffer state clean here, once the
3098c2c66affSColin Finck * state management allows this */
3099c2c66affSColin Finck context_invalidate_state(context, STATE_FRAMEBUFFER);
3100c2c66affSColin Finck }
3101c2c66affSColin Finck else
3102c2c66affSColin Finck {
3103*81cffd76SJoachim Henze rt_mask = context_generate_rt_mask_no_fbo(context,
3104*81cffd76SJoachim Henze rt_count ? wined3d_rendertarget_view_get_surface(rts[0])->container : NULL);
3105c2c66affSColin Finck }
3106c2c66affSColin Finck }
3107c2c66affSColin Finck else if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3108c2c66affSColin Finck && (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource)))
3109c2c66affSColin Finck {
3110c2c66affSColin Finck for (i = 0; i < rt_count; ++i)
3111c2c66affSColin Finck {
3112c2c66affSColin Finck if (rts[i] && rts[i]->format->id != WINED3DFMT_NULL)
3113c2c66affSColin Finck rt_mask |= (1u << i);
3114c2c66affSColin Finck }
3115c2c66affSColin Finck }
3116c2c66affSColin Finck else
3117c2c66affSColin Finck {
3118*81cffd76SJoachim Henze rt_mask = context_generate_rt_mask_no_fbo(context,
3119*81cffd76SJoachim Henze rt_count ? wined3d_rendertarget_view_get_surface(rts[0])->container : NULL);
3120c2c66affSColin Finck }
3121c2c66affSColin Finck
3122c2c66affSColin Finck cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3123c2c66affSColin Finck
3124c2c66affSColin Finck if (rt_mask != *cur_mask)
3125c2c66affSColin Finck {
3126c2c66affSColin Finck context_apply_draw_buffers(context, rt_mask);
3127c2c66affSColin Finck *cur_mask = rt_mask;
3128c2c66affSColin Finck context_invalidate_state(context, STATE_FRAMEBUFFER);
3129c2c66affSColin Finck }
3130c2c66affSColin Finck
3131c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3132c2c66affSColin Finck {
3133c2c66affSColin Finck context_check_fbo_status(context, GL_FRAMEBUFFER);
3134c2c66affSColin Finck }
3135c2c66affSColin Finck
3136c2c66affSColin Finck context->last_was_blit = FALSE;
3137c2c66affSColin Finck
3138c2c66affSColin Finck /* Blending and clearing should be orthogonal, but tests on the nvidia
3139c2c66affSColin Finck * driver show that disabling blending when clearing improves the clearing
3140c2c66affSColin Finck * performance incredibly. */
3141c2c66affSColin Finck gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
3142c2c66affSColin Finck gl_info->gl_ops.gl.p_glEnable(GL_SCISSOR_TEST);
3143c2c66affSColin Finck if (rt_count && gl_info->supported[ARB_FRAMEBUFFER_SRGB])
3144c2c66affSColin Finck {
3145c2c66affSColin Finck if (needs_srgb_write(context, state, fb))
3146c2c66affSColin Finck gl_info->gl_ops.gl.p_glEnable(GL_FRAMEBUFFER_SRGB);
3147c2c66affSColin Finck else
3148c2c66affSColin Finck gl_info->gl_ops.gl.p_glDisable(GL_FRAMEBUFFER_SRGB);
3149c2c66affSColin Finck context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
3150c2c66affSColin Finck }
3151c2c66affSColin Finck checkGLcall("setting up state for clear");
3152c2c66affSColin Finck
3153c2c66affSColin Finck context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
3154c2c66affSColin Finck context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
3155c2c66affSColin Finck context_invalidate_state(context, STATE_SCISSORRECT);
3156c2c66affSColin Finck
3157c2c66affSColin Finck return TRUE;
3158c2c66affSColin Finck }
3159c2c66affSColin Finck
find_draw_buffers_mask(const struct wined3d_context * context,const struct wined3d_state * state)3160c2c66affSColin Finck static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_state *state)
3161c2c66affSColin Finck {
31629987f029SAmine Khaldi struct wined3d_rendertarget_view * const *rts = state->fb->render_targets;
3163c2c66affSColin Finck struct wined3d_shader *ps = state->shader[WINED3D_SHADER_TYPE_PIXEL];
31649987f029SAmine Khaldi DWORD rt_mask, mask;
3165c2c66affSColin Finck unsigned int i;
3166c2c66affSColin Finck
3167c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode != ORM_FBO)
3168*81cffd76SJoachim Henze return context_generate_rt_mask_no_fbo(context, wined3d_rendertarget_view_get_surface(rts[0])->container);
3169c2c66affSColin Finck else if (!context->render_offscreen)
3170c2c66affSColin Finck return context_generate_rt_mask_from_resource(rts[0]->resource);
3171c2c66affSColin Finck
31729987f029SAmine Khaldi /* If we attach more buffers than supported in dual blend mode, the NVIDIA
31739987f029SAmine Khaldi * driver generates the following error:
31749987f029SAmine Khaldi * GL_INVALID_OPERATION error generated. State(s) are invalid: blend.
31759987f029SAmine Khaldi * DX11 does not treat this configuration as invalid, so disable the unused ones.
31769987f029SAmine Khaldi */
3177c2c66affSColin Finck rt_mask = ps ? ps->reg_maps.rt_mask : 1;
31789987f029SAmine Khaldi if (wined3d_dualblend_enabled(state, context->gl_info))
31799987f029SAmine Khaldi rt_mask &= context->d3d_info->valid_dual_rt_mask;
31809987f029SAmine Khaldi else
3181c2c66affSColin Finck rt_mask &= context->d3d_info->valid_rt_mask;
31829987f029SAmine Khaldi
31839987f029SAmine Khaldi mask = rt_mask;
3184c2c66affSColin Finck i = 0;
31859987f029SAmine Khaldi while (mask)
3186c2c66affSColin Finck {
31879987f029SAmine Khaldi i = wined3d_bit_scan(&mask);
3188c2c66affSColin Finck if (!rts[i] || rts[i]->format->id == WINED3DFMT_NULL)
3189c2c66affSColin Finck rt_mask &= ~(1u << i);
3190c2c66affSColin Finck }
3191c2c66affSColin Finck
3192c2c66affSColin Finck return rt_mask;
3193c2c66affSColin Finck }
3194c2c66affSColin Finck
3195c2c66affSColin Finck /* Context activation is done by the caller. */
context_state_fb(struct wined3d_context * context,const struct wined3d_state * state,DWORD state_id)3196c2c66affSColin Finck void context_state_fb(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
3197c2c66affSColin Finck {
3198c2c66affSColin Finck DWORD rt_mask = find_draw_buffers_mask(context, state);
3199c2c66affSColin Finck const struct wined3d_fb_state *fb = state->fb;
32009987f029SAmine Khaldi DWORD color_location = 0;
3201c2c66affSColin Finck DWORD *cur_mask;
3202c2c66affSColin Finck
3203c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3204c2c66affSColin Finck {
3205c2c66affSColin Finck if (!context->render_offscreen)
3206c2c66affSColin Finck {
3207*81cffd76SJoachim Henze context_apply_fbo_state(context, GL_FRAMEBUFFER, NULL, NULL,
3208c2c66affSColin Finck WINED3D_LOCATION_DRAWABLE, WINED3D_LOCATION_DRAWABLE);
3209c2c66affSColin Finck }
3210c2c66affSColin Finck else
3211c2c66affSColin Finck {
3212c2c66affSColin Finck unsigned int i;
3213c2c66affSColin Finck
32149987f029SAmine Khaldi memset(context->blit_targets, 0, sizeof(context->blit_targets));
3215c2c66affSColin Finck for (i = 0; i < context->gl_info->limits.buffers; ++i)
3216c2c66affSColin Finck {
32179987f029SAmine Khaldi if (!fb->render_targets[i])
32189987f029SAmine Khaldi continue;
32199987f029SAmine Khaldi
3220c2c66affSColin Finck context->blit_targets[i].gl_view = fb->render_targets[i]->gl_view;
3221c2c66affSColin Finck context->blit_targets[i].resource = fb->render_targets[i]->resource;
3222c2c66affSColin Finck context->blit_targets[i].sub_resource_idx = fb->render_targets[i]->sub_resource_idx;
3223c2c66affSColin Finck context->blit_targets[i].layer_count = fb->render_targets[i]->layer_count;
32249987f029SAmine Khaldi
32259987f029SAmine Khaldi if (!color_location)
32269987f029SAmine Khaldi color_location = fb->render_targets[i]->resource->draw_binding;
3227c2c66affSColin Finck }
3228*81cffd76SJoachim Henze context_apply_fbo_state(context, GL_FRAMEBUFFER, context->blit_targets,
3229*81cffd76SJoachim Henze wined3d_rendertarget_view_get_surface(fb->depth_stencil),
32309987f029SAmine Khaldi color_location, fb->depth_stencil ? fb->depth_stencil->resource->draw_binding : 0);
3231c2c66affSColin Finck }
3232c2c66affSColin Finck }
3233c2c66affSColin Finck
3234c2c66affSColin Finck cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3235c2c66affSColin Finck if (rt_mask != *cur_mask)
3236c2c66affSColin Finck {
3237c2c66affSColin Finck context_apply_draw_buffers(context, rt_mask);
3238c2c66affSColin Finck *cur_mask = rt_mask;
3239c2c66affSColin Finck }
3240c2c66affSColin Finck context->constant_update_mask |= WINED3D_SHADER_CONST_PS_Y_CORR;
3241c2c66affSColin Finck }
3242c2c66affSColin Finck
context_map_stage(struct wined3d_context * context,DWORD stage,DWORD unit)3243c2c66affSColin Finck static void context_map_stage(struct wined3d_context *context, DWORD stage, DWORD unit)
3244c2c66affSColin Finck {
3245c2c66affSColin Finck DWORD i = context->rev_tex_unit_map[unit];
3246c2c66affSColin Finck DWORD j = context->tex_unit_map[stage];
3247c2c66affSColin Finck
3248c2c66affSColin Finck TRACE("Mapping stage %u to unit %u.\n", stage, unit);
3249c2c66affSColin Finck context->tex_unit_map[stage] = unit;
3250c2c66affSColin Finck if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3251c2c66affSColin Finck context->tex_unit_map[i] = WINED3D_UNMAPPED_STAGE;
3252c2c66affSColin Finck
3253c2c66affSColin Finck context->rev_tex_unit_map[unit] = stage;
3254c2c66affSColin Finck if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3255c2c66affSColin Finck context->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3256c2c66affSColin Finck }
3257c2c66affSColin Finck
context_invalidate_texture_stage(struct wined3d_context * context,DWORD stage)3258c2c66affSColin Finck static void context_invalidate_texture_stage(struct wined3d_context *context, DWORD stage)
3259c2c66affSColin Finck {
3260c2c66affSColin Finck DWORD i;
3261c2c66affSColin Finck
3262c2c66affSColin Finck for (i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3263c2c66affSColin Finck context_invalidate_state(context, STATE_TEXTURESTAGE(stage, i));
3264c2c66affSColin Finck }
3265c2c66affSColin Finck
context_update_fixed_function_usage_map(struct wined3d_context * context,const struct wined3d_state * state)3266c2c66affSColin Finck static void context_update_fixed_function_usage_map(struct wined3d_context *context,
3267c2c66affSColin Finck const struct wined3d_state *state)
3268c2c66affSColin Finck {
3269c2c66affSColin Finck UINT i, start, end;
3270c2c66affSColin Finck
3271c2c66affSColin Finck context->fixed_function_usage_map = 0;
3272c2c66affSColin Finck for (i = 0; i < MAX_TEXTURES; ++i)
3273c2c66affSColin Finck {
3274c2c66affSColin Finck enum wined3d_texture_op color_op = state->texture_states[i][WINED3D_TSS_COLOR_OP];
3275c2c66affSColin Finck enum wined3d_texture_op alpha_op = state->texture_states[i][WINED3D_TSS_ALPHA_OP];
3276c2c66affSColin Finck DWORD color_arg1 = state->texture_states[i][WINED3D_TSS_COLOR_ARG1] & WINED3DTA_SELECTMASK;
3277c2c66affSColin Finck DWORD color_arg2 = state->texture_states[i][WINED3D_TSS_COLOR_ARG2] & WINED3DTA_SELECTMASK;
3278c2c66affSColin Finck DWORD color_arg3 = state->texture_states[i][WINED3D_TSS_COLOR_ARG0] & WINED3DTA_SELECTMASK;
3279c2c66affSColin Finck DWORD alpha_arg1 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG1] & WINED3DTA_SELECTMASK;
3280c2c66affSColin Finck DWORD alpha_arg2 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG2] & WINED3DTA_SELECTMASK;
3281c2c66affSColin Finck DWORD alpha_arg3 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG0] & WINED3DTA_SELECTMASK;
3282c2c66affSColin Finck
3283c2c66affSColin Finck /* Not used, and disable higher stages. */
3284c2c66affSColin Finck if (color_op == WINED3D_TOP_DISABLE)
3285c2c66affSColin Finck break;
3286c2c66affSColin Finck
3287c2c66affSColin Finck if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG2)
3288c2c66affSColin Finck || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG1)
3289c2c66affSColin Finck || ((color_arg3 == WINED3DTA_TEXTURE)
3290c2c66affSColin Finck && (color_op == WINED3D_TOP_MULTIPLY_ADD || color_op == WINED3D_TOP_LERP))
3291c2c66affSColin Finck || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG2)
3292c2c66affSColin Finck || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG1)
3293c2c66affSColin Finck || ((alpha_arg3 == WINED3DTA_TEXTURE)
3294c2c66affSColin Finck && (alpha_op == WINED3D_TOP_MULTIPLY_ADD || alpha_op == WINED3D_TOP_LERP)))
3295c2c66affSColin Finck context->fixed_function_usage_map |= (1u << i);
3296c2c66affSColin Finck
3297c2c66affSColin Finck if ((color_op == WINED3D_TOP_BUMPENVMAP || color_op == WINED3D_TOP_BUMPENVMAP_LUMINANCE)
3298c2c66affSColin Finck && i < MAX_TEXTURES - 1)
3299c2c66affSColin Finck context->fixed_function_usage_map |= (1u << (i + 1));
3300c2c66affSColin Finck }
3301c2c66affSColin Finck
3302c2c66affSColin Finck if (i < context->lowest_disabled_stage)
3303c2c66affSColin Finck {
3304c2c66affSColin Finck start = i;
3305c2c66affSColin Finck end = context->lowest_disabled_stage;
3306c2c66affSColin Finck }
3307c2c66affSColin Finck else
3308c2c66affSColin Finck {
3309c2c66affSColin Finck start = context->lowest_disabled_stage;
3310c2c66affSColin Finck end = i;
3311c2c66affSColin Finck }
3312c2c66affSColin Finck
3313c2c66affSColin Finck context->lowest_disabled_stage = i;
3314c2c66affSColin Finck for (i = start + 1; i < end; ++i)
3315c2c66affSColin Finck {
3316c2c66affSColin Finck context_invalidate_state(context, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3317c2c66affSColin Finck }
3318c2c66affSColin Finck }
3319c2c66affSColin Finck
context_map_fixed_function_samplers(struct wined3d_context * context,const struct wined3d_state * state)3320c2c66affSColin Finck static void context_map_fixed_function_samplers(struct wined3d_context *context,
3321c2c66affSColin Finck const struct wined3d_state *state)
3322c2c66affSColin Finck {
3323c2c66affSColin Finck const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3324c2c66affSColin Finck unsigned int i, tex;
3325c2c66affSColin Finck WORD ffu_map;
3326c2c66affSColin Finck
3327c2c66affSColin Finck ffu_map = context->fixed_function_usage_map;
3328c2c66affSColin Finck
3329c2c66affSColin Finck if (d3d_info->limits.ffp_textures == d3d_info->limits.ffp_blend_stages
3330c2c66affSColin Finck || context->lowest_disabled_stage <= d3d_info->limits.ffp_textures)
3331c2c66affSColin Finck {
3332c2c66affSColin Finck for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3333c2c66affSColin Finck {
3334c2c66affSColin Finck if (!(ffu_map & 1))
3335c2c66affSColin Finck continue;
3336c2c66affSColin Finck
3337c2c66affSColin Finck if (context->tex_unit_map[i] != i)
3338c2c66affSColin Finck {
3339c2c66affSColin Finck context_map_stage(context, i, i);
3340c2c66affSColin Finck context_invalidate_state(context, STATE_SAMPLER(i));
3341c2c66affSColin Finck context_invalidate_texture_stage(context, i);
3342c2c66affSColin Finck }
3343c2c66affSColin Finck }
3344c2c66affSColin Finck return;
3345c2c66affSColin Finck }
3346c2c66affSColin Finck
3347c2c66affSColin Finck /* Now work out the mapping */
3348c2c66affSColin Finck tex = 0;
3349c2c66affSColin Finck for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3350c2c66affSColin Finck {
3351c2c66affSColin Finck if (!(ffu_map & 1))
3352c2c66affSColin Finck continue;
3353c2c66affSColin Finck
3354c2c66affSColin Finck if (context->tex_unit_map[i] != tex)
3355c2c66affSColin Finck {
3356c2c66affSColin Finck context_map_stage(context, i, tex);
3357c2c66affSColin Finck context_invalidate_state(context, STATE_SAMPLER(i));
3358c2c66affSColin Finck context_invalidate_texture_stage(context, i);
3359c2c66affSColin Finck }
3360c2c66affSColin Finck
3361c2c66affSColin Finck ++tex;
3362c2c66affSColin Finck }
3363c2c66affSColin Finck }
3364c2c66affSColin Finck
context_map_psamplers(struct wined3d_context * context,const struct wined3d_state * state)3365c2c66affSColin Finck static void context_map_psamplers(struct wined3d_context *context, const struct wined3d_state *state)
3366c2c66affSColin Finck {
3367c2c66affSColin Finck const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3368c2c66affSColin Finck const struct wined3d_shader_resource_info *resource_info =
3369c2c66affSColin Finck state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info;
3370c2c66affSColin Finck unsigned int i;
3371c2c66affSColin Finck
3372c2c66affSColin Finck for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
3373c2c66affSColin Finck {
3374c2c66affSColin Finck if (resource_info[i].type && context->tex_unit_map[i] != i)
3375c2c66affSColin Finck {
3376c2c66affSColin Finck context_map_stage(context, i, i);
3377c2c66affSColin Finck context_invalidate_state(context, STATE_SAMPLER(i));
3378c2c66affSColin Finck if (i < d3d_info->limits.ffp_blend_stages)
3379c2c66affSColin Finck context_invalidate_texture_stage(context, i);
3380c2c66affSColin Finck }
3381c2c66affSColin Finck }
3382c2c66affSColin Finck }
3383c2c66affSColin Finck
context_unit_free_for_vs(const struct wined3d_context * context,const struct wined3d_shader_resource_info * ps_resource_info,DWORD unit)3384c2c66affSColin Finck static BOOL context_unit_free_for_vs(const struct wined3d_context *context,
3385c2c66affSColin Finck const struct wined3d_shader_resource_info *ps_resource_info, DWORD unit)
3386c2c66affSColin Finck {
3387c2c66affSColin Finck DWORD current_mapping = context->rev_tex_unit_map[unit];
3388c2c66affSColin Finck
3389c2c66affSColin Finck /* Not currently used */
3390c2c66affSColin Finck if (current_mapping == WINED3D_UNMAPPED_STAGE)
3391c2c66affSColin Finck return TRUE;
3392c2c66affSColin Finck
3393c2c66affSColin Finck if (current_mapping < MAX_FRAGMENT_SAMPLERS)
3394c2c66affSColin Finck {
3395c2c66affSColin Finck /* Used by a fragment sampler */
3396c2c66affSColin Finck
3397c2c66affSColin Finck if (!ps_resource_info)
3398c2c66affSColin Finck {
3399c2c66affSColin Finck /* No pixel shader, check fixed function */
3400c2c66affSColin Finck return current_mapping >= MAX_TEXTURES || !(context->fixed_function_usage_map & (1u << current_mapping));
3401c2c66affSColin Finck }
3402c2c66affSColin Finck
3403c2c66affSColin Finck /* Pixel shader, check the shader's sampler map */
3404c2c66affSColin Finck return !ps_resource_info[current_mapping].type;
3405c2c66affSColin Finck }
3406c2c66affSColin Finck
3407c2c66affSColin Finck return TRUE;
3408c2c66affSColin Finck }
3409c2c66affSColin Finck
context_map_vsamplers(struct wined3d_context * context,BOOL ps,const struct wined3d_state * state)3410c2c66affSColin Finck static void context_map_vsamplers(struct wined3d_context *context, BOOL ps, const struct wined3d_state *state)
3411c2c66affSColin Finck {
3412c2c66affSColin Finck const struct wined3d_shader_resource_info *vs_resource_info =
3413c2c66affSColin Finck state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.resource_info;
3414c2c66affSColin Finck const struct wined3d_shader_resource_info *ps_resource_info = NULL;
3415c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
3416c2c66affSColin Finck int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.graphics_samplers) - 1;
3417c2c66affSColin Finck int i;
3418c2c66affSColin Finck
3419c2c66affSColin Finck /* Note that we only care if a resource is used or not, not the
3420c2c66affSColin Finck * resource's specific type. Otherwise we'd need to call
3421c2c66affSColin Finck * shader_update_samplers() here for 1.x pixelshaders. */
3422c2c66affSColin Finck if (ps)
3423c2c66affSColin Finck ps_resource_info = state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info;
3424c2c66affSColin Finck
3425c2c66affSColin Finck for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
3426c2c66affSColin Finck {
3427c2c66affSColin Finck DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3428c2c66affSColin Finck if (vs_resource_info[i].type)
3429c2c66affSColin Finck {
3430c2c66affSColin Finck while (start >= 0)
3431c2c66affSColin Finck {
3432c2c66affSColin Finck if (context_unit_free_for_vs(context, ps_resource_info, start))
3433c2c66affSColin Finck {
3434c2c66affSColin Finck if (context->tex_unit_map[vsampler_idx] != start)
3435c2c66affSColin Finck {
3436c2c66affSColin Finck context_map_stage(context, vsampler_idx, start);
3437c2c66affSColin Finck context_invalidate_state(context, STATE_SAMPLER(vsampler_idx));
3438c2c66affSColin Finck }
3439c2c66affSColin Finck
3440c2c66affSColin Finck --start;
3441c2c66affSColin Finck break;
3442c2c66affSColin Finck }
3443c2c66affSColin Finck
3444c2c66affSColin Finck --start;
3445c2c66affSColin Finck }
3446c2c66affSColin Finck if (context->tex_unit_map[vsampler_idx] == WINED3D_UNMAPPED_STAGE)
3447c2c66affSColin Finck WARN("Couldn't find a free texture unit for vertex sampler %u.\n", i);
3448c2c66affSColin Finck }
3449c2c66affSColin Finck }
3450c2c66affSColin Finck }
3451c2c66affSColin Finck
context_update_tex_unit_map(struct wined3d_context * context,const struct wined3d_state * state)3452c2c66affSColin Finck static void context_update_tex_unit_map(struct wined3d_context *context, const struct wined3d_state *state)
3453c2c66affSColin Finck {
3454c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
3455c2c66affSColin Finck BOOL vs = use_vs(state);
3456c2c66affSColin Finck BOOL ps = use_ps(state);
3457c2c66affSColin Finck
3458c2c66affSColin Finck if (!ps)
3459c2c66affSColin Finck context_update_fixed_function_usage_map(context, state);
3460c2c66affSColin Finck
3461c2c66affSColin Finck /* Try to go for a 1:1 mapping of the samplers when possible. Pixel shaders
3462c2c66affSColin Finck * need a 1:1 map at the moment.
3463c2c66affSColin Finck * When the mapping of a stage is changed, sampler and ALL texture stage
3464c2c66affSColin Finck * states have to be reset. */
3465c2c66affSColin Finck
3466c2c66affSColin Finck if (gl_info->limits.graphics_samplers >= MAX_COMBINED_SAMPLERS)
3467c2c66affSColin Finck return;
3468c2c66affSColin Finck
3469c2c66affSColin Finck if (ps)
3470c2c66affSColin Finck context_map_psamplers(context, state);
3471c2c66affSColin Finck else
3472c2c66affSColin Finck context_map_fixed_function_samplers(context, state);
3473c2c66affSColin Finck
3474c2c66affSColin Finck if (vs)
3475c2c66affSColin Finck context_map_vsamplers(context, ps, state);
3476c2c66affSColin Finck }
3477c2c66affSColin Finck
3478c2c66affSColin Finck /* Context activation is done by the caller. */
context_state_drawbuf(struct wined3d_context * context,const struct wined3d_state * state,DWORD state_id)3479c2c66affSColin Finck void context_state_drawbuf(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
3480c2c66affSColin Finck {
3481c2c66affSColin Finck DWORD rt_mask, *cur_mask;
3482c2c66affSColin Finck
3483c2c66affSColin Finck if (isStateDirty(context, STATE_FRAMEBUFFER)) return;
3484c2c66affSColin Finck
3485c2c66affSColin Finck cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
3486c2c66affSColin Finck rt_mask = find_draw_buffers_mask(context, state);
3487c2c66affSColin Finck if (rt_mask != *cur_mask)
3488c2c66affSColin Finck {
3489c2c66affSColin Finck context_apply_draw_buffers(context, rt_mask);
3490c2c66affSColin Finck *cur_mask = rt_mask;
3491c2c66affSColin Finck }
3492c2c66affSColin Finck }
3493c2c66affSColin Finck
fixed_get_input(BYTE usage,BYTE usage_idx,unsigned int * regnum)3494c2c66affSColin Finck static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
3495c2c66affSColin Finck {
3496c2c66affSColin Finck if ((usage == WINED3D_DECL_USAGE_POSITION || usage == WINED3D_DECL_USAGE_POSITIONT) && !usage_idx)
3497c2c66affSColin Finck *regnum = WINED3D_FFP_POSITION;
3498c2c66affSColin Finck else if (usage == WINED3D_DECL_USAGE_BLEND_WEIGHT && !usage_idx)
3499c2c66affSColin Finck *regnum = WINED3D_FFP_BLENDWEIGHT;
3500c2c66affSColin Finck else if (usage == WINED3D_DECL_USAGE_BLEND_INDICES && !usage_idx)
3501c2c66affSColin Finck *regnum = WINED3D_FFP_BLENDINDICES;
3502c2c66affSColin Finck else if (usage == WINED3D_DECL_USAGE_NORMAL && !usage_idx)
3503c2c66affSColin Finck *regnum = WINED3D_FFP_NORMAL;
3504c2c66affSColin Finck else if (usage == WINED3D_DECL_USAGE_PSIZE && !usage_idx)
3505c2c66affSColin Finck *regnum = WINED3D_FFP_PSIZE;
3506c2c66affSColin Finck else if (usage == WINED3D_DECL_USAGE_COLOR && !usage_idx)
3507c2c66affSColin Finck *regnum = WINED3D_FFP_DIFFUSE;
3508c2c66affSColin Finck else if (usage == WINED3D_DECL_USAGE_COLOR && usage_idx == 1)
3509c2c66affSColin Finck *regnum = WINED3D_FFP_SPECULAR;
3510c2c66affSColin Finck else if (usage == WINED3D_DECL_USAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
3511c2c66affSColin Finck *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
3512c2c66affSColin Finck else
3513c2c66affSColin Finck {
3514c2c66affSColin Finck WARN("Unsupported input stream [usage=%s, usage_idx=%u].\n", debug_d3ddeclusage(usage), usage_idx);
3515c2c66affSColin Finck *regnum = ~0u;
3516c2c66affSColin Finck return FALSE;
3517c2c66affSColin Finck }
3518c2c66affSColin Finck
3519c2c66affSColin Finck return TRUE;
3520c2c66affSColin Finck }
3521c2c66affSColin Finck
3522c2c66affSColin Finck /* 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)3523c2c66affSColin Finck void wined3d_stream_info_from_declaration(struct wined3d_stream_info *stream_info,
3524c2c66affSColin Finck const struct wined3d_state *state, const struct wined3d_gl_info *gl_info,
3525c2c66affSColin Finck const struct wined3d_d3d_info *d3d_info)
3526c2c66affSColin Finck {
3527c2c66affSColin Finck /* We need to deal with frequency data! */
3528c2c66affSColin Finck struct wined3d_vertex_declaration *declaration = state->vertex_declaration;
3529c2c66affSColin Finck BOOL generic_attributes = d3d_info->ffp_generic_attributes;
3530c2c66affSColin Finck BOOL use_vshader = use_vs(state);
3531c2c66affSColin Finck unsigned int i;
3532c2c66affSColin Finck
3533c2c66affSColin Finck stream_info->use_map = 0;
3534c2c66affSColin Finck stream_info->swizzle_map = 0;
3535c2c66affSColin Finck stream_info->position_transformed = 0;
3536c2c66affSColin Finck
3537c2c66affSColin Finck if (!declaration)
3538c2c66affSColin Finck return;
3539c2c66affSColin Finck
3540c2c66affSColin Finck stream_info->position_transformed = declaration->position_transformed;
3541c2c66affSColin Finck
3542c2c66affSColin Finck /* Translate the declaration into strided data. */
3543c2c66affSColin Finck for (i = 0; i < declaration->element_count; ++i)
3544c2c66affSColin Finck {
3545c2c66affSColin Finck const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
3546c2c66affSColin Finck const struct wined3d_stream_state *stream = &state->streams[element->input_slot];
3547c2c66affSColin Finck BOOL stride_used;
3548c2c66affSColin Finck unsigned int idx;
3549c2c66affSColin Finck
3550c2c66affSColin Finck TRACE("%p Element %p (%u of %u).\n", declaration->elements,
3551c2c66affSColin Finck element, i + 1, declaration->element_count);
3552c2c66affSColin Finck
3553c2c66affSColin Finck if (!stream->buffer)
3554c2c66affSColin Finck continue;
3555c2c66affSColin Finck
3556c2c66affSColin Finck TRACE("offset %u input_slot %u usage_idx %d.\n", element->offset, element->input_slot, element->usage_idx);
3557c2c66affSColin Finck
3558c2c66affSColin Finck if (use_vshader)
3559c2c66affSColin Finck {
3560c2c66affSColin Finck if (element->output_slot == WINED3D_OUTPUT_SLOT_UNUSED)
3561c2c66affSColin Finck {
3562c2c66affSColin Finck stride_used = FALSE;
3563c2c66affSColin Finck }
3564c2c66affSColin Finck else if (element->output_slot == WINED3D_OUTPUT_SLOT_SEMANTIC)
3565c2c66affSColin Finck {
3566c2c66affSColin Finck /* TODO: Assuming vertexdeclarations are usually used with the
3567c2c66affSColin Finck * same or a similar shader, it might be worth it to store the
3568c2c66affSColin Finck * last used output slot and try that one first. */
3569c2c66affSColin Finck stride_used = vshader_get_input(state->shader[WINED3D_SHADER_TYPE_VERTEX],
3570c2c66affSColin Finck element->usage, element->usage_idx, &idx);
3571c2c66affSColin Finck }
3572c2c66affSColin Finck else
3573c2c66affSColin Finck {
3574c2c66affSColin Finck idx = element->output_slot;
3575c2c66affSColin Finck stride_used = TRUE;
3576c2c66affSColin Finck }
3577c2c66affSColin Finck }
3578c2c66affSColin Finck else
3579c2c66affSColin Finck {
3580c2c66affSColin Finck if (!generic_attributes && !element->ffp_valid)
3581c2c66affSColin Finck {
3582c2c66affSColin Finck WARN("Skipping unsupported fixed function element of format %s and usage %s.\n",
3583c2c66affSColin Finck debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
3584c2c66affSColin Finck stride_used = FALSE;
3585c2c66affSColin Finck }
3586c2c66affSColin Finck else
3587c2c66affSColin Finck {
3588c2c66affSColin Finck stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
3589c2c66affSColin Finck }
3590c2c66affSColin Finck }
3591c2c66affSColin Finck
3592c2c66affSColin Finck if (stride_used)
3593c2c66affSColin Finck {
3594c2c66affSColin Finck TRACE("Load %s array %u [usage %s, usage_idx %u, "
3595c2c66affSColin Finck "input_slot %u, offset %u, stride %u, format %s, class %s, step_rate %u].\n",
3596c2c66affSColin Finck use_vshader ? "shader": "fixed function", idx,
3597c2c66affSColin Finck debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
3598c2c66affSColin Finck element->offset, stream->stride, debug_d3dformat(element->format->id),
3599c2c66affSColin Finck debug_d3dinput_classification(element->input_slot_class), element->instance_data_step_rate);
3600c2c66affSColin Finck
3601c2c66affSColin Finck stream_info->elements[idx].format = element->format;
3602c2c66affSColin Finck stream_info->elements[idx].data.buffer_object = 0;
3603c2c66affSColin Finck stream_info->elements[idx].data.addr = (BYTE *)NULL + stream->offset + element->offset;
3604c2c66affSColin Finck stream_info->elements[idx].stride = stream->stride;
3605c2c66affSColin Finck stream_info->elements[idx].stream_idx = element->input_slot;
3606c2c66affSColin Finck if (stream->flags & WINED3DSTREAMSOURCE_INSTANCEDATA)
3607c2c66affSColin Finck {
3608c2c66affSColin Finck stream_info->elements[idx].divisor = 1;
3609c2c66affSColin Finck }
3610c2c66affSColin Finck else if (element->input_slot_class == WINED3D_INPUT_PER_INSTANCE_DATA)
3611c2c66affSColin Finck {
3612c2c66affSColin Finck stream_info->elements[idx].divisor = element->instance_data_step_rate;
3613c2c66affSColin Finck if (!element->instance_data_step_rate)
3614c2c66affSColin Finck FIXME("Instance step rate 0 not implemented.\n");
3615c2c66affSColin Finck }
3616c2c66affSColin Finck else
3617c2c66affSColin Finck {
3618c2c66affSColin Finck stream_info->elements[idx].divisor = 0;
3619c2c66affSColin Finck }
3620c2c66affSColin Finck
3621c2c66affSColin Finck if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
3622c2c66affSColin Finck && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
3623c2c66affSColin Finck {
3624c2c66affSColin Finck stream_info->swizzle_map |= 1u << idx;
3625c2c66affSColin Finck }
3626c2c66affSColin Finck stream_info->use_map |= 1u << idx;
3627c2c66affSColin Finck }
3628c2c66affSColin Finck }
3629c2c66affSColin Finck }
3630c2c66affSColin Finck
3631c2c66affSColin Finck /* Context activation is done by the caller. */
context_update_stream_info(struct wined3d_context * context,const struct wined3d_state * state)3632c2c66affSColin Finck static void context_update_stream_info(struct wined3d_context *context, const struct wined3d_state *state)
3633c2c66affSColin Finck {
3634c2c66affSColin Finck struct wined3d_stream_info *stream_info = &context->stream_info;
3635c2c66affSColin Finck const struct wined3d_d3d_info *d3d_info = context->d3d_info;
3636c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
3637c2c66affSColin Finck DWORD prev_all_vbo = stream_info->all_vbo;
3638c2c66affSColin Finck unsigned int i;
3639c2c66affSColin Finck WORD map;
3640c2c66affSColin Finck
3641c2c66affSColin Finck wined3d_stream_info_from_declaration(stream_info, state, gl_info, d3d_info);
3642c2c66affSColin Finck
3643c2c66affSColin Finck stream_info->all_vbo = 1;
3644c2c66affSColin Finck context->buffer_fence_count = 0;
3645c2c66affSColin Finck for (i = 0, map = stream_info->use_map; map; map >>= 1, ++i)
3646c2c66affSColin Finck {
3647c2c66affSColin Finck struct wined3d_stream_info_element *element;
3648c2c66affSColin Finck struct wined3d_bo_address data;
3649c2c66affSColin Finck struct wined3d_buffer *buffer;
3650c2c66affSColin Finck
3651c2c66affSColin Finck if (!(map & 1))
3652c2c66affSColin Finck continue;
3653c2c66affSColin Finck
3654c2c66affSColin Finck element = &stream_info->elements[i];
3655c2c66affSColin Finck buffer = state->streams[element->stream_idx].buffer;
3656c2c66affSColin Finck
3657c2c66affSColin Finck /* We can't use VBOs if the base vertex index is negative. OpenGL
3658c2c66affSColin Finck * doesn't accept negative offsets (or rather offsets bigger than the
3659c2c66affSColin Finck * VBO, because the pointer is unsigned), so use system memory
3660c2c66affSColin Finck * sources. In most sane cases the pointer - offset will still be > 0,
3661c2c66affSColin Finck * otherwise it will wrap around to some big value. Hope that with the
3662c2c66affSColin Finck * indices the driver wraps it back internally. If not,
3663c2c66affSColin Finck * draw_primitive_immediate_mode() is needed, including a vertex buffer
3664c2c66affSColin Finck * path. */
3665c2c66affSColin Finck if (state->load_base_vertex_index < 0)
3666c2c66affSColin Finck {
3667c2c66affSColin Finck WARN_(d3d_perf)("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
3668c2c66affSColin Finck state->load_base_vertex_index);
3669c2c66affSColin Finck element->data.buffer_object = 0;
3670c2c66affSColin Finck element->data.addr += (ULONG_PTR)wined3d_buffer_load_sysmem(buffer, context);
3671c2c66affSColin Finck if ((UINT_PTR)element->data.addr < -state->load_base_vertex_index * element->stride)
3672c2c66affSColin Finck FIXME("System memory vertex data load offset is negative!\n");
3673c2c66affSColin Finck }
3674c2c66affSColin Finck else
3675c2c66affSColin Finck {
3676c2c66affSColin Finck wined3d_buffer_load(buffer, context, state);
3677c2c66affSColin Finck wined3d_buffer_get_memory(buffer, &data, buffer->locations);
3678c2c66affSColin Finck element->data.buffer_object = data.buffer_object;
3679c2c66affSColin Finck element->data.addr += (ULONG_PTR)data.addr;
3680c2c66affSColin Finck }
3681c2c66affSColin Finck
3682c2c66affSColin Finck if (!element->data.buffer_object)
3683c2c66affSColin Finck stream_info->all_vbo = 0;
3684c2c66affSColin Finck
3685c2c66affSColin Finck if (buffer->fence)
3686c2c66affSColin Finck context->buffer_fences[context->buffer_fence_count++] = buffer->fence;
3687c2c66affSColin Finck
3688c2c66affSColin Finck TRACE("Load array %u {%#x:%p}.\n", i, element->data.buffer_object, element->data.addr);
3689c2c66affSColin Finck }
3690c2c66affSColin Finck
3691c2c66affSColin Finck if (prev_all_vbo != stream_info->all_vbo)
3692c2c66affSColin Finck context_invalidate_state(context, STATE_INDEXBUFFER);
3693c2c66affSColin Finck
3694c2c66affSColin Finck context->use_immediate_mode_draw = FALSE;
3695c2c66affSColin Finck
3696c2c66affSColin Finck if (stream_info->all_vbo)
3697c2c66affSColin Finck return;
3698c2c66affSColin Finck
3699c2c66affSColin Finck if (use_vs(state))
3700c2c66affSColin Finck {
3701c2c66affSColin Finck if (state->vertex_declaration->half_float_conv_needed)
3702c2c66affSColin Finck {
3703c2c66affSColin Finck TRACE("Using immediate mode draw with vertex shaders for FLOAT16 conversion.\n");
3704c2c66affSColin Finck context->use_immediate_mode_draw = TRUE;
3705c2c66affSColin Finck }
3706c2c66affSColin Finck }
3707c2c66affSColin Finck else
3708c2c66affSColin Finck {
3709c2c66affSColin Finck WORD slow_mask = -!d3d_info->ffp_generic_attributes & (1u << WINED3D_FFP_PSIZE);
3710c2c66affSColin Finck slow_mask |= -(!gl_info->supported[ARB_VERTEX_ARRAY_BGRA] && !d3d_info->ffp_generic_attributes)
3711c2c66affSColin Finck & ((1u << WINED3D_FFP_DIFFUSE) | (1u << WINED3D_FFP_SPECULAR) | (1u << WINED3D_FFP_BLENDWEIGHT));
3712c2c66affSColin Finck
3713c2c66affSColin Finck if ((stream_info->position_transformed && !d3d_info->xyzrhw)
3714c2c66affSColin Finck || (stream_info->use_map & slow_mask))
3715c2c66affSColin Finck context->use_immediate_mode_draw = TRUE;
3716c2c66affSColin Finck }
3717c2c66affSColin Finck }
3718c2c66affSColin Finck
3719c2c66affSColin Finck /* Context activation is done by the caller. */
context_preload_texture(struct wined3d_context * context,const struct wined3d_state * state,unsigned int idx)3720c2c66affSColin Finck static void context_preload_texture(struct wined3d_context *context,
3721c2c66affSColin Finck const struct wined3d_state *state, unsigned int idx)
3722c2c66affSColin Finck {
3723c2c66affSColin Finck struct wined3d_texture *texture;
3724c2c66affSColin Finck
3725c2c66affSColin Finck if (!(texture = state->textures[idx]))
3726c2c66affSColin Finck return;
3727c2c66affSColin Finck
3728c2c66affSColin Finck wined3d_texture_load(texture, context, state->sampler_states[idx][WINED3D_SAMP_SRGB_TEXTURE]);
3729c2c66affSColin Finck }
3730c2c66affSColin Finck
3731c2c66affSColin Finck /* Context activation is done by the caller. */
context_preload_textures(struct wined3d_context * context,const struct wined3d_state * state)3732c2c66affSColin Finck static void context_preload_textures(struct wined3d_context *context, const struct wined3d_state *state)
3733c2c66affSColin Finck {
3734c2c66affSColin Finck unsigned int i;
3735c2c66affSColin Finck
3736c2c66affSColin Finck if (use_vs(state))
3737c2c66affSColin Finck {
3738c2c66affSColin Finck for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
3739c2c66affSColin Finck {
3740c2c66affSColin Finck if (state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.resource_info[i].type)
3741c2c66affSColin Finck context_preload_texture(context, state, MAX_FRAGMENT_SAMPLERS + i);
3742c2c66affSColin Finck }
3743c2c66affSColin Finck }
3744c2c66affSColin Finck
3745c2c66affSColin Finck if (use_ps(state))
3746c2c66affSColin Finck {
3747c2c66affSColin Finck for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
3748c2c66affSColin Finck {
3749c2c66affSColin Finck if (state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info[i].type)
3750c2c66affSColin Finck context_preload_texture(context, state, i);
3751c2c66affSColin Finck }
3752c2c66affSColin Finck }
3753c2c66affSColin Finck else
3754c2c66affSColin Finck {
3755c2c66affSColin Finck WORD ffu_map = context->fixed_function_usage_map;
3756c2c66affSColin Finck
3757c2c66affSColin Finck for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3758c2c66affSColin Finck {
3759c2c66affSColin Finck if (ffu_map & 1)
3760c2c66affSColin Finck context_preload_texture(context, state, i);
3761c2c66affSColin Finck }
3762c2c66affSColin Finck }
3763c2c66affSColin Finck }
3764c2c66affSColin Finck
context_load_shader_resources(struct wined3d_context * context,const struct wined3d_state * state,unsigned int shader_mask)3765c2c66affSColin Finck static void context_load_shader_resources(struct wined3d_context *context, const struct wined3d_state *state,
3766c2c66affSColin Finck unsigned int shader_mask)
3767c2c66affSColin Finck {
3768c2c66affSColin Finck struct wined3d_shader_sampler_map_entry *entry;
3769c2c66affSColin Finck struct wined3d_shader_resource_view *view;
3770c2c66affSColin Finck struct wined3d_shader *shader;
3771c2c66affSColin Finck unsigned int i, j;
3772c2c66affSColin Finck
3773c2c66affSColin Finck for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
3774c2c66affSColin Finck {
3775c2c66affSColin Finck if (!(shader_mask & (1u << i)))
3776c2c66affSColin Finck continue;
3777c2c66affSColin Finck
3778c2c66affSColin Finck if (!(shader = state->shader[i]))
3779c2c66affSColin Finck continue;
3780c2c66affSColin Finck
3781c2c66affSColin Finck for (j = 0; j < WINED3D_MAX_CBS; ++j)
3782c2c66affSColin Finck {
3783c2c66affSColin Finck if (state->cb[i][j])
3784c2c66affSColin Finck wined3d_buffer_load(state->cb[i][j], context, state);
3785c2c66affSColin Finck }
3786c2c66affSColin Finck
3787c2c66affSColin Finck for (j = 0; j < shader->reg_maps.sampler_map.count; ++j)
3788c2c66affSColin Finck {
3789c2c66affSColin Finck entry = &shader->reg_maps.sampler_map.entries[j];
3790c2c66affSColin Finck
3791c2c66affSColin Finck if (!(view = state->shader_resource_view[i][entry->resource_idx]))
3792c2c66affSColin Finck continue;
3793c2c66affSColin Finck
3794c2c66affSColin Finck if (view->resource->type == WINED3D_RTYPE_BUFFER)
3795c2c66affSColin Finck wined3d_buffer_load(buffer_from_resource(view->resource), context, state);
3796c2c66affSColin Finck else
3797c2c66affSColin Finck wined3d_texture_load(texture_from_resource(view->resource), context, FALSE);
3798c2c66affSColin Finck }
3799c2c66affSColin Finck }
3800c2c66affSColin Finck }
3801c2c66affSColin Finck
context_bind_shader_resources(struct wined3d_context * context,const struct wined3d_state * state,enum wined3d_shader_type shader_type)3802c2c66affSColin Finck static void context_bind_shader_resources(struct wined3d_context *context,
3803c2c66affSColin Finck const struct wined3d_state *state, enum wined3d_shader_type shader_type)
3804c2c66affSColin Finck {
3805c2c66affSColin Finck unsigned int bind_idx, shader_sampler_count, base, count, i;
3806c2c66affSColin Finck const struct wined3d_device *device = context->device;
3807c2c66affSColin Finck struct wined3d_shader_sampler_map_entry *entry;
3808c2c66affSColin Finck struct wined3d_shader_resource_view *view;
3809c2c66affSColin Finck const struct wined3d_shader *shader;
3810c2c66affSColin Finck struct wined3d_sampler *sampler;
3811c2c66affSColin Finck const DWORD *tex_unit_map;
3812c2c66affSColin Finck
3813c2c66affSColin Finck if (!(shader = state->shader[shader_type]))
3814c2c66affSColin Finck return;
3815c2c66affSColin Finck
3816c2c66affSColin Finck tex_unit_map = context_get_tex_unit_mapping(context,
3817c2c66affSColin Finck &shader->reg_maps.shader_version, &base, &count);
3818c2c66affSColin Finck
3819c2c66affSColin Finck shader_sampler_count = shader->reg_maps.sampler_map.count;
3820c2c66affSColin Finck if (shader_sampler_count > count)
3821c2c66affSColin Finck FIXME("Shader %p needs %u samplers, but only %u are supported.\n",
3822c2c66affSColin Finck shader, shader_sampler_count, count);
3823c2c66affSColin Finck count = min(shader_sampler_count, count);
3824c2c66affSColin Finck
3825c2c66affSColin Finck for (i = 0; i < count; ++i)
3826c2c66affSColin Finck {
3827c2c66affSColin Finck entry = &shader->reg_maps.sampler_map.entries[i];
3828c2c66affSColin Finck bind_idx = base + entry->bind_idx;
3829c2c66affSColin Finck if (tex_unit_map)
3830c2c66affSColin Finck bind_idx = tex_unit_map[bind_idx];
3831c2c66affSColin Finck
3832c2c66affSColin Finck if (!(view = state->shader_resource_view[shader_type][entry->resource_idx]))
3833c2c66affSColin Finck {
3834c2c66affSColin Finck WARN("No resource view bound at index %u, %u.\n", shader_type, entry->resource_idx);
3835c2c66affSColin Finck continue;
3836c2c66affSColin Finck }
3837c2c66affSColin Finck
3838c2c66affSColin Finck if (entry->sampler_idx == WINED3D_SAMPLER_DEFAULT)
3839c2c66affSColin Finck sampler = device->default_sampler;
3840c2c66affSColin Finck else if (!(sampler = state->sampler[shader_type][entry->sampler_idx]))
3841c2c66affSColin Finck sampler = device->null_sampler;
3842c2c66affSColin Finck wined3d_shader_resource_view_bind(view, bind_idx, sampler, context);
3843c2c66affSColin Finck }
3844c2c66affSColin Finck }
3845c2c66affSColin Finck
context_load_unordered_access_resources(struct wined3d_context * context,const struct wined3d_shader * shader,struct wined3d_unordered_access_view * const * views)3846c2c66affSColin Finck static void context_load_unordered_access_resources(struct wined3d_context *context,
3847c2c66affSColin Finck const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
3848c2c66affSColin Finck {
3849c2c66affSColin Finck struct wined3d_unordered_access_view *view;
3850c2c66affSColin Finck struct wined3d_texture *texture;
3851c2c66affSColin Finck struct wined3d_buffer *buffer;
3852c2c66affSColin Finck unsigned int i;
3853c2c66affSColin Finck
3854c2c66affSColin Finck context->uses_uavs = 0;
3855c2c66affSColin Finck
3856c2c66affSColin Finck if (!shader)
3857c2c66affSColin Finck return;
3858c2c66affSColin Finck
3859c2c66affSColin Finck for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
3860c2c66affSColin Finck {
3861c2c66affSColin Finck if (!(view = views[i]))
3862c2c66affSColin Finck continue;
3863c2c66affSColin Finck
3864c2c66affSColin Finck if (view->resource->type == WINED3D_RTYPE_BUFFER)
3865c2c66affSColin Finck {
3866c2c66affSColin Finck buffer = buffer_from_resource(view->resource);
3867c2c66affSColin Finck wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER);
3868c2c66affSColin Finck wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_BUFFER);
3869c2c66affSColin Finck }
3870c2c66affSColin Finck else
3871c2c66affSColin Finck {
3872c2c66affSColin Finck texture = texture_from_resource(view->resource);
3873c2c66affSColin Finck wined3d_texture_load(texture, context, FALSE);
3874c2c66affSColin Finck wined3d_unordered_access_view_invalidate_location(view, ~WINED3D_LOCATION_TEXTURE_RGB);
3875c2c66affSColin Finck }
3876c2c66affSColin Finck
3877c2c66affSColin Finck context->uses_uavs = 1;
3878c2c66affSColin Finck }
3879c2c66affSColin Finck }
3880c2c66affSColin Finck
context_bind_unordered_access_views(struct wined3d_context * context,const struct wined3d_shader * shader,struct wined3d_unordered_access_view * const * views)3881c2c66affSColin Finck static void context_bind_unordered_access_views(struct wined3d_context *context,
3882c2c66affSColin Finck const struct wined3d_shader *shader, struct wined3d_unordered_access_view * const *views)
3883c2c66affSColin Finck {
3884c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
3885c2c66affSColin Finck struct wined3d_unordered_access_view *view;
3886c2c66affSColin Finck GLuint texture_name;
3887c2c66affSColin Finck unsigned int i;
3888c2c66affSColin Finck GLint level;
3889c2c66affSColin Finck
3890c2c66affSColin Finck if (!shader)
3891c2c66affSColin Finck return;
3892c2c66affSColin Finck
3893c2c66affSColin Finck for (i = 0; i < MAX_UNORDERED_ACCESS_VIEWS; ++i)
3894c2c66affSColin Finck {
3895c2c66affSColin Finck if (!(view = views[i]))
3896c2c66affSColin Finck {
3897c2c66affSColin Finck if (shader->reg_maps.uav_resource_info[i].type)
3898c2c66affSColin Finck WARN("No unordered access view bound at index %u.\n", i);
3899c2c66affSColin Finck GL_EXTCALL(glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R8));
3900c2c66affSColin Finck continue;
3901c2c66affSColin Finck }
3902c2c66affSColin Finck
3903c2c66affSColin Finck if (view->gl_view.name)
3904c2c66affSColin Finck {
3905c2c66affSColin Finck texture_name = view->gl_view.name;
3906c2c66affSColin Finck level = 0;
3907c2c66affSColin Finck }
3908c2c66affSColin Finck else if (view->resource->type != WINED3D_RTYPE_BUFFER)
3909c2c66affSColin Finck {
3910c2c66affSColin Finck struct wined3d_texture *texture = texture_from_resource(view->resource);
3911c2c66affSColin Finck texture_name = wined3d_texture_get_texture_name(texture, context, FALSE);
3912c2c66affSColin Finck level = view->desc.u.texture.level_idx;
3913c2c66affSColin Finck }
3914c2c66affSColin Finck else
3915c2c66affSColin Finck {
3916c2c66affSColin Finck FIXME("Unsupported buffer unordered access view.\n");
3917c2c66affSColin Finck GL_EXTCALL(glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R8));
3918c2c66affSColin Finck continue;
3919c2c66affSColin Finck }
3920c2c66affSColin Finck
3921c2c66affSColin Finck GL_EXTCALL(glBindImageTexture(i, texture_name, level, GL_TRUE, 0, GL_READ_WRITE,
3922c2c66affSColin Finck view->format->glInternal));
3923c2c66affSColin Finck
3924c2c66affSColin Finck if (view->counter_bo)
3925c2c66affSColin Finck GL_EXTCALL(glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, view->counter_bo));
3926c2c66affSColin Finck }
3927c2c66affSColin Finck checkGLcall("Bind unordered access views");
3928c2c66affSColin Finck }
3929c2c66affSColin Finck
context_load_stream_output_buffers(struct wined3d_context * context,const struct wined3d_state * state)3930c2c66affSColin Finck static void context_load_stream_output_buffers(struct wined3d_context *context,
3931c2c66affSColin Finck const struct wined3d_state *state)
3932c2c66affSColin Finck {
3933c2c66affSColin Finck unsigned int i;
3934c2c66affSColin Finck
3935c2c66affSColin Finck for (i = 0; i < ARRAY_SIZE(state->stream_output); ++i)
3936c2c66affSColin Finck {
3937c2c66affSColin Finck struct wined3d_buffer *buffer;
3938c2c66affSColin Finck if (!(buffer = state->stream_output[i].buffer))
3939c2c66affSColin Finck continue;
3940c2c66affSColin Finck
3941c2c66affSColin Finck wined3d_buffer_load(buffer, context, state);
3942c2c66affSColin Finck wined3d_buffer_invalidate_location(buffer, ~WINED3D_LOCATION_BUFFER);
3943c2c66affSColin Finck }
3944c2c66affSColin Finck }
3945c2c66affSColin Finck
3946c2c66affSColin Finck /* 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)39479987f029SAmine Khaldi static BOOL context_apply_draw_state(struct wined3d_context *context,
3948c2c66affSColin Finck const struct wined3d_device *device, const struct wined3d_state *state)
3949c2c66affSColin Finck {
3950c2c66affSColin Finck const struct StateEntry *state_table = context->state_table;
3951c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
3952c2c66affSColin Finck const struct wined3d_fb_state *fb = state->fb;
3953c2c66affSColin Finck unsigned int i;
3954c2c66affSColin Finck WORD map;
3955c2c66affSColin Finck
39569987f029SAmine Khaldi if (!have_framebuffer_attachment(gl_info->limits.buffers, fb->render_targets, fb->depth_stencil))
39579987f029SAmine Khaldi {
39589987f029SAmine Khaldi if (!gl_info->supported[ARB_FRAMEBUFFER_NO_ATTACHMENTS])
39599987f029SAmine Khaldi {
39609987f029SAmine Khaldi FIXME("OpenGL implementation does not support framebuffers with no attachments.\n");
3961c2c66affSColin Finck return FALSE;
39629987f029SAmine Khaldi }
39639987f029SAmine Khaldi
39649987f029SAmine Khaldi context_set_render_offscreen(context, TRUE);
39659987f029SAmine Khaldi }
3966c2c66affSColin Finck
3967c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && isStateDirty(context, STATE_FRAMEBUFFER))
3968c2c66affSColin Finck {
3969c2c66affSColin Finck context_validate_onscreen_formats(context, fb->depth_stencil);
3970c2c66affSColin Finck }
3971c2c66affSColin Finck
3972c2c66affSColin Finck /* Preload resources before FBO setup. Texture preload in particular may
3973c2c66affSColin Finck * result in changes to the current FBO, due to using e.g. FBO blits for
3974c2c66affSColin Finck * updating a resource location. */
3975c2c66affSColin Finck context_update_tex_unit_map(context, state);
3976c2c66affSColin Finck context_preload_textures(context, state);
3977c2c66affSColin Finck context_load_shader_resources(context, state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE));
3978c2c66affSColin Finck context_load_unordered_access_resources(context, state->shader[WINED3D_SHADER_TYPE_PIXEL],
3979c2c66affSColin Finck state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
3980c2c66affSColin Finck context_load_stream_output_buffers(context, state);
3981c2c66affSColin Finck /* TODO: Right now the dependency on the vertex shader is necessary
3982c2c66affSColin Finck * since wined3d_stream_info_from_declaration() depends on the reg_maps of
3983c2c66affSColin Finck * the current VS but maybe it's possible to relax the coupling in some
3984c2c66affSColin Finck * situations at least. */
3985c2c66affSColin Finck if (isStateDirty(context, STATE_VDECL) || isStateDirty(context, STATE_STREAMSRC)
3986c2c66affSColin Finck || isStateDirty(context, STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX)))
3987c2c66affSColin Finck {
3988c2c66affSColin Finck context_update_stream_info(context, state);
3989c2c66affSColin Finck }
3990c2c66affSColin Finck else
3991c2c66affSColin Finck {
3992c2c66affSColin Finck for (i = 0, map = context->stream_info.use_map; map; map >>= 1, ++i)
3993c2c66affSColin Finck {
3994c2c66affSColin Finck if (map & 1)
3995c2c66affSColin Finck wined3d_buffer_load(state->streams[context->stream_info.elements[i].stream_idx].buffer,
3996c2c66affSColin Finck context, state);
3997c2c66affSColin Finck }
3998c2c66affSColin Finck /* Loading the buffers above may have invalidated the stream info. */
3999c2c66affSColin Finck if (isStateDirty(context, STATE_STREAMSRC))
4000c2c66affSColin Finck context_update_stream_info(context, state);
4001c2c66affSColin Finck }
4002c2c66affSColin Finck if (state->index_buffer)
4003c2c66affSColin Finck {
4004c2c66affSColin Finck if (context->stream_info.all_vbo)
4005c2c66affSColin Finck wined3d_buffer_load(state->index_buffer, context, state);
4006c2c66affSColin Finck else
4007c2c66affSColin Finck wined3d_buffer_load_sysmem(state->index_buffer, context);
4008c2c66affSColin Finck }
4009c2c66affSColin Finck
4010c2c66affSColin Finck for (i = 0; i < context->numDirtyEntries; ++i)
4011c2c66affSColin Finck {
4012c2c66affSColin Finck DWORD rep = context->dirtyArray[i];
4013c2c66affSColin Finck DWORD idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
4014c2c66affSColin Finck BYTE shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
4015c2c66affSColin Finck context->isStateDirty[idx] &= ~(1u << shift);
4016c2c66affSColin Finck state_table[rep].apply(context, state, rep);
4017c2c66affSColin Finck }
4018c2c66affSColin Finck
4019c2c66affSColin Finck if (context->shader_update_mask & ~(1u << WINED3D_SHADER_TYPE_COMPUTE))
4020c2c66affSColin Finck {
4021c2c66affSColin Finck device->shader_backend->shader_select(device->shader_priv, context, state);
4022c2c66affSColin Finck context->shader_update_mask &= 1u << WINED3D_SHADER_TYPE_COMPUTE;
4023c2c66affSColin Finck }
4024c2c66affSColin Finck
4025c2c66affSColin Finck if (context->constant_update_mask)
4026c2c66affSColin Finck {
4027c2c66affSColin Finck device->shader_backend->shader_load_constants(device->shader_priv, context, state);
4028c2c66affSColin Finck context->constant_update_mask = 0;
4029c2c66affSColin Finck }
4030c2c66affSColin Finck
4031c2c66affSColin Finck if (context->update_shader_resource_bindings)
4032c2c66affSColin Finck {
4033c2c66affSColin Finck for (i = 0; i < WINED3D_SHADER_TYPE_GRAPHICS_COUNT; ++i)
4034c2c66affSColin Finck context_bind_shader_resources(context, state, i);
4035c2c66affSColin Finck context->update_shader_resource_bindings = 0;
4036c2c66affSColin Finck if (gl_info->limits.combined_samplers == gl_info->limits.graphics_samplers)
4037c2c66affSColin Finck context->update_compute_shader_resource_bindings = 1;
4038c2c66affSColin Finck }
4039c2c66affSColin Finck
4040c2c66affSColin Finck if (context->update_unordered_access_view_bindings)
4041c2c66affSColin Finck {
4042c2c66affSColin Finck context_bind_unordered_access_views(context,
4043c2c66affSColin Finck state->shader[WINED3D_SHADER_TYPE_PIXEL],
4044c2c66affSColin Finck state->unordered_access_view[WINED3D_PIPELINE_GRAPHICS]);
4045c2c66affSColin Finck context->update_unordered_access_view_bindings = 0;
4046c2c66affSColin Finck context->update_compute_unordered_access_view_bindings = 1;
4047c2c66affSColin Finck }
4048c2c66affSColin Finck
4049c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4050c2c66affSColin Finck {
4051c2c66affSColin Finck context_check_fbo_status(context, GL_FRAMEBUFFER);
4052c2c66affSColin Finck }
4053c2c66affSColin Finck
4054c2c66affSColin Finck context->numDirtyEntries = 0; /* This makes the whole list clean */
4055c2c66affSColin Finck context->last_was_blit = FALSE;
4056c2c66affSColin Finck
4057c2c66affSColin Finck return TRUE;
4058c2c66affSColin Finck }
4059c2c66affSColin Finck
context_apply_compute_state(struct wined3d_context * context,const struct wined3d_device * device,const struct wined3d_state * state)40609987f029SAmine Khaldi static void context_apply_compute_state(struct wined3d_context *context,
4061c2c66affSColin Finck const struct wined3d_device *device, const struct wined3d_state *state)
4062c2c66affSColin Finck {
4063c2c66affSColin Finck const struct StateEntry *state_table = context->state_table;
4064c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
40659987f029SAmine Khaldi unsigned int state_id, i;
4066c2c66affSColin Finck
4067c2c66affSColin Finck context_load_shader_resources(context, state, 1u << WINED3D_SHADER_TYPE_COMPUTE);
4068c2c66affSColin Finck context_load_unordered_access_resources(context, state->shader[WINED3D_SHADER_TYPE_COMPUTE],
4069c2c66affSColin Finck state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
4070c2c66affSColin Finck
4071c2c66affSColin Finck for (i = 0, state_id = STATE_COMPUTE_OFFSET; i < ARRAY_SIZE(context->dirty_compute_states); ++i)
4072c2c66affSColin Finck {
40739987f029SAmine Khaldi unsigned int dirty_mask = context->dirty_compute_states[i];
40749987f029SAmine Khaldi while (dirty_mask)
4075c2c66affSColin Finck {
40769987f029SAmine Khaldi unsigned int current_state_id = state_id + wined3d_bit_scan(&dirty_mask);
40779987f029SAmine Khaldi state_table[current_state_id].apply(context, state, current_state_id);
4078c2c66affSColin Finck }
40799987f029SAmine Khaldi state_id += sizeof(*context->dirty_compute_states) * CHAR_BIT;
4080c2c66affSColin Finck }
4081c2c66affSColin Finck memset(context->dirty_compute_states, 0, sizeof(*context->dirty_compute_states));
4082c2c66affSColin Finck
4083c2c66affSColin Finck if (context->shader_update_mask & (1u << WINED3D_SHADER_TYPE_COMPUTE))
4084c2c66affSColin Finck {
4085c2c66affSColin Finck device->shader_backend->shader_select_compute(device->shader_priv, context, state);
4086c2c66affSColin Finck context->shader_update_mask &= ~(1u << WINED3D_SHADER_TYPE_COMPUTE);
4087c2c66affSColin Finck }
4088c2c66affSColin Finck
4089c2c66affSColin Finck if (context->update_compute_shader_resource_bindings)
4090c2c66affSColin Finck {
4091c2c66affSColin Finck context_bind_shader_resources(context, state, WINED3D_SHADER_TYPE_COMPUTE);
4092c2c66affSColin Finck context->update_compute_shader_resource_bindings = 0;
4093c2c66affSColin Finck if (gl_info->limits.combined_samplers == gl_info->limits.graphics_samplers)
4094c2c66affSColin Finck context->update_shader_resource_bindings = 1;
4095c2c66affSColin Finck }
4096c2c66affSColin Finck
4097c2c66affSColin Finck if (context->update_compute_unordered_access_view_bindings)
4098c2c66affSColin Finck {
4099c2c66affSColin Finck context_bind_unordered_access_views(context,
4100c2c66affSColin Finck state->shader[WINED3D_SHADER_TYPE_COMPUTE],
4101c2c66affSColin Finck state->unordered_access_view[WINED3D_PIPELINE_COMPUTE]);
4102c2c66affSColin Finck context->update_compute_unordered_access_view_bindings = 0;
4103c2c66affSColin Finck context->update_unordered_access_view_bindings = 1;
4104c2c66affSColin Finck }
4105c2c66affSColin Finck
4106d6ac0a71SAmine Khaldi /* Updates to currently bound render targets aren't necessarily coherent
4107d6ac0a71SAmine Khaldi * between the graphics and compute pipelines. Unbind any currently bound
4108d6ac0a71SAmine Khaldi * FBO here to ensure preceding updates to its attachments by the graphics
4109d6ac0a71SAmine Khaldi * pipeline are visible to the compute pipeline.
4110d6ac0a71SAmine Khaldi *
4111d6ac0a71SAmine Khaldi * Without this, the bloom effect in Nier:Automata is too bright on the
4112d6ac0a71SAmine Khaldi * Mesa radeonsi driver, and presumably on other Mesa based drivers. */
4113d6ac0a71SAmine Khaldi context_bind_fbo(context, GL_FRAMEBUFFER, 0);
4114d6ac0a71SAmine Khaldi context_invalidate_state(context, STATE_FRAMEBUFFER);
4115d6ac0a71SAmine Khaldi
4116c2c66affSColin Finck context->last_was_blit = FALSE;
4117c2c66affSColin Finck }
4118c2c66affSColin Finck
use_transform_feedback(const struct wined3d_state * state)41199987f029SAmine Khaldi static BOOL use_transform_feedback(const struct wined3d_state *state)
41209987f029SAmine Khaldi {
41219987f029SAmine Khaldi const struct wined3d_shader *shader;
41229987f029SAmine Khaldi if (!(shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]))
41239987f029SAmine Khaldi return FALSE;
41249987f029SAmine Khaldi return shader->u.gs.so_desc.element_count;
41259987f029SAmine Khaldi }
41269987f029SAmine Khaldi
context_end_transform_feedback(struct wined3d_context * context)4127c2c66affSColin Finck void context_end_transform_feedback(struct wined3d_context *context)
4128c2c66affSColin Finck {
4129c2c66affSColin Finck const struct wined3d_gl_info *gl_info = context->gl_info;
4130c2c66affSColin Finck if (context->transform_feedback_active)
4131c2c66affSColin Finck {
4132c2c66affSColin Finck GL_EXTCALL(glEndTransformFeedback());
4133c2c66affSColin Finck checkGLcall("glEndTransformFeedback");
4134c2c66affSColin Finck context->transform_feedback_active = 0;
4135c2c66affSColin Finck context->transform_feedback_paused = 0;
4136c2c66affSColin Finck }
4137c2c66affSColin Finck }
4138c2c66affSColin Finck
context_pause_transform_feedback(struct wined3d_context * context,BOOL force)41399987f029SAmine Khaldi static void context_pause_transform_feedback(struct wined3d_context *context, BOOL force)
41409987f029SAmine Khaldi {
41419987f029SAmine Khaldi const struct wined3d_gl_info *gl_info = context->gl_info;
41429987f029SAmine Khaldi
41439987f029SAmine Khaldi if (!context->transform_feedback_active || context->transform_feedback_paused)
41449987f029SAmine Khaldi return;
41459987f029SAmine Khaldi
41469987f029SAmine Khaldi if (gl_info->supported[ARB_TRANSFORM_FEEDBACK2])
41479987f029SAmine Khaldi {
41489987f029SAmine Khaldi GL_EXTCALL(glPauseTransformFeedback());
41499987f029SAmine Khaldi checkGLcall("glPauseTransformFeedback");
41509987f029SAmine Khaldi context->transform_feedback_paused = 1;
41519987f029SAmine Khaldi return;
41529987f029SAmine Khaldi }
41539987f029SAmine Khaldi
41549987f029SAmine Khaldi WARN("Cannot pause transform feedback operations.\n");
41559987f029SAmine Khaldi
41569987f029SAmine Khaldi if (force)
41579987f029SAmine Khaldi context_end_transform_feedback(context);
41589987f029SAmine Khaldi }
41599987f029SAmine Khaldi
context_setup_target(struct wined3d_context * context,struct wined3d_texture * texture,unsigned int sub_resource_idx)4160c2c66affSColin Finck static void context_setup_target(struct wined3d_context *context,
4161c2c66affSColin Finck struct wined3d_texture *texture, unsigned int sub_resource_idx)
4162c2c66affSColin Finck {
4163c2c66affSColin Finck BOOL old_render_offscreen = context->render_offscreen, render_offscreen;
4164c2c66affSColin Finck
4165c2c66affSColin Finck render_offscreen = wined3d_resource_is_offscreen(&texture->resource);
4166c2c66affSColin Finck if (context->current_rt.texture == texture
4167c2c66affSColin Finck && context->current_rt.sub_resource_idx == sub_resource_idx
4168c2c66affSColin Finck && render_offscreen == old_render_offscreen)
4169c2c66affSColin Finck return;
4170c2c66affSColin Finck
4171c2c66affSColin Finck /* To compensate the lack of format switching with some offscreen rendering methods and on onscreen buffers
4172c2c66affSColin Finck * the alpha blend state changes with different render target formats. */
4173c2c66affSColin Finck if (!context->current_rt.texture)
4174c2c66affSColin Finck {
4175c2c66affSColin Finck context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
4176c2c66affSColin Finck }
4177c2c66affSColin Finck else
4178c2c66affSColin Finck {
4179c2c66affSColin Finck const struct wined3d_format *old = context->current_rt.texture->resource.format;
4180c2c66affSColin Finck const struct wined3d_format *new = texture->resource.format;
4181c2c66affSColin Finck
4182c2c66affSColin Finck if (old->id != new->id)
4183c2c66affSColin Finck {
4184c2c66affSColin Finck /* Disable blending when the alpha mask has changed and when a format doesn't support blending. */
4185c2c66affSColin Finck if ((old->alpha_size && !new->alpha_size) || (!old->alpha_size && new->alpha_size)
4186c2c66affSColin Finck || !(texture->resource.format_flags & WINED3DFMT_FLAG_POSTPIXELSHADER_BLENDING))
4187c2c66affSColin Finck context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ALPHABLENDENABLE));
4188c2c66affSColin Finck
4189c2c66affSColin Finck /* Update sRGB writing when switching between formats that do/do not support sRGB writing */
4190c2c66affSColin Finck if ((context->current_rt.texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE)
4191c2c66affSColin Finck != (texture->resource.format_flags & WINED3DFMT_FLAG_SRGB_WRITE))
4192c2c66affSColin Finck context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
4193c2c66affSColin Finck }
4194c2c66affSColin Finck
4195c2c66affSColin Finck /* When switching away from an offscreen render target, and we're not
4196c2c66affSColin Finck * using FBOs, we have to read the drawable into the texture. This is
4197c2c66affSColin Finck * done via PreLoad (and WINED3D_LOCATION_DRAWABLE set on the surface).
4198c2c66affSColin Finck * There are some things that need care though. PreLoad needs a GL context,
4199c2c66affSColin Finck * and FindContext is called before the context is activated. It also
4200c2c66affSColin Finck * has to be called with the old rendertarget active, otherwise a
4201c2c66affSColin Finck * wrong drawable is read. */
4202c2c66affSColin Finck if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
4203c2c66affSColin Finck && old_render_offscreen && (context->current_rt.texture != texture
4204c2c66affSColin Finck || context->current_rt.sub_resource_idx != sub_resource_idx))
4205c2c66affSColin Finck {
4206c2c66affSColin Finck unsigned int prev_sub_resource_idx = context->current_rt.sub_resource_idx;
4207c2c66affSColin Finck struct wined3d_texture *prev_texture = context->current_rt.texture;
4208c2c66affSColin Finck
4209c2c66affSColin Finck /* Read the back buffer of the old drawable into the destination texture. */
4210c2c66affSColin Finck if (prev_texture->texture_srgb.name)
4211c2c66affSColin Finck wined3d_texture_load(prev_texture, context, TRUE);
4212c2c66affSColin Finck wined3d_texture_load(prev_texture, context, FALSE);
4213c2c66affSColin Finck wined3d_texture_invalidate_location(prev_texture, prev_sub_resource_idx, WINED3D_LOCATION_DRAWABLE);
4214c2c66affSColin Finck }
4215c2c66affSColin Finck }
4216c2c66affSColin Finck
4217c2c66affSColin Finck context->current_rt.texture = texture;
4218c2c66affSColin Finck context->current_rt.sub_resource_idx = sub_resource_idx;
4219c2c66affSColin Finck context_set_render_offscreen(context, render_offscreen);
4220c2c66affSColin Finck }
4221c2c66affSColin Finck
context_activate(struct wined3d_context * context,struct wined3d_texture * texture,unsigned int sub_resource_idx)42229987f029SAmine Khaldi static void context_activate(struct wined3d_context *context,
42239987f029SAmine Khaldi struct wined3d_texture *texture, unsigned int sub_resource_idx)
42249987f029SAmine Khaldi {
42259987f029SAmine Khaldi context_enter(context);
42269987f029SAmine Khaldi context_update_window(context);
42279987f029SAmine Khaldi context_setup_target(context, texture, sub_resource_idx);
42289987f029SAmine Khaldi if (!context->valid)
42299987f029SAmine Khaldi return;
42309987f029SAmine Khaldi
42319987f029SAmine Khaldi if (context != context_get_current())
42329987f029SAmine Khaldi {
42339987f029SAmine Khaldi if (!context_set_current(context))
42349987f029SAmine Khaldi ERR("Failed to activate the new context.\n");
42359987f029SAmine Khaldi }
42369987f029SAmine Khaldi else if (context->needs_set)
42379987f029SAmine Khaldi {
42389987f029SAmine Khaldi context_set_gl_context(context);
42399987f029SAmine Khaldi }
42409987f029SAmine Khaldi }
42419987f029SAmine Khaldi
context_acquire(const struct wined3d_device * device,struct wined3d_texture * texture,unsigned int sub_resource_idx)4242c2c66affSColin Finck struct wined3d_context *context_acquire(const struct wined3d_device *device,
4243c2c66affSColin Finck struct wined3d_texture *texture, unsigned int sub_resource_idx)
4244c2c66affSColin Finck {
4245c2c66affSColin Finck struct wined3d_context *current_context = context_get_current();
4246c2c66affSColin Finck struct wined3d_context *context;
4247c2c66affSColin Finck BOOL swapchain_texture;
4248c2c66affSColin Finck
4249c2c66affSColin Finck TRACE("device %p, texture %p, sub_resource_idx %u.\n", device, texture, sub_resource_idx);
4250c2c66affSColin Finck
4251c2c66affSColin Finck wined3d_from_cs(device->cs);
4252c2c66affSColin Finck
4253c2c66affSColin Finck if (current_context && current_context->destroyed)
4254c2c66affSColin Finck current_context = NULL;
4255c2c66affSColin Finck
4256c2c66affSColin Finck swapchain_texture = texture && texture->swapchain;
4257c2c66affSColin Finck if (!texture)
4258c2c66affSColin Finck {
4259c2c66affSColin Finck if (current_context
4260c2c66affSColin Finck && current_context->current_rt.texture
4261c2c66affSColin Finck && current_context->device == device)
4262c2c66affSColin Finck {
4263c2c66affSColin Finck texture = current_context->current_rt.texture;
4264c2c66affSColin Finck sub_resource_idx = current_context->current_rt.sub_resource_idx;
4265c2c66affSColin Finck }
4266c2c66affSColin Finck else
4267c2c66affSColin Finck {
4268c2c66affSColin Finck struct wined3d_swapchain *swapchain = device->swapchains[0];
4269c2c66affSColin Finck
4270c2c66affSColin Finck if (swapchain->back_buffers)
4271c2c66affSColin Finck texture = swapchain->back_buffers[0];
4272c2c66affSColin Finck else
4273c2c66affSColin Finck texture = swapchain->front_buffer;
4274c2c66affSColin Finck sub_resource_idx = 0;
4275c2c66affSColin Finck }
4276c2c66affSColin Finck }
4277c2c66affSColin Finck
4278c2c66affSColin Finck if (current_context && current_context->current_rt.texture == texture)
4279c2c66affSColin Finck {
4280c2c66affSColin Finck context = current_context;
4281c2c66affSColin Finck }
4282c2c66affSColin Finck else if (swapchain_texture)
4283c2c66affSColin Finck {
4284c2c66affSColin Finck TRACE("Rendering onscreen.\n");
4285c2c66affSColin Finck
4286c2c66affSColin Finck context = swapchain_get_context(texture->swapchain);
4287c2c66affSColin Finck }
4288c2c66affSColin Finck else
4289c2c66affSColin Finck {
4290c2c66affSColin Finck TRACE("Rendering offscreen.\n");
4291c2c66affSColin Finck
4292c2c66affSColin Finck /* Stay with the current context if possible. Otherwise use the
4293c2c66affSColin Finck * context for the primary swapchain. */
4294c2c66affSColin Finck if (current_context && current_context->device == device)
4295c2c66affSColin Finck context = current_context;
4296c2c66affSColin Finck else
4297c2c66affSColin Finck context = swapchain_get_context(device->swapchains[0]);
4298c2c66affSColin Finck }
4299c2c66affSColin Finck
43009987f029SAmine Khaldi context_activate(context, texture, sub_resource_idx);
4301c2c66affSColin Finck
4302c2c66affSColin Finck return context;
4303c2c66affSColin Finck }
4304c2c66affSColin Finck
context_reacquire(const struct wined3d_device * device,struct wined3d_context * context)4305c2c66affSColin Finck struct wined3d_context *context_reacquire(const struct wined3d_device *device,
4306c2c66affSColin Finck struct wined3d_context *context)
4307c2c66affSColin Finck {
43089987f029SAmine Khaldi struct wined3d_context *acquired_context;
43099987f029SAmine Khaldi
43109987f029SAmine Khaldi wined3d_from_cs(device->cs);
4311c2c66affSColin Finck
4312c2c66affSColin Finck if (!context || context->tid != GetCurrentThreadId())
4313c2c66affSColin Finck return NULL;
4314c2c66affSColin Finck
43159987f029SAmine Khaldi if (context->current_rt.texture)
43169987f029SAmine Khaldi {
43179987f029SAmine Khaldi context_activate(context, context->current_rt.texture, context->current_rt.sub_resource_idx);
43189987f029SAmine Khaldi return context;
43199987f029SAmine Khaldi }
43209987f029SAmine Khaldi
43219987f029SAmine Khaldi acquired_context = context_acquire(device, NULL, 0);
43229987f029SAmine Khaldi if (acquired_context != context)
43239987f029SAmine Khaldi ERR("Acquired context %p instead of %p.\n", acquired_context, context);
43249987f029SAmine Khaldi return acquired_context;
43259987f029SAmine Khaldi }
43269987f029SAmine Khaldi
dispatch_compute(struct wined3d_device * device,const struct wined3d_state * state,const struct wined3d_dispatch_parameters * parameters)43279987f029SAmine Khaldi void dispatch_compute(struct wined3d_device *device, const struct wined3d_state *state,
43289987f029SAmine Khaldi const struct wined3d_dispatch_parameters *parameters)
43299987f029SAmine Khaldi {
43309987f029SAmine Khaldi const struct wined3d_gl_info *gl_info;
43319987f029SAmine Khaldi struct wined3d_context *context;
43329987f029SAmine Khaldi
43339987f029SAmine Khaldi context = context_acquire(device, NULL, 0);
43349987f029SAmine Khaldi if (!context->valid)
43359987f029SAmine Khaldi {
43369987f029SAmine Khaldi context_release(context);
43379987f029SAmine Khaldi WARN("Invalid context, skipping dispatch.\n");
43389987f029SAmine Khaldi return;
43399987f029SAmine Khaldi }
43409987f029SAmine Khaldi gl_info = context->gl_info;
43419987f029SAmine Khaldi
43429987f029SAmine Khaldi if (!gl_info->supported[ARB_COMPUTE_SHADER])
43439987f029SAmine Khaldi {
43449987f029SAmine Khaldi context_release(context);
43459987f029SAmine Khaldi FIXME("OpenGL implementation does not support compute shaders.\n");
43469987f029SAmine Khaldi return;
43479987f029SAmine Khaldi }
43489987f029SAmine Khaldi
43499987f029SAmine Khaldi if (parameters->indirect)
43509987f029SAmine Khaldi wined3d_buffer_load(parameters->u.indirect.buffer, context, state);
43519987f029SAmine Khaldi
43529987f029SAmine Khaldi context_apply_compute_state(context, device, state);
43539987f029SAmine Khaldi
43549987f029SAmine Khaldi if (!state->shader[WINED3D_SHADER_TYPE_COMPUTE])
43559987f029SAmine Khaldi {
43569987f029SAmine Khaldi context_release(context);
43579987f029SAmine Khaldi WARN("No compute shader bound, skipping dispatch.\n");
43589987f029SAmine Khaldi return;
43599987f029SAmine Khaldi }
43609987f029SAmine Khaldi
43619987f029SAmine Khaldi if (parameters->indirect)
43629987f029SAmine Khaldi {
43639987f029SAmine Khaldi const struct wined3d_indirect_dispatch_parameters *indirect = ¶meters->u.indirect;
43649987f029SAmine Khaldi struct wined3d_buffer *buffer = indirect->buffer;
43659987f029SAmine Khaldi
43669987f029SAmine Khaldi GL_EXTCALL(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer->buffer_object));
43679987f029SAmine Khaldi GL_EXTCALL(glDispatchComputeIndirect((GLintptr)indirect->offset));
43689987f029SAmine Khaldi GL_EXTCALL(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0));
43699987f029SAmine Khaldi }
43709987f029SAmine Khaldi else
43719987f029SAmine Khaldi {
43729987f029SAmine Khaldi const struct wined3d_direct_dispatch_parameters *direct = ¶meters->u.direct;
43739987f029SAmine Khaldi GL_EXTCALL(glDispatchCompute(direct->group_count_x, direct->group_count_y, direct->group_count_z));
43749987f029SAmine Khaldi }
43759987f029SAmine Khaldi checkGLcall("dispatch compute");
43769987f029SAmine Khaldi
43779987f029SAmine Khaldi GL_EXTCALL(glMemoryBarrier(GL_ALL_BARRIER_BITS));
43789987f029SAmine Khaldi checkGLcall("glMemoryBarrier");
43799987f029SAmine Khaldi
4380*81cffd76SJoachim Henze if (wined3d_settings.strict_draw_ordering)
4381*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
4382*81cffd76SJoachim Henze
43839987f029SAmine Khaldi context_release(context);
43849987f029SAmine Khaldi }
43859987f029SAmine Khaldi
43869987f029SAmine Khaldi /* 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)43879987f029SAmine Khaldi static void draw_primitive_arrays(struct wined3d_context *context, const struct wined3d_state *state,
43889987f029SAmine Khaldi const void *idx_data, unsigned int idx_size, int base_vertex_idx, unsigned int start_idx,
43899987f029SAmine Khaldi unsigned int count, unsigned int start_instance, unsigned int instance_count)
43909987f029SAmine Khaldi {
43919987f029SAmine Khaldi const struct wined3d_ffp_attrib_ops *ops = &context->d3d_info->ffp_attrib_ops;
43929987f029SAmine Khaldi GLenum idx_type = idx_size == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
43939987f029SAmine Khaldi const struct wined3d_stream_info *si = &context->stream_info;
43949987f029SAmine Khaldi unsigned int instanced_elements[ARRAY_SIZE(si->elements)];
43959987f029SAmine Khaldi const struct wined3d_gl_info *gl_info = context->gl_info;
43969987f029SAmine Khaldi unsigned int instanced_element_count = 0;
43979987f029SAmine Khaldi GLenum mode = state->gl_primitive_type;
43989987f029SAmine Khaldi const void *indices;
43999987f029SAmine Khaldi unsigned int i, j;
44009987f029SAmine Khaldi
44019987f029SAmine Khaldi indices = (const char *)idx_data + idx_size * start_idx;
44029987f029SAmine Khaldi
44039987f029SAmine Khaldi if (!instance_count)
44049987f029SAmine Khaldi {
44059987f029SAmine Khaldi if (!idx_size)
44069987f029SAmine Khaldi {
44079987f029SAmine Khaldi gl_info->gl_ops.gl.p_glDrawArrays(mode, start_idx, count);
44089987f029SAmine Khaldi checkGLcall("glDrawArrays");
44099987f029SAmine Khaldi return;
44109987f029SAmine Khaldi }
44119987f029SAmine Khaldi
44129987f029SAmine Khaldi if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
44139987f029SAmine Khaldi {
44149987f029SAmine Khaldi GL_EXTCALL(glDrawElementsBaseVertex(mode, count, idx_type, indices, base_vertex_idx));
44159987f029SAmine Khaldi checkGLcall("glDrawElementsBaseVertex");
44169987f029SAmine Khaldi return;
44179987f029SAmine Khaldi }
44189987f029SAmine Khaldi
44199987f029SAmine Khaldi gl_info->gl_ops.gl.p_glDrawElements(mode, count, idx_type, indices);
44209987f029SAmine Khaldi checkGLcall("glDrawElements");
44219987f029SAmine Khaldi return;
44229987f029SAmine Khaldi }
44239987f029SAmine Khaldi
44249987f029SAmine Khaldi if (start_instance && !(gl_info->supported[ARB_BASE_INSTANCE] && gl_info->supported[ARB_INSTANCED_ARRAYS]))
44259987f029SAmine Khaldi FIXME("Start instance (%u) not supported.\n", start_instance);
44269987f029SAmine Khaldi
44279987f029SAmine Khaldi if (gl_info->supported[ARB_INSTANCED_ARRAYS])
44289987f029SAmine Khaldi {
44299987f029SAmine Khaldi if (!idx_size)
44309987f029SAmine Khaldi {
44319987f029SAmine Khaldi if (gl_info->supported[ARB_BASE_INSTANCE])
44329987f029SAmine Khaldi {
44339987f029SAmine Khaldi GL_EXTCALL(glDrawArraysInstancedBaseInstance(mode, start_idx, count, instance_count, start_instance));
44349987f029SAmine Khaldi checkGLcall("glDrawArraysInstancedBaseInstance");
44359987f029SAmine Khaldi return;
44369987f029SAmine Khaldi }
44379987f029SAmine Khaldi
44389987f029SAmine Khaldi GL_EXTCALL(glDrawArraysInstanced(mode, start_idx, count, instance_count));
44399987f029SAmine Khaldi checkGLcall("glDrawArraysInstanced");
44409987f029SAmine Khaldi return;
44419987f029SAmine Khaldi }
44429987f029SAmine Khaldi
44439987f029SAmine Khaldi if (gl_info->supported[ARB_BASE_INSTANCE])
44449987f029SAmine Khaldi {
44459987f029SAmine Khaldi GL_EXTCALL(glDrawElementsInstancedBaseVertexBaseInstance(mode, count, idx_type,
44469987f029SAmine Khaldi indices, instance_count, base_vertex_idx, start_instance));
44479987f029SAmine Khaldi checkGLcall("glDrawElementsInstancedBaseVertexBaseInstance");
44489987f029SAmine Khaldi return;
44499987f029SAmine Khaldi }
44509987f029SAmine Khaldi if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
44519987f029SAmine Khaldi {
44529987f029SAmine Khaldi GL_EXTCALL(glDrawElementsInstancedBaseVertex(mode, count, idx_type,
44539987f029SAmine Khaldi indices, instance_count, base_vertex_idx));
44549987f029SAmine Khaldi checkGLcall("glDrawElementsInstancedBaseVertex");
44559987f029SAmine Khaldi return;
44569987f029SAmine Khaldi }
44579987f029SAmine Khaldi
44589987f029SAmine Khaldi GL_EXTCALL(glDrawElementsInstanced(mode, count, idx_type, indices, instance_count));
44599987f029SAmine Khaldi checkGLcall("glDrawElementsInstanced");
44609987f029SAmine Khaldi return;
44619987f029SAmine Khaldi }
44629987f029SAmine Khaldi
44639987f029SAmine Khaldi /* Instancing emulation by mixing immediate mode and arrays. */
44649987f029SAmine Khaldi
44659987f029SAmine Khaldi /* This is a nasty thing. MSDN says no hardware supports this and
44669987f029SAmine Khaldi * applications have to use software vertex processing. We don't support
44679987f029SAmine Khaldi * this for now.
44689987f029SAmine Khaldi *
44699987f029SAmine Khaldi * Shouldn't be too hard to support with OpenGL, in theory just call
44709987f029SAmine Khaldi * glDrawArrays() instead of drawElements(). But the stream fequency value
44719987f029SAmine Khaldi * has a different meaning in that situation. */
44729987f029SAmine Khaldi if (!idx_size)
44739987f029SAmine Khaldi {
44749987f029SAmine Khaldi FIXME("Non-indexed instanced drawing is not supported.\n");
44759987f029SAmine Khaldi return;
44769987f029SAmine Khaldi }
44779987f029SAmine Khaldi
44789987f029SAmine Khaldi for (i = 0; i < ARRAY_SIZE(si->elements); ++i)
44799987f029SAmine Khaldi {
44809987f029SAmine Khaldi if (!(si->use_map & (1u << i)))
44819987f029SAmine Khaldi continue;
44829987f029SAmine Khaldi
44839987f029SAmine Khaldi if (state->streams[si->elements[i].stream_idx].flags & WINED3DSTREAMSOURCE_INSTANCEDATA)
44849987f029SAmine Khaldi instanced_elements[instanced_element_count++] = i;
44859987f029SAmine Khaldi }
44869987f029SAmine Khaldi
44879987f029SAmine Khaldi for (i = 0; i < instance_count; ++i)
44889987f029SAmine Khaldi {
44899987f029SAmine Khaldi /* Specify the instanced attributes using immediate mode calls. */
44909987f029SAmine Khaldi for (j = 0; j < instanced_element_count; ++j)
44919987f029SAmine Khaldi {
44929987f029SAmine Khaldi const struct wined3d_stream_info_element *element;
44939987f029SAmine Khaldi unsigned int element_idx;
44949987f029SAmine Khaldi const BYTE *ptr;
44959987f029SAmine Khaldi
44969987f029SAmine Khaldi element_idx = instanced_elements[j];
44979987f029SAmine Khaldi element = &si->elements[element_idx];
44989987f029SAmine Khaldi ptr = element->data.addr + element->stride * i;
44999987f029SAmine Khaldi if (element->data.buffer_object)
45009987f029SAmine Khaldi ptr += (ULONG_PTR)wined3d_buffer_load_sysmem(state->streams[element->stream_idx].buffer, context);
45019987f029SAmine Khaldi ops->generic[element->format->emit_idx](element_idx, ptr);
45029987f029SAmine Khaldi }
45039987f029SAmine Khaldi
45049987f029SAmine Khaldi if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
45059987f029SAmine Khaldi {
45069987f029SAmine Khaldi GL_EXTCALL(glDrawElementsBaseVertex(mode, count, idx_type, indices, base_vertex_idx));
45079987f029SAmine Khaldi checkGLcall("glDrawElementsBaseVertex");
45089987f029SAmine Khaldi }
45099987f029SAmine Khaldi else
45109987f029SAmine Khaldi {
45119987f029SAmine Khaldi gl_info->gl_ops.gl.p_glDrawElements(mode, count, idx_type, indices);
45129987f029SAmine Khaldi checkGLcall("glDrawElements");
45139987f029SAmine Khaldi }
45149987f029SAmine Khaldi }
45159987f029SAmine Khaldi }
45169987f029SAmine Khaldi
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)45179987f029SAmine Khaldi static const BYTE *software_vertex_blending(struct wined3d_context *context,
45189987f029SAmine Khaldi const struct wined3d_state *state, const struct wined3d_stream_info *si,
45199987f029SAmine Khaldi unsigned int element_idx, unsigned int stride_idx, float *result)
45209987f029SAmine Khaldi {
45219987f029SAmine Khaldi #define SI_FORMAT(idx) (si->elements[(idx)].format->emit_idx)
45229987f029SAmine Khaldi #define SI_PTR(idx1, idx2) (si->elements[(idx1)].data.addr + si->elements[(idx1)].stride * (idx2))
45239987f029SAmine Khaldi
45249987f029SAmine Khaldi const float *data = (const float *)SI_PTR(element_idx, stride_idx);
45259987f029SAmine Khaldi float vector[4] = {0.0f, 0.0f, 0.0f, 1.0f};
45269987f029SAmine Khaldi float cur_weight, weight_sum = 0.0f;
45279987f029SAmine Khaldi struct wined3d_matrix m;
45289987f029SAmine Khaldi const BYTE *blend_index;
45299987f029SAmine Khaldi const float *weights;
45309987f029SAmine Khaldi int i, num_weights;
45319987f029SAmine Khaldi
45329987f029SAmine Khaldi if (element_idx != WINED3D_FFP_POSITION && element_idx != WINED3D_FFP_NORMAL)
45339987f029SAmine Khaldi return (BYTE *)data;
45349987f029SAmine Khaldi
45359987f029SAmine Khaldi if (!use_indexed_vertex_blending(state, si) || !use_software_vertex_processing(context->device))
45369987f029SAmine Khaldi return (BYTE *)data;
45379987f029SAmine Khaldi
45389987f029SAmine Khaldi if (!si->elements[WINED3D_FFP_BLENDINDICES].data.addr ||
45399987f029SAmine Khaldi !si->elements[WINED3D_FFP_BLENDWEIGHT].data.addr)
45409987f029SAmine Khaldi {
45419987f029SAmine Khaldi FIXME("no blend indices / weights set\n");
45429987f029SAmine Khaldi return (BYTE *)data;
45439987f029SAmine Khaldi }
45449987f029SAmine Khaldi
45459987f029SAmine Khaldi if (SI_FORMAT(WINED3D_FFP_BLENDINDICES) != WINED3D_FFP_EMIT_UBYTE4)
45469987f029SAmine Khaldi {
45479987f029SAmine Khaldi FIXME("unsupported blend index format: %u\n", SI_FORMAT(WINED3D_FFP_BLENDINDICES));
45489987f029SAmine Khaldi return (BYTE *)data;
45499987f029SAmine Khaldi }
45509987f029SAmine Khaldi
45519987f029SAmine Khaldi /* FIXME: validate weight format */
45529987f029SAmine Khaldi switch (state->render_states[WINED3D_RS_VERTEXBLEND])
45539987f029SAmine Khaldi {
45549987f029SAmine Khaldi case WINED3D_VBF_0WEIGHTS: num_weights = 0; break;
45559987f029SAmine Khaldi case WINED3D_VBF_1WEIGHTS: num_weights = 1; break;
45569987f029SAmine Khaldi case WINED3D_VBF_2WEIGHTS: num_weights = 2; break;
45579987f029SAmine Khaldi case WINED3D_VBF_3WEIGHTS: num_weights = 3; break;
45589987f029SAmine Khaldi default:
45599987f029SAmine Khaldi FIXME("unsupported vertex blend render state: %u\n", state->render_states[WINED3D_RS_VERTEXBLEND]);
45609987f029SAmine Khaldi return (BYTE *)data;
45619987f029SAmine Khaldi }
45629987f029SAmine Khaldi
45639987f029SAmine Khaldi switch (SI_FORMAT(element_idx))
45649987f029SAmine Khaldi {
45659987f029SAmine Khaldi case WINED3D_FFP_EMIT_FLOAT4: vector[3] = data[3];
45669987f029SAmine Khaldi case WINED3D_FFP_EMIT_FLOAT3: vector[2] = data[2];
45679987f029SAmine Khaldi case WINED3D_FFP_EMIT_FLOAT2: vector[1] = data[1];
45689987f029SAmine Khaldi default:
45699987f029SAmine Khaldi FIXME("unsupported value format: %u\n", SI_FORMAT(element_idx));
45709987f029SAmine Khaldi return (BYTE *)data;
45719987f029SAmine Khaldi }
45729987f029SAmine Khaldi
45739987f029SAmine Khaldi blend_index = SI_PTR(WINED3D_FFP_BLENDINDICES, stride_idx);
45749987f029SAmine Khaldi weights = (const float *)SI_PTR(WINED3D_FFP_BLENDWEIGHT, stride_idx);
45759987f029SAmine Khaldi result[0] = result[1] = result[2] = result[3] = 0.0f;
45769987f029SAmine Khaldi
45779987f029SAmine Khaldi for (i = 0; i < num_weights + 1; i++)
45789987f029SAmine Khaldi {
45799987f029SAmine Khaldi cur_weight = (i < num_weights) ? weights[i] : 1.0f - weight_sum;
45809987f029SAmine Khaldi get_modelview_matrix(context, state, blend_index[i], &m);
45819987f029SAmine Khaldi
45829987f029SAmine Khaldi if (element_idx == WINED3D_FFP_POSITION)
45839987f029SAmine Khaldi {
45849987f029SAmine Khaldi result[0] += cur_weight * (vector[0] * m._11 + vector[1] * m._21 + vector[2] * m._31 + vector[3] * m._41);
45859987f029SAmine Khaldi result[1] += cur_weight * (vector[0] * m._12 + vector[1] * m._22 + vector[2] * m._32 + vector[3] * m._42);
45869987f029SAmine Khaldi result[2] += cur_weight * (vector[0] * m._13 + vector[1] * m._23 + vector[2] * m._33 + vector[3] * m._43);
45879987f029SAmine Khaldi result[3] += cur_weight * (vector[0] * m._14 + vector[1] * m._24 + vector[2] * m._34 + vector[3] * m._44);
45889987f029SAmine Khaldi }
45899987f029SAmine Khaldi else
45909987f029SAmine Khaldi {
45919987f029SAmine Khaldi if (context->d3d_info->wined3d_creation_flags & WINED3D_LEGACY_FFP_LIGHTING)
45929987f029SAmine Khaldi invert_matrix_3d(&m, &m);
45939987f029SAmine Khaldi else
45949987f029SAmine Khaldi invert_matrix(&m, &m);
45959987f029SAmine Khaldi
45969987f029SAmine Khaldi /* multiply with transposed M */
45979987f029SAmine Khaldi result[0] += cur_weight * (vector[0] * m._11 + vector[1] * m._12 + vector[2] * m._13);
45989987f029SAmine Khaldi result[1] += cur_weight * (vector[0] * m._21 + vector[1] * m._22 + vector[2] * m._23);
45999987f029SAmine Khaldi result[2] += cur_weight * (vector[0] * m._31 + vector[1] * m._32 + vector[2] * m._33);
46009987f029SAmine Khaldi }
46019987f029SAmine Khaldi
46029987f029SAmine Khaldi weight_sum += weights[i];
46039987f029SAmine Khaldi }
46049987f029SAmine Khaldi
46059987f029SAmine Khaldi #undef SI_FORMAT
46069987f029SAmine Khaldi #undef SI_PTR
46079987f029SAmine Khaldi
46089987f029SAmine Khaldi return (BYTE *)result;
46099987f029SAmine Khaldi }
46109987f029SAmine Khaldi
get_stride_idx(const void * idx_data,unsigned int idx_size,unsigned int base_vertex_idx,unsigned int start_idx,unsigned int vertex_idx)46119987f029SAmine Khaldi static unsigned int get_stride_idx(const void *idx_data, unsigned int idx_size,
46129987f029SAmine Khaldi unsigned int base_vertex_idx, unsigned int start_idx, unsigned int vertex_idx)
46139987f029SAmine Khaldi {
46149987f029SAmine Khaldi if (!idx_data)
46159987f029SAmine Khaldi return start_idx + vertex_idx;
46169987f029SAmine Khaldi if (idx_size == 2)
46179987f029SAmine Khaldi return ((const WORD *)idx_data)[start_idx + vertex_idx] + base_vertex_idx;
46189987f029SAmine Khaldi return ((const DWORD *)idx_data)[start_idx + vertex_idx] + base_vertex_idx;
46199987f029SAmine Khaldi }
46209987f029SAmine Khaldi
46219987f029SAmine Khaldi /* 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)46229987f029SAmine Khaldi static void draw_primitive_immediate_mode(struct wined3d_context *context, const struct wined3d_state *state,
46239987f029SAmine Khaldi const struct wined3d_stream_info *si, const void *idx_data, unsigned int idx_size,
46249987f029SAmine Khaldi int base_vertex_idx, unsigned int start_idx, unsigned int vertex_count, unsigned int instance_count)
46259987f029SAmine Khaldi {
46269987f029SAmine Khaldi const BYTE *position = NULL, *normal = NULL, *diffuse = NULL, *specular = NULL;
46279987f029SAmine Khaldi const struct wined3d_d3d_info *d3d_info = context->d3d_info;
46289987f029SAmine Khaldi unsigned int coord_idx, stride_idx, texture_idx, vertex_idx;
46299987f029SAmine Khaldi const struct wined3d_gl_info *gl_info = context->gl_info;
46309987f029SAmine Khaldi const struct wined3d_stream_info_element *element;
46319987f029SAmine Khaldi const BYTE *tex_coords[WINED3DDP_MAXTEXCOORD];
46329987f029SAmine Khaldi unsigned int texture_unit, texture_stages;
46339987f029SAmine Khaldi const struct wined3d_ffp_attrib_ops *ops;
46349987f029SAmine Khaldi unsigned int untracked_material_count;
46359987f029SAmine Khaldi unsigned int tex_mask = 0;
46369987f029SAmine Khaldi BOOL specular_fog = FALSE;
46379987f029SAmine Khaldi BOOL ps = use_ps(state);
46389987f029SAmine Khaldi const void *ptr;
46399987f029SAmine Khaldi float tmp[4];
46409987f029SAmine Khaldi
46419987f029SAmine Khaldi static unsigned int once;
46429987f029SAmine Khaldi
46439987f029SAmine Khaldi if (!once++)
46449987f029SAmine Khaldi FIXME_(d3d_perf)("Drawing using immediate mode.\n");
46459987f029SAmine Khaldi else
46469987f029SAmine Khaldi WARN_(d3d_perf)("Drawing using immediate mode.\n");
46479987f029SAmine Khaldi
46489987f029SAmine Khaldi if (!idx_size && idx_data)
46499987f029SAmine Khaldi ERR("Non-NULL idx_data with 0 idx_size, this should never happen.\n");
46509987f029SAmine Khaldi
46519987f029SAmine Khaldi if (instance_count)
46529987f029SAmine Khaldi FIXME("Instancing not implemented.\n");
46539987f029SAmine Khaldi
46549987f029SAmine Khaldi /* Immediate mode drawing can't make use of indices in a VBO - get the
46559987f029SAmine Khaldi * data from the index buffer. */
46569987f029SAmine Khaldi if (idx_size)
46579987f029SAmine Khaldi idx_data = wined3d_buffer_load_sysmem(state->index_buffer, context) + state->index_offset;
46589987f029SAmine Khaldi
46599987f029SAmine Khaldi ops = &d3d_info->ffp_attrib_ops;
46609987f029SAmine Khaldi
46619987f029SAmine Khaldi gl_info->gl_ops.gl.p_glBegin(state->gl_primitive_type);
46629987f029SAmine Khaldi
46639987f029SAmine Khaldi if (use_vs(state) || d3d_info->ffp_generic_attributes)
46649987f029SAmine Khaldi {
46659987f029SAmine Khaldi for (vertex_idx = 0; vertex_idx < vertex_count; ++vertex_idx)
46669987f029SAmine Khaldi {
46679987f029SAmine Khaldi unsigned int use_map = si->use_map;
46689987f029SAmine Khaldi unsigned int element_idx;
46699987f029SAmine Khaldi
46709987f029SAmine Khaldi stride_idx = get_stride_idx(idx_data, idx_size, base_vertex_idx, start_idx, vertex_idx);
46719987f029SAmine Khaldi for (element_idx = MAX_ATTRIBS - 1; use_map; use_map &= ~(1u << element_idx), --element_idx)
46729987f029SAmine Khaldi {
46739987f029SAmine Khaldi if (!(use_map & 1u << element_idx))
46749987f029SAmine Khaldi continue;
46759987f029SAmine Khaldi
46769987f029SAmine Khaldi ptr = software_vertex_blending(context, state, si, element_idx, stride_idx, tmp);
46779987f029SAmine Khaldi ops->generic[si->elements[element_idx].format->emit_idx](element_idx, ptr);
46789987f029SAmine Khaldi }
46799987f029SAmine Khaldi }
46809987f029SAmine Khaldi
46819987f029SAmine Khaldi gl_info->gl_ops.gl.p_glEnd();
46829987f029SAmine Khaldi return;
46839987f029SAmine Khaldi }
46849987f029SAmine Khaldi
46859987f029SAmine Khaldi if (si->use_map & (1u << WINED3D_FFP_POSITION))
46869987f029SAmine Khaldi position = si->elements[WINED3D_FFP_POSITION].data.addr;
46879987f029SAmine Khaldi
46889987f029SAmine Khaldi if (si->use_map & (1u << WINED3D_FFP_NORMAL))
46899987f029SAmine Khaldi normal = si->elements[WINED3D_FFP_NORMAL].data.addr;
46909987f029SAmine Khaldi else
46919987f029SAmine Khaldi gl_info->gl_ops.gl.p_glNormal3f(0.0f, 0.0f, 0.0f);
46929987f029SAmine Khaldi
46939987f029SAmine Khaldi untracked_material_count = context->num_untracked_materials;
46949987f029SAmine Khaldi if (si->use_map & (1u << WINED3D_FFP_DIFFUSE))
46959987f029SAmine Khaldi {
46969987f029SAmine Khaldi element = &si->elements[WINED3D_FFP_DIFFUSE];
46979987f029SAmine Khaldi diffuse = element->data.addr;
46989987f029SAmine Khaldi
46999987f029SAmine Khaldi if (untracked_material_count && element->format->id != WINED3DFMT_B8G8R8A8_UNORM)
47009987f029SAmine Khaldi FIXME("Implement diffuse color tracking from %s.\n", debug_d3dformat(element->format->id));
47019987f029SAmine Khaldi }
47029987f029SAmine Khaldi else
47039987f029SAmine Khaldi {
47049987f029SAmine Khaldi gl_info->gl_ops.gl.p_glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
47059987f029SAmine Khaldi }
47069987f029SAmine Khaldi
47079987f029SAmine Khaldi if (si->use_map & (1u << WINED3D_FFP_SPECULAR))
47089987f029SAmine Khaldi {
47099987f029SAmine Khaldi element = &si->elements[WINED3D_FFP_SPECULAR];
47109987f029SAmine Khaldi specular = element->data.addr;
47119987f029SAmine Khaldi
47129987f029SAmine Khaldi /* Special case where the fog density is stored in the specular alpha channel. */
47139987f029SAmine Khaldi if (state->render_states[WINED3D_RS_FOGENABLE]
47149987f029SAmine Khaldi && (state->render_states[WINED3D_RS_FOGVERTEXMODE] == WINED3D_FOG_NONE
47159987f029SAmine Khaldi || si->elements[WINED3D_FFP_POSITION].format->id == WINED3DFMT_R32G32B32A32_FLOAT)
47169987f029SAmine Khaldi && state->render_states[WINED3D_RS_FOGTABLEMODE] == WINED3D_FOG_NONE)
47179987f029SAmine Khaldi {
47189987f029SAmine Khaldi if (gl_info->supported[EXT_FOG_COORD])
47199987f029SAmine Khaldi {
47209987f029SAmine Khaldi if (element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
47219987f029SAmine Khaldi specular_fog = TRUE;
47229987f029SAmine Khaldi else
47239987f029SAmine Khaldi FIXME("Implement fog coordinates from %s.\n", debug_d3dformat(element->format->id));
47249987f029SAmine Khaldi }
47259987f029SAmine Khaldi else
47269987f029SAmine Khaldi {
47279987f029SAmine Khaldi static unsigned int once;
47289987f029SAmine Khaldi
47299987f029SAmine Khaldi if (!once++)
47309987f029SAmine Khaldi FIXME("Implement fog for transformed vertices in software.\n");
47319987f029SAmine Khaldi }
47329987f029SAmine Khaldi }
47339987f029SAmine Khaldi }
47349987f029SAmine Khaldi else if (gl_info->supported[EXT_SECONDARY_COLOR])
47359987f029SAmine Khaldi {
47369987f029SAmine Khaldi GL_EXTCALL(glSecondaryColor3fEXT)(0.0f, 0.0f, 0.0f);
47379987f029SAmine Khaldi }
47389987f029SAmine Khaldi
47399987f029SAmine Khaldi texture_stages = d3d_info->limits.ffp_blend_stages;
47409987f029SAmine Khaldi for (texture_idx = 0; texture_idx < texture_stages; ++texture_idx)
47419987f029SAmine Khaldi {
47429987f029SAmine Khaldi if (!gl_info->supported[ARB_MULTITEXTURE] && texture_idx > 0)
47439987f029SAmine Khaldi {
47449987f029SAmine Khaldi FIXME("Program using multiple concurrent textures which this OpenGL implementation doesn't support.\n");
47459987f029SAmine Khaldi continue;
47469987f029SAmine Khaldi }
47479987f029SAmine Khaldi
47489987f029SAmine Khaldi if (!ps && !state->textures[texture_idx])
47499987f029SAmine Khaldi continue;
47509987f029SAmine Khaldi
47519987f029SAmine Khaldi texture_unit = context->tex_unit_map[texture_idx];
47529987f029SAmine Khaldi if (texture_unit == WINED3D_UNMAPPED_STAGE)
47539987f029SAmine Khaldi continue;
47549987f029SAmine Khaldi
47559987f029SAmine Khaldi coord_idx = state->texture_states[texture_idx][WINED3D_TSS_TEXCOORD_INDEX];
47569987f029SAmine Khaldi if (coord_idx > 7)
47579987f029SAmine Khaldi {
47589987f029SAmine Khaldi TRACE("Skipping generated coordinates (%#x) for texture %u.\n", coord_idx, texture_idx);
47599987f029SAmine Khaldi continue;
47609987f029SAmine Khaldi }
47619987f029SAmine Khaldi
47629987f029SAmine Khaldi if (si->use_map & (1u << (WINED3D_FFP_TEXCOORD0 + coord_idx)))
47639987f029SAmine Khaldi {
47649987f029SAmine Khaldi tex_coords[coord_idx] = si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].data.addr;
47659987f029SAmine Khaldi tex_mask |= (1u << texture_idx);
47669987f029SAmine Khaldi }
47679987f029SAmine Khaldi else
47689987f029SAmine Khaldi {
47699987f029SAmine Khaldi TRACE("Setting default coordinates for texture %u.\n", texture_idx);
47709987f029SAmine Khaldi if (gl_info->supported[ARB_MULTITEXTURE])
47719987f029SAmine Khaldi GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_unit, 0.0f, 0.0f, 0.0f, 1.0f));
47729987f029SAmine Khaldi else
47739987f029SAmine Khaldi gl_info->gl_ops.gl.p_glTexCoord4f(0.0f, 0.0f, 0.0f, 1.0f);
47749987f029SAmine Khaldi }
47759987f029SAmine Khaldi }
47769987f029SAmine Khaldi
47779987f029SAmine Khaldi /* Blending data and point sizes are not supported by this function. They
47789987f029SAmine Khaldi * are not supported by the fixed function pipeline at all. A FIXME for
47799987f029SAmine Khaldi * them is printed after decoding the vertex declaration. */
47809987f029SAmine Khaldi for (vertex_idx = 0; vertex_idx < vertex_count; ++vertex_idx)
47819987f029SAmine Khaldi {
47829987f029SAmine Khaldi unsigned int tmp_tex_mask;
47839987f029SAmine Khaldi
47849987f029SAmine Khaldi stride_idx = get_stride_idx(idx_data, idx_size, base_vertex_idx, start_idx, vertex_idx);
47859987f029SAmine Khaldi
47869987f029SAmine Khaldi if (normal)
47879987f029SAmine Khaldi {
47889987f029SAmine Khaldi ptr = software_vertex_blending(context, state, si, WINED3D_FFP_NORMAL, stride_idx, tmp);
47899987f029SAmine Khaldi ops->normal[si->elements[WINED3D_FFP_NORMAL].format->emit_idx](ptr);
47909987f029SAmine Khaldi }
47919987f029SAmine Khaldi
47929987f029SAmine Khaldi if (diffuse)
47939987f029SAmine Khaldi {
47949987f029SAmine Khaldi ptr = diffuse + stride_idx * si->elements[WINED3D_FFP_DIFFUSE].stride;
47959987f029SAmine Khaldi ops->diffuse[si->elements[WINED3D_FFP_DIFFUSE].format->emit_idx](ptr);
47969987f029SAmine Khaldi
47979987f029SAmine Khaldi if (untracked_material_count)
47989987f029SAmine Khaldi {
47999987f029SAmine Khaldi struct wined3d_color color;
48009987f029SAmine Khaldi unsigned int i;
48019987f029SAmine Khaldi
48029987f029SAmine Khaldi wined3d_color_from_d3dcolor(&color, *(const DWORD *)ptr);
48039987f029SAmine Khaldi for (i = 0; i < untracked_material_count; ++i)
48049987f029SAmine Khaldi {
48059987f029SAmine Khaldi gl_info->gl_ops.gl.p_glMaterialfv(GL_FRONT_AND_BACK, context->untracked_materials[i], &color.r);
48069987f029SAmine Khaldi }
48079987f029SAmine Khaldi }
48089987f029SAmine Khaldi }
48099987f029SAmine Khaldi
48109987f029SAmine Khaldi if (specular)
48119987f029SAmine Khaldi {
48129987f029SAmine Khaldi ptr = specular + stride_idx * si->elements[WINED3D_FFP_SPECULAR].stride;
48139987f029SAmine Khaldi ops->specular[si->elements[WINED3D_FFP_SPECULAR].format->emit_idx](ptr);
48149987f029SAmine Khaldi
48159987f029SAmine Khaldi if (specular_fog)
48169987f029SAmine Khaldi GL_EXTCALL(glFogCoordfEXT((float)(*(const DWORD *)ptr >> 24)));
48179987f029SAmine Khaldi }
48189987f029SAmine Khaldi
48199987f029SAmine Khaldi tmp_tex_mask = tex_mask;
48209987f029SAmine Khaldi for (texture_idx = 0; tmp_tex_mask; tmp_tex_mask >>= 1, ++texture_idx)
48219987f029SAmine Khaldi {
48229987f029SAmine Khaldi if (!(tmp_tex_mask & 1))
48239987f029SAmine Khaldi continue;
48249987f029SAmine Khaldi
48259987f029SAmine Khaldi coord_idx = state->texture_states[texture_idx][WINED3D_TSS_TEXCOORD_INDEX];
48269987f029SAmine Khaldi ptr = tex_coords[coord_idx] + (stride_idx * si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].stride);
48279987f029SAmine Khaldi ops->texcoord[si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].format->emit_idx](
48289987f029SAmine Khaldi GL_TEXTURE0_ARB + context->tex_unit_map[texture_idx], ptr);
48299987f029SAmine Khaldi }
48309987f029SAmine Khaldi
48319987f029SAmine Khaldi if (position)
48329987f029SAmine Khaldi {
48339987f029SAmine Khaldi ptr = software_vertex_blending(context, state, si, WINED3D_FFP_POSITION, stride_idx, tmp);
48349987f029SAmine Khaldi ops->position[si->elements[WINED3D_FFP_POSITION].format->emit_idx](ptr);
48359987f029SAmine Khaldi }
48369987f029SAmine Khaldi }
48379987f029SAmine Khaldi
48389987f029SAmine Khaldi gl_info->gl_ops.gl.p_glEnd();
48399987f029SAmine Khaldi checkGLcall("draw immediate mode");
48409987f029SAmine Khaldi }
48419987f029SAmine Khaldi
draw_indirect(struct wined3d_context * context,const struct wined3d_state * state,const struct wined3d_indirect_draw_parameters * parameters,unsigned int idx_size)48429987f029SAmine Khaldi static void draw_indirect(struct wined3d_context *context, const struct wined3d_state *state,
48439987f029SAmine Khaldi const struct wined3d_indirect_draw_parameters *parameters, unsigned int idx_size)
48449987f029SAmine Khaldi {
48459987f029SAmine Khaldi const struct wined3d_gl_info *gl_info = context->gl_info;
48469987f029SAmine Khaldi struct wined3d_buffer *buffer = parameters->buffer;
48479987f029SAmine Khaldi const void *offset;
48489987f029SAmine Khaldi
48499987f029SAmine Khaldi if (!gl_info->supported[ARB_DRAW_INDIRECT])
48509987f029SAmine Khaldi {
48519987f029SAmine Khaldi FIXME("OpenGL implementation does not support indirect draws.\n");
48529987f029SAmine Khaldi return;
48539987f029SAmine Khaldi }
48549987f029SAmine Khaldi
48559987f029SAmine Khaldi GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->buffer_object));
48569987f029SAmine Khaldi
48579987f029SAmine Khaldi offset = (void *)(GLintptr)parameters->offset;
48589987f029SAmine Khaldi if (idx_size)
48599987f029SAmine Khaldi {
48609987f029SAmine Khaldi GLenum idx_type = idx_size == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
48619987f029SAmine Khaldi if (state->index_offset)
48629987f029SAmine Khaldi FIXME("Ignoring index offset %u.\n", state->index_offset);
48639987f029SAmine Khaldi GL_EXTCALL(glDrawElementsIndirect(state->gl_primitive_type, idx_type, offset));
48649987f029SAmine Khaldi }
48659987f029SAmine Khaldi else
48669987f029SAmine Khaldi {
48679987f029SAmine Khaldi GL_EXTCALL(glDrawArraysIndirect(state->gl_primitive_type, offset));
48689987f029SAmine Khaldi }
48699987f029SAmine Khaldi
48709987f029SAmine Khaldi GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));
48719987f029SAmine Khaldi
48729987f029SAmine Khaldi checkGLcall("draw indirect");
48739987f029SAmine Khaldi }
48749987f029SAmine Khaldi
remove_vbos(struct wined3d_context * context,const struct wined3d_state * state,struct wined3d_stream_info * s)48759987f029SAmine Khaldi static void remove_vbos(struct wined3d_context *context,
48769987f029SAmine Khaldi const struct wined3d_state *state, struct wined3d_stream_info *s)
48779987f029SAmine Khaldi {
48789987f029SAmine Khaldi unsigned int i;
48799987f029SAmine Khaldi
48809987f029SAmine Khaldi for (i = 0; i < ARRAY_SIZE(s->elements); ++i)
48819987f029SAmine Khaldi {
48829987f029SAmine Khaldi struct wined3d_stream_info_element *e;
48839987f029SAmine Khaldi
48849987f029SAmine Khaldi if (!(s->use_map & (1u << i)))
48859987f029SAmine Khaldi continue;
48869987f029SAmine Khaldi
48879987f029SAmine Khaldi e = &s->elements[i];
48889987f029SAmine Khaldi if (e->data.buffer_object)
48899987f029SAmine Khaldi {
48909987f029SAmine Khaldi struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer;
48919987f029SAmine Khaldi e->data.buffer_object = 0;
48929987f029SAmine Khaldi e->data.addr += (ULONG_PTR)wined3d_buffer_load_sysmem(vb, context);
48939987f029SAmine Khaldi }
48949987f029SAmine Khaldi }
48959987f029SAmine Khaldi }
48969987f029SAmine Khaldi
gl_tfb_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)48979987f029SAmine Khaldi static GLenum gl_tfb_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
48989987f029SAmine Khaldi {
48999987f029SAmine Khaldi GLenum gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
49009987f029SAmine Khaldi switch (gl_primitive_type)
49019987f029SAmine Khaldi {
49029987f029SAmine Khaldi case GL_POINTS:
49039987f029SAmine Khaldi return GL_POINTS;
49049987f029SAmine Khaldi
49059987f029SAmine Khaldi case GL_LINE_STRIP:
49069987f029SAmine Khaldi case GL_LINE_STRIP_ADJACENCY:
49079987f029SAmine Khaldi case GL_LINES_ADJACENCY:
49089987f029SAmine Khaldi case GL_LINES:
49099987f029SAmine Khaldi return GL_LINES;
49109987f029SAmine Khaldi
49119987f029SAmine Khaldi case GL_TRIANGLE_FAN:
49129987f029SAmine Khaldi case GL_TRIANGLE_STRIP:
49139987f029SAmine Khaldi case GL_TRIANGLE_STRIP_ADJACENCY:
49149987f029SAmine Khaldi case GL_TRIANGLES_ADJACENCY:
49159987f029SAmine Khaldi case GL_TRIANGLES:
49169987f029SAmine Khaldi return GL_TRIANGLES;
49179987f029SAmine Khaldi
49189987f029SAmine Khaldi default:
49199987f029SAmine Khaldi return gl_primitive_type;
49209987f029SAmine Khaldi }
49219987f029SAmine Khaldi }
49229987f029SAmine Khaldi
49239987f029SAmine Khaldi /* 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)49249987f029SAmine Khaldi void draw_primitive(struct wined3d_device *device, const struct wined3d_state *state,
49259987f029SAmine Khaldi const struct wined3d_draw_parameters *parameters)
49269987f029SAmine Khaldi {
49279987f029SAmine Khaldi BOOL emulation = FALSE, rasterizer_discard = FALSE;
49289987f029SAmine Khaldi const struct wined3d_fb_state *fb = state->fb;
49299987f029SAmine Khaldi const struct wined3d_stream_info *stream_info;
49309987f029SAmine Khaldi struct wined3d_rendertarget_view *dsv, *rtv;
49319987f029SAmine Khaldi struct wined3d_stream_info si_emulated;
49329987f029SAmine Khaldi struct wined3d_fence *ib_fence = NULL;
49339987f029SAmine Khaldi const struct wined3d_gl_info *gl_info;
49349987f029SAmine Khaldi struct wined3d_context *context;
49359987f029SAmine Khaldi unsigned int i, idx_size = 0;
49369987f029SAmine Khaldi const void *idx_data = NULL;
49379987f029SAmine Khaldi
49389987f029SAmine Khaldi if (!parameters->indirect && !parameters->u.direct.index_count)
49399987f029SAmine Khaldi return;
49409987f029SAmine Khaldi
49419987f029SAmine Khaldi if (!(rtv = fb->render_targets[0]))
49429987f029SAmine Khaldi rtv = fb->depth_stencil;
49439987f029SAmine Khaldi if (rtv)
49449987f029SAmine Khaldi context = context_acquire(device, wined3d_texture_from_resource(rtv->resource), rtv->sub_resource_idx);
49459987f029SAmine Khaldi else
49469987f029SAmine Khaldi context = context_acquire(device, NULL, 0);
49479987f029SAmine Khaldi if (!context->valid)
49489987f029SAmine Khaldi {
49499987f029SAmine Khaldi context_release(context);
49509987f029SAmine Khaldi WARN("Invalid context, skipping draw.\n");
49519987f029SAmine Khaldi return;
49529987f029SAmine Khaldi }
49539987f029SAmine Khaldi gl_info = context->gl_info;
49549987f029SAmine Khaldi
49559987f029SAmine Khaldi if (!use_transform_feedback(state))
49569987f029SAmine Khaldi context_pause_transform_feedback(context, TRUE);
49579987f029SAmine Khaldi
49589987f029SAmine Khaldi for (i = 0; i < gl_info->limits.buffers; ++i)
49599987f029SAmine Khaldi {
49609987f029SAmine Khaldi if (!(rtv = fb->render_targets[i]) || rtv->format->id == WINED3DFMT_NULL)
49619987f029SAmine Khaldi continue;
49629987f029SAmine Khaldi
49639987f029SAmine Khaldi if (state->render_states[WINED3D_RS_COLORWRITE(i)])
49649987f029SAmine Khaldi {
49659987f029SAmine Khaldi wined3d_rendertarget_view_load_location(rtv, context, rtv->resource->draw_binding);
49669987f029SAmine Khaldi wined3d_rendertarget_view_invalidate_location(rtv, ~rtv->resource->draw_binding);
49679987f029SAmine Khaldi }
49689987f029SAmine Khaldi else
49699987f029SAmine Khaldi {
49709987f029SAmine Khaldi wined3d_rendertarget_view_prepare_location(rtv, context, rtv->resource->draw_binding);
49719987f029SAmine Khaldi }
49729987f029SAmine Khaldi }
49739987f029SAmine Khaldi
49749987f029SAmine Khaldi if ((dsv = fb->depth_stencil))
49759987f029SAmine Khaldi {
49769987f029SAmine Khaldi /* Note that this depends on the context_acquire() call above to set
49779987f029SAmine Khaldi * context->render_offscreen properly. We don't currently take the
49789987f029SAmine Khaldi * Z-compare function into account, but we could skip loading the
49799987f029SAmine Khaldi * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note
49809987f029SAmine Khaldi * that we never copy the stencil data.*/
49819987f029SAmine Khaldi DWORD location = context->render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
49829987f029SAmine Khaldi
49839987f029SAmine Khaldi if (state->render_states[WINED3D_RS_ZWRITEENABLE] || state->render_states[WINED3D_RS_ZENABLE])
49849987f029SAmine Khaldi wined3d_rendertarget_view_load_location(dsv, context, location);
49859987f029SAmine Khaldi else
49869987f029SAmine Khaldi wined3d_rendertarget_view_prepare_location(dsv, context, location);
49879987f029SAmine Khaldi }
49889987f029SAmine Khaldi
49899987f029SAmine Khaldi if (parameters->indirect)
49909987f029SAmine Khaldi wined3d_buffer_load(parameters->u.indirect.buffer, context, state);
49919987f029SAmine Khaldi
49929987f029SAmine Khaldi if (!context_apply_draw_state(context, device, state))
49939987f029SAmine Khaldi {
49949987f029SAmine Khaldi context_release(context);
49959987f029SAmine Khaldi WARN("Unable to apply draw state, skipping draw.\n");
49969987f029SAmine Khaldi return;
49979987f029SAmine Khaldi }
49989987f029SAmine Khaldi
49999987f029SAmine Khaldi if (dsv && state->render_states[WINED3D_RS_ZWRITEENABLE])
50009987f029SAmine Khaldi {
50019987f029SAmine Khaldi DWORD location = context->render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
50029987f029SAmine Khaldi
50039987f029SAmine Khaldi wined3d_rendertarget_view_validate_location(dsv, location);
50049987f029SAmine Khaldi wined3d_rendertarget_view_invalidate_location(dsv, ~location);
50059987f029SAmine Khaldi }
50069987f029SAmine Khaldi
50079987f029SAmine Khaldi stream_info = &context->stream_info;
50089987f029SAmine Khaldi
50099987f029SAmine Khaldi if (parameters->indexed)
50109987f029SAmine Khaldi {
50119987f029SAmine Khaldi struct wined3d_buffer *index_buffer = state->index_buffer;
50129987f029SAmine Khaldi if (!index_buffer->buffer_object || !stream_info->all_vbo)
50139987f029SAmine Khaldi {
50149987f029SAmine Khaldi idx_data = index_buffer->resource.heap_memory;
50159987f029SAmine Khaldi }
50169987f029SAmine Khaldi else
50179987f029SAmine Khaldi {
50189987f029SAmine Khaldi ib_fence = index_buffer->fence;
50199987f029SAmine Khaldi idx_data = NULL;
50209987f029SAmine Khaldi }
50219987f029SAmine Khaldi idx_data = (const BYTE *)idx_data + state->index_offset;
50229987f029SAmine Khaldi
50239987f029SAmine Khaldi if (state->index_format == WINED3DFMT_R16_UINT)
50249987f029SAmine Khaldi idx_size = 2;
50259987f029SAmine Khaldi else
50269987f029SAmine Khaldi idx_size = 4;
50279987f029SAmine Khaldi }
50289987f029SAmine Khaldi
50299987f029SAmine Khaldi if (!use_vs(state))
50309987f029SAmine Khaldi {
50319987f029SAmine Khaldi if (!stream_info->position_transformed && context->num_untracked_materials
50329987f029SAmine Khaldi && state->render_states[WINED3D_RS_LIGHTING])
50339987f029SAmine Khaldi {
50349987f029SAmine Khaldi static BOOL warned;
50359987f029SAmine Khaldi
50369987f029SAmine Khaldi if (!warned++)
50379987f029SAmine Khaldi FIXME("Using software emulation because not all material properties could be tracked.\n");
50389987f029SAmine Khaldi else
50399987f029SAmine Khaldi WARN_(d3d_perf)("Using software emulation because not all material properties could be tracked.\n");
50409987f029SAmine Khaldi emulation = TRUE;
50419987f029SAmine Khaldi }
50429987f029SAmine Khaldi else if (context->fog_coord && state->render_states[WINED3D_RS_FOGENABLE])
50439987f029SAmine Khaldi {
50449987f029SAmine Khaldi static BOOL warned;
50459987f029SAmine Khaldi
50469987f029SAmine Khaldi /* Either write a pipeline replacement shader or convert the
50479987f029SAmine Khaldi * specular alpha from unsigned byte to a float in the vertex
50489987f029SAmine Khaldi * buffer. */
50499987f029SAmine Khaldi if (!warned++)
50509987f029SAmine Khaldi FIXME("Using software emulation because manual fog coordinates are provided.\n");
50519987f029SAmine Khaldi else
50529987f029SAmine Khaldi WARN_(d3d_perf)("Using software emulation because manual fog coordinates are provided.\n");
50539987f029SAmine Khaldi emulation = TRUE;
50549987f029SAmine Khaldi }
50559987f029SAmine Khaldi else if (use_indexed_vertex_blending(state, stream_info) && use_software_vertex_processing(context->device))
50569987f029SAmine Khaldi {
50579987f029SAmine Khaldi WARN_(d3d_perf)("Using software emulation because application requested SVP.\n");
50589987f029SAmine Khaldi emulation = TRUE;
50599987f029SAmine Khaldi }
50609987f029SAmine Khaldi
5061*81cffd76SJoachim Henze
50629987f029SAmine Khaldi if (emulation)
50639987f029SAmine Khaldi {
50649987f029SAmine Khaldi si_emulated = context->stream_info;
50659987f029SAmine Khaldi remove_vbos(context, state, &si_emulated);
50669987f029SAmine Khaldi stream_info = &si_emulated;
50679987f029SAmine Khaldi }
50689987f029SAmine Khaldi }
50699987f029SAmine Khaldi
50709987f029SAmine Khaldi if (use_transform_feedback(state))
50719987f029SAmine Khaldi {
50729987f029SAmine Khaldi const struct wined3d_shader *shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY];
50739987f029SAmine Khaldi
50749987f029SAmine Khaldi if (is_rasterization_disabled(shader))
50759987f029SAmine Khaldi {
50769987f029SAmine Khaldi glEnable(GL_RASTERIZER_DISCARD);
50779987f029SAmine Khaldi checkGLcall("enable rasterizer discard");
50789987f029SAmine Khaldi rasterizer_discard = TRUE;
50799987f029SAmine Khaldi }
50809987f029SAmine Khaldi
50819987f029SAmine Khaldi if (context->transform_feedback_paused)
50829987f029SAmine Khaldi {
50839987f029SAmine Khaldi GL_EXTCALL(glResumeTransformFeedback());
50849987f029SAmine Khaldi checkGLcall("glResumeTransformFeedback");
50859987f029SAmine Khaldi context->transform_feedback_paused = 0;
50869987f029SAmine Khaldi }
50879987f029SAmine Khaldi else if (!context->transform_feedback_active)
50889987f029SAmine Khaldi {
5089*81cffd76SJoachim Henze GLenum mode = gl_tfb_primitive_type_from_d3d(shader->u.gs.output_type);
50909987f029SAmine Khaldi GL_EXTCALL(glBeginTransformFeedback(mode));
50919987f029SAmine Khaldi checkGLcall("glBeginTransformFeedback");
50929987f029SAmine Khaldi context->transform_feedback_active = 1;
50939987f029SAmine Khaldi }
50949987f029SAmine Khaldi }
50959987f029SAmine Khaldi
50969987f029SAmine Khaldi if (state->gl_primitive_type == GL_PATCHES)
50979987f029SAmine Khaldi {
50989987f029SAmine Khaldi GL_EXTCALL(glPatchParameteri(GL_PATCH_VERTICES, state->gl_patch_vertices));
50999987f029SAmine Khaldi checkGLcall("glPatchParameteri");
51009987f029SAmine Khaldi }
51019987f029SAmine Khaldi
51029987f029SAmine Khaldi if (parameters->indirect)
51039987f029SAmine Khaldi {
51049987f029SAmine Khaldi if (!context->use_immediate_mode_draw && !emulation)
51059987f029SAmine Khaldi draw_indirect(context, state, ¶meters->u.indirect, idx_size);
51069987f029SAmine Khaldi else
51079987f029SAmine Khaldi FIXME("Indirect draws with immediate mode/emulation are not supported.\n");
51089987f029SAmine Khaldi }
51099987f029SAmine Khaldi else
51109987f029SAmine Khaldi {
51119987f029SAmine Khaldi unsigned int instance_count = parameters->u.direct.instance_count;
51129987f029SAmine Khaldi if (context->instance_count)
51139987f029SAmine Khaldi instance_count = context->instance_count;
51149987f029SAmine Khaldi
51159987f029SAmine Khaldi if (context->use_immediate_mode_draw || emulation)
51169987f029SAmine Khaldi draw_primitive_immediate_mode(context, state, stream_info, idx_data,
51179987f029SAmine Khaldi idx_size, parameters->u.direct.base_vertex_idx,
51189987f029SAmine Khaldi parameters->u.direct.start_idx, parameters->u.direct.index_count, instance_count);
51199987f029SAmine Khaldi else
51209987f029SAmine Khaldi draw_primitive_arrays(context, state, idx_data, idx_size, parameters->u.direct.base_vertex_idx,
51219987f029SAmine Khaldi parameters->u.direct.start_idx, parameters->u.direct.index_count,
51229987f029SAmine Khaldi parameters->u.direct.start_instance, instance_count);
51239987f029SAmine Khaldi }
51249987f029SAmine Khaldi
51259987f029SAmine Khaldi if (context->uses_uavs)
51269987f029SAmine Khaldi {
51279987f029SAmine Khaldi GL_EXTCALL(glMemoryBarrier(GL_ALL_BARRIER_BITS));
51289987f029SAmine Khaldi checkGLcall("glMemoryBarrier");
51299987f029SAmine Khaldi }
51309987f029SAmine Khaldi
51319987f029SAmine Khaldi context_pause_transform_feedback(context, FALSE);
51329987f029SAmine Khaldi
51339987f029SAmine Khaldi if (rasterizer_discard)
51349987f029SAmine Khaldi {
51359987f029SAmine Khaldi glDisable(GL_RASTERIZER_DISCARD);
51369987f029SAmine Khaldi checkGLcall("disable rasterizer discard");
51379987f029SAmine Khaldi }
51389987f029SAmine Khaldi
51399987f029SAmine Khaldi if (ib_fence)
51409987f029SAmine Khaldi wined3d_fence_issue(ib_fence, device);
51419987f029SAmine Khaldi for (i = 0; i < context->buffer_fence_count; ++i)
51429987f029SAmine Khaldi wined3d_fence_issue(context->buffer_fences[i], device);
51439987f029SAmine Khaldi
5144*81cffd76SJoachim Henze if (wined3d_settings.strict_draw_ordering)
5145*81cffd76SJoachim Henze gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5146*81cffd76SJoachim Henze
51479987f029SAmine Khaldi context_release(context);
5148c2c66affSColin Finck }
5149