[D3D8][D3D9][DDRAW][WINED3D] Sync with Wine Staging 1.9.4. CORE-10912
[reactos.git] / reactos / dll / directx / wine / wined3d / surface.c
1 /*
2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011, 2013-2014 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 */
28
29 #include "wined3d_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
32 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
33 WINE_DECLARE_DEBUG_CHANNEL(d3d);
34
35 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
36
37 #if defined(STAGING_CSMT)
38
39 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
40 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
41 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter);
42
43 void wined3d_surface_cleanup_cs(struct wined3d_surface *surface)
44 {
45 if (surface->rb_multisample || surface->rb_resolved || !list_empty(&surface->renderbuffers))
46 #else /* STAGING_CSMT */
47 static const DWORD surface_simple_locations =
48 WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_USER_MEMORY
49 | WINED3D_LOCATION_DIB | WINED3D_LOCATION_BUFFER;
50
51 static void surface_cleanup(struct wined3d_surface *surface)
52 {
53 struct wined3d_surface *overlay, *cur;
54
55 TRACE("surface %p.\n", surface);
56
57 if (surface->pbo || surface->rb_multisample
58 || surface->rb_resolved || !list_empty(&surface->renderbuffers))
59 #endif /* STAGING_CSMT */
60 {
61 struct wined3d_renderbuffer_entry *entry, *entry2;
62 const struct wined3d_gl_info *gl_info;
63 struct wined3d_context *context;
64
65 context = context_acquire(surface->resource.device, NULL);
66 gl_info = context->gl_info;
67
68 #if !defined(STAGING_CSMT)
69 if (surface->pbo)
70 {
71 TRACE("Deleting PBO %u.\n", surface->pbo);
72 GL_EXTCALL(glDeleteBuffers(1, &surface->pbo));
73 }
74
75 #endif /* STAGING_CSMT */
76 if (surface->rb_multisample)
77 {
78 TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
79 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
80 }
81
82 if (surface->rb_resolved)
83 {
84 TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved);
85 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
86 }
87
88 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
89 {
90 TRACE("Deleting renderbuffer %u.\n", entry->id);
91 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
92 HeapFree(GetProcessHeap(), 0, entry);
93 }
94
95 context_release(context);
96 }
97
98 if (surface->flags & SFLAG_DIBSECTION)
99 {
100 DeleteDC(surface->hDC);
101 DeleteObject(surface->dib.DIBsection);
102 #if defined(STAGING_CSMT)
103 surface->resource.bitmap_data = NULL;
104 }
105
106 TRACE("Destroyed surface %p.\n", surface);
107 HeapFree(GetProcessHeap(), 0, surface);
108 }
109
110 static void surface_cleanup(struct wined3d_surface *surface)
111 {
112 struct wined3d_surface *overlay, *cur;
113 struct wined3d_cs *cs = surface->resource.device->cs;
114 BOOL user_mem = surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY;
115
116 TRACE("surface %p.\n", surface);
117 #else /* STAGING_CSMT */
118 surface->dib.bitmap_data = NULL;
119 }
120 #endif /* STAGING_CSMT */
121
122 if (surface->overlay_dest)
123 list_remove(&surface->overlay_entry);
124
125 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry)
126 {
127 list_remove(&overlay->overlay_entry);
128 overlay->overlay_dest = NULL;
129 }
130
131 resource_cleanup(&surface->resource);
132 #if defined(STAGING_CSMT)
133 wined3d_cs_emit_surface_cleanup(cs, surface);
134
135 /* Wait for the CS to finish operations on this surface when user memory was in use.
136 * The application is allowed to free the memory after texture / surface destruction
137 * returns. */
138 if (user_mem)
139 wined3d_resource_wait_fence(&surface->container->resource);
140 }
141
142 void wined3d_surface_destroy(struct wined3d_surface *surface)
143 {
144 TRACE("surface %p.\n", surface);
145
146 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
147 surface_cleanup(surface);
148 #else /* STAGING_CSMT */
149 }
150
151 void wined3d_surface_destroy(struct wined3d_surface *surface)
152 {
153 TRACE("surface %p.\n", surface);
154
155 surface_cleanup(surface);
156 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
157 HeapFree(GetProcessHeap(), 0, surface);
158 #endif /* STAGING_CSMT */
159 }
160
161 void surface_get_drawable_size(const struct wined3d_surface *surface, const struct wined3d_context *context,
162 unsigned int *width, unsigned int *height)
163 {
164 if (surface->container->swapchain)
165 {
166 /* The drawable size of an onscreen drawable is the surface size.
167 * (Actually: The window size, but the surface is created in window
168 * size.) */
169 *width = context->current_rt->resource.width;
170 *height = context->current_rt->resource.height;
171 }
172 else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
173 {
174 const struct wined3d_swapchain *swapchain = context->swapchain;
175
176 /* The drawable size of a backbuffer / aux buffer offscreen target is
177 * the size of the current context's drawable, which is the size of
178 * the back buffer of the swapchain the active context belongs to. */
179 *width = swapchain->desc.backbuffer_width;
180 *height = swapchain->desc.backbuffer_height;
181 }
182 else
183 {
184 /* The drawable size of an FBO target is the OpenGL texture size,
185 * which is the power of two size. */
186 *width = context->current_rt->pow2Width;
187 *height = context->current_rt->pow2Height;
188 }
189 }
190
191 struct blt_info
192 {
193 GLenum binding;
194 GLenum bind_target;
195 enum wined3d_gl_resource_type tex_type;
196 GLfloat coords[4][3];
197 };
198
199 struct float_rect
200 {
201 float l;
202 float t;
203 float r;
204 float b;
205 };
206
207 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
208 {
209 f->l = ((r->left * 2.0f) / w) - 1.0f;
210 f->t = ((r->top * 2.0f) / h) - 1.0f;
211 f->r = ((r->right * 2.0f) / w) - 1.0f;
212 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
213 }
214
215 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
216 {
217 GLfloat (*coords)[3] = info->coords;
218 struct float_rect f;
219
220 switch (target)
221 {
222 default:
223 FIXME("Unsupported texture target %#x\n", target);
224 /* Fall back to GL_TEXTURE_2D */
225 case GL_TEXTURE_2D:
226 info->binding = GL_TEXTURE_BINDING_2D;
227 info->bind_target = GL_TEXTURE_2D;
228 info->tex_type = WINED3D_GL_RES_TYPE_TEX_2D;
229 coords[0][0] = (float)rect->left / w;
230 coords[0][1] = (float)rect->top / h;
231 coords[0][2] = 0.0f;
232
233 coords[1][0] = (float)rect->right / w;
234 coords[1][1] = (float)rect->top / h;
235 coords[1][2] = 0.0f;
236
237 coords[2][0] = (float)rect->left / w;
238 coords[2][1] = (float)rect->bottom / h;
239 coords[2][2] = 0.0f;
240
241 coords[3][0] = (float)rect->right / w;
242 coords[3][1] = (float)rect->bottom / h;
243 coords[3][2] = 0.0f;
244 break;
245
246 case GL_TEXTURE_RECTANGLE_ARB:
247 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
248 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
249 info->tex_type = WINED3D_GL_RES_TYPE_TEX_RECT;
250 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
251 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
252 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
253 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
254 break;
255
256 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
257 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
258 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
259 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
260 cube_coords_float(rect, w, h, &f);
261
262 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
263 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
264 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
265 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
266 break;
267
268 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
269 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
270 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
271 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
272 cube_coords_float(rect, w, h, &f);
273
274 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
275 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
276 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
277 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
278 break;
279
280 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
281 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
282 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
283 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
284 cube_coords_float(rect, w, h, &f);
285
286 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
287 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
288 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
289 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
290 break;
291
292 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
293 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
294 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
295 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
296 cube_coords_float(rect, w, h, &f);
297
298 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
299 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
300 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
301 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
302 break;
303
304 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
305 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
306 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
307 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
308 cube_coords_float(rect, w, h, &f);
309
310 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
311 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
312 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
313 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
314 break;
315
316 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
317 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
318 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
319 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
320 cube_coords_float(rect, w, h, &f);
321
322 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
323 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
324 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
325 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
326 break;
327 }
328 }
329
330 static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
331 {
332 if (rect_in)
333 *rect_out = *rect_in;
334 else
335 {
336 rect_out->left = 0;
337 rect_out->top = 0;
338 rect_out->right = surface->resource.width;
339 rect_out->bottom = surface->resource.height;
340 }
341 }
342
343 /* Context activation is done by the caller. */
344 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
345 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
346 {
347 const struct wined3d_gl_info *gl_info = context->gl_info;
348 struct wined3d_texture *texture = src_surface->container;
349 struct blt_info info;
350
351 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
352
353 gl_info->gl_ops.gl.p_glEnable(info.bind_target);
354 checkGLcall("glEnable(bind_target)");
355
356 context_bind_texture(context, info.bind_target, texture->texture_rgb.name);
357
358 /* Filtering for StretchRect */
359 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
360 checkGLcall("glTexParameteri");
361 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
362 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
363 checkGLcall("glTexParameteri");
364 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
365 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
366 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
367 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
368 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
369 checkGLcall("glTexEnvi");
370
371 /* Draw a quad */
372 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
373 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
374 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->top);
375
376 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
377 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->top);
378
379 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
380 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->bottom);
381
382 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
383 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->bottom);
384 gl_info->gl_ops.gl.p_glEnd();
385
386 /* Unbind the texture */
387 context_bind_texture(context, info.bind_target, 0);
388
389 /* We changed the filtering settings on the texture. Inform the
390 * container about this to get the filters reset properly next draw. */
391 texture->texture_rgb.sampler_desc.mag_filter = WINED3D_TEXF_POINT;
392 texture->texture_rgb.sampler_desc.min_filter = WINED3D_TEXF_POINT;
393 texture->texture_rgb.sampler_desc.mip_filter = WINED3D_TEXF_NONE;
394 texture->texture_rgb.sampler_desc.srgb_decode = FALSE;
395 }
396
397 /* Works correctly only for <= 4 bpp formats. */
398 static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
399 {
400 masks[0] = ((1u << format->red_size) - 1) << format->red_offset;
401 masks[1] = ((1u << format->green_size) - 1) << format->green_offset;
402 masks[2] = ((1u << format->blue_size) - 1) << format->blue_offset;
403 }
404
405 HRESULT surface_create_dib_section(struct wined3d_surface *surface)
406 {
407 const struct wined3d_format *format = surface->resource.format;
408 unsigned int format_flags = surface->container->resource.format_flags;
409 unsigned int row_pitch, slice_pitch;
410 BITMAPINFO *b_info;
411 DWORD *masks;
412
413 TRACE("surface %p.\n", surface);
414
415 if (!(format_flags & WINED3DFMT_FLAG_GETDC))
416 {
417 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
418 return WINED3DERR_INVALIDCALL;
419 }
420
421 switch (format->byte_count)
422 {
423 case 2:
424 case 4:
425 /* Allocate extra space to store the RGB bit masks. */
426 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO, bmiColors[3]));
427 break;
428
429 case 3:
430 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO, bmiColors[0]));
431 break;
432
433 default:
434 /* Allocate extra space for a palette. */
435 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
436 FIELD_OFFSET(BITMAPINFO, bmiColors[1u << (format->byte_count * 8)]));
437 break;
438 }
439
440 if (!b_info)
441 return E_OUTOFMEMORY;
442
443 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
444 #if defined(STAGING_CSMT)
445 wined3d_resource_get_pitch(&surface->resource, &row_pitch, &slice_pitch);
446 #else /* STAGING_CSMT */
447 wined3d_texture_get_pitch(surface->container, surface->texture_level, &row_pitch, &slice_pitch);
448 #endif /* STAGING_CSMT */
449 b_info->bmiHeader.biWidth = row_pitch / format->byte_count;
450 b_info->bmiHeader.biHeight = 0 - surface->resource.height;
451 b_info->bmiHeader.biSizeImage = slice_pitch;
452 b_info->bmiHeader.biPlanes = 1;
453 b_info->bmiHeader.biBitCount = format->byte_count * 8;
454
455 b_info->bmiHeader.biXPelsPerMeter = 0;
456 b_info->bmiHeader.biYPelsPerMeter = 0;
457 b_info->bmiHeader.biClrUsed = 0;
458 b_info->bmiHeader.biClrImportant = 0;
459
460 /* Get the bit masks */
461 masks = (DWORD *)b_info->bmiColors;
462 switch (surface->resource.format->id)
463 {
464 case WINED3DFMT_B8G8R8_UNORM:
465 b_info->bmiHeader.biCompression = BI_RGB;
466 break;
467
468 case WINED3DFMT_B5G5R5X1_UNORM:
469 case WINED3DFMT_B5G5R5A1_UNORM:
470 case WINED3DFMT_B4G4R4A4_UNORM:
471 case WINED3DFMT_B4G4R4X4_UNORM:
472 case WINED3DFMT_B2G3R3_UNORM:
473 case WINED3DFMT_B2G3R3A8_UNORM:
474 case WINED3DFMT_R10G10B10A2_UNORM:
475 case WINED3DFMT_R8G8B8A8_UNORM:
476 case WINED3DFMT_R8G8B8X8_UNORM:
477 case WINED3DFMT_B10G10R10A2_UNORM:
478 case WINED3DFMT_B5G6R5_UNORM:
479 case WINED3DFMT_R16G16B16A16_UNORM:
480 b_info->bmiHeader.biCompression = BI_BITFIELDS;
481 get_color_masks(format, masks);
482 break;
483
484 default:
485 /* Don't know palette */
486 b_info->bmiHeader.biCompression = BI_RGB;
487 break;
488 }
489
490 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
491 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
492 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
493 #if defined(STAGING_CSMT)
494 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->resource.bitmap_data, 0, 0);
495 #else /* STAGING_CSMT */
496 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
497 #endif /* STAGING_CSMT */
498
499 if (!surface->dib.DIBsection)
500 {
501 ERR("Failed to create DIB section.\n");
502 HeapFree(GetProcessHeap(), 0, b_info);
503 return HRESULT_FROM_WIN32(GetLastError());
504 }
505
506 #if defined(STAGING_CSMT)
507 TRACE("DIBSection at %p.\n", surface->resource.bitmap_data);
508 #else /* STAGING_CSMT */
509 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
510 #endif /* STAGING_CSMT */
511 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
512
513 HeapFree(GetProcessHeap(), 0, b_info);
514
515 /* Now allocate a DC. */
516 surface->hDC = CreateCompatibleDC(0);
517 SelectObject(surface->hDC, surface->dib.DIBsection);
518
519 surface->flags |= SFLAG_DIBSECTION;
520
521 return WINED3D_OK;
522 }
523
524 #if !defined(STAGING_CSMT)
525 static void surface_get_memory(const struct wined3d_surface *surface, struct wined3d_bo_address *data,
526 DWORD location)
527 {
528 if (location & WINED3D_LOCATION_BUFFER)
529 {
530 data->addr = NULL;
531 data->buffer_object = surface->pbo;
532 return;
533 }
534 if (location & WINED3D_LOCATION_USER_MEMORY)
535 {
536 data->addr = surface->container->user_memory;
537 data->buffer_object = 0;
538 return;
539 }
540 if (location & WINED3D_LOCATION_DIB)
541 {
542 data->addr = surface->dib.bitmap_data;
543 data->buffer_object = 0;
544 return;
545 }
546 if (location & WINED3D_LOCATION_SYSMEM)
547 {
548 data->addr = surface->resource.heap_memory;
549 data->buffer_object = 0;
550 return;
551 }
552
553 ERR("Unexpected locations %s.\n", wined3d_debug_location(location));
554 data->addr = NULL;
555 data->buffer_object = 0;
556 }
557
558 static void surface_prepare_buffer(struct wined3d_surface *surface)
559 {
560 struct wined3d_context *context;
561 GLenum error;
562 const struct wined3d_gl_info *gl_info;
563
564 if (surface->pbo)
565 return;
566
567 context = context_acquire(surface->resource.device, NULL);
568 gl_info = context->gl_info;
569
570 GL_EXTCALL(glGenBuffers(1, &surface->pbo));
571 error = gl_info->gl_ops.gl.p_glGetError();
572 if (!surface->pbo || error != GL_NO_ERROR)
573 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
574
575 TRACE("Binding PBO %u.\n", surface->pbo);
576
577 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, surface->pbo));
578 checkGLcall("glBindBuffer");
579
580 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER, surface->resource.size + 4,
581 NULL, GL_STREAM_DRAW));
582 checkGLcall("glBufferData");
583
584 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
585 checkGLcall("glBindBuffer");
586
587 context_release(context);
588 }
589
590 static void surface_prepare_system_memory(struct wined3d_surface *surface)
591 {
592 TRACE("surface %p.\n", surface);
593
594 if (surface->resource.heap_memory)
595 return;
596
597 /* Whatever surface we have, make sure that there is memory allocated
598 * for the downloaded copy, or a PBO to map. */
599 if (!wined3d_resource_allocate_sysmem(&surface->resource))
600 ERR("Failed to allocate system memory.\n");
601
602 if (surface->locations & WINED3D_LOCATION_SYSMEM)
603 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
604 }
605
606 void surface_prepare_map_memory(struct wined3d_surface *surface)
607 {
608 switch (surface->resource.map_binding)
609 {
610 case WINED3D_LOCATION_SYSMEM:
611 surface_prepare_system_memory(surface);
612 break;
613
614 case WINED3D_LOCATION_USER_MEMORY:
615 if (!surface->container->user_memory)
616 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
617 break;
618
619 case WINED3D_LOCATION_DIB:
620 if (!surface->dib.bitmap_data)
621 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
622 break;
623
624 case WINED3D_LOCATION_BUFFER:
625 surface_prepare_buffer(surface);
626 break;
627
628 default:
629 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->resource.map_binding));
630 }
631 }
632
633 #endif /* STAGING_CSMT */
634 static void surface_evict_sysmem(struct wined3d_surface *surface)
635 {
636 /* In some conditions the surface memory must not be freed:
637 * WINED3D_TEXTURE_CONVERTED: Converting the data back would take too long
638 * WINED3D_TEXTURE_DYNAMIC_MAP: Avoid freeing the data for performance */
639 if (surface->resource.map_count || surface->container->flags & (WINED3D_TEXTURE_CONVERTED
640 | WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_DYNAMIC_MAP))
641 return;
642
643 wined3d_resource_free_sysmem(&surface->resource);
644 #if defined(STAGING_CSMT)
645 surface->resource.map_heap_memory = NULL;
646 wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_SYSMEM);
647 #else /* STAGING_CSMT */
648 surface_invalidate_location(surface, WINED3D_LOCATION_SYSMEM);
649 #endif /* STAGING_CSMT */
650 }
651
652 static BOOL surface_use_pbo(const struct wined3d_surface *surface)
653 {
654 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
655 struct wined3d_texture *texture = surface->container;
656
657 return texture->resource.pool == WINED3D_POOL_DEFAULT
658 && surface->resource.access_flags & WINED3D_RESOURCE_ACCESS_CPU
659 && gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]
660 && !texture->resource.format->convert
661 && !(texture->flags & WINED3D_TEXTURE_PIN_SYSMEM)
662 && !(texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED);
663 }
664
665 static HRESULT surface_private_setup(struct wined3d_surface *surface)
666 {
667 /* TODO: Check against the maximum texture sizes supported by the video card. */
668 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
669 unsigned int pow2Width, pow2Height;
670
671 TRACE("surface %p.\n", surface);
672
673 /* Non-power2 support */
674 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT]
675 || gl_info->supported[ARB_TEXTURE_RECTANGLE])
676 {
677 pow2Width = surface->resource.width;
678 pow2Height = surface->resource.height;
679 }
680 else
681 {
682 /* Find the nearest pow2 match */
683 pow2Width = pow2Height = 1;
684 while (pow2Width < surface->resource.width)
685 pow2Width <<= 1;
686 while (pow2Height < surface->resource.height)
687 pow2Height <<= 1;
688 }
689 surface->pow2Width = pow2Width;
690 surface->pow2Height = pow2Height;
691
692 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
693 {
694 /* TODO: Add support for non power two compressed textures. */
695 if (surface->container->resource.format_flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_HEIGHT_SCALE))
696 {
697 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
698 surface, surface->resource.width, surface->resource.height);
699 return WINED3DERR_NOTAVAILABLE;
700 }
701 }
702
703 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
704 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
705 {
706 /* One of three options:
707 * 1: Do the same as we do with NPOT and scale the texture, (any
708 * texture ops would require the texture to be scaled which is
709 * potentially slow)
710 * 2: Set the texture to the maximum size (bad idea).
711 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
712 * 4: Create the surface, but allow it to be used only for DirectDraw
713 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
714 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
715 * the render target. */
716 if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED)
717 {
718 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
719 return WINED3DERR_NOTAVAILABLE;
720 }
721
722 /* We should never use this surface in combination with OpenGL! */
723 TRACE("Creating an oversized surface: %ux%u.\n",
724 surface->pow2Width, surface->pow2Height);
725 }
726
727 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
728 #if defined(STAGING_CSMT)
729 surface->resource.locations = WINED3D_LOCATION_DISCARDED;
730 #else /* STAGING_CSMT */
731 surface->locations = WINED3D_LOCATION_DISCARDED;
732 #endif /* STAGING_CSMT */
733
734 if (surface_use_pbo(surface))
735 surface->resource.map_binding = WINED3D_LOCATION_BUFFER;
736
737 return WINED3D_OK;
738 }
739
740 #if defined(STAGING_CSMT)
741 static void surface_frontbuffer_updated(struct wined3d_surface *surface)
742 {
743 struct wined3d_context *context = NULL;
744 struct wined3d_device *device = surface->resource.device;
745
746 if (surface->resource.locations & WINED3D_LOCATION_DRAWABLE)
747 {
748 TRACE("Not dirtified, nothing to do.\n");
749 return;
750 }
751
752 if (device->d3d_initialized)
753 context = context_acquire(surface->resource.device, NULL);
754 wined3d_resource_load_location(&surface->resource, context, surface->container->resource.draw_binding);
755 if (context)
756 context_release(context);
757 #else /* STAGING_CSMT */
758 static void surface_unmap(struct wined3d_surface *surface)
759 {
760 struct wined3d_device *device = surface->resource.device;
761 const struct wined3d_gl_info *gl_info;
762 struct wined3d_context *context;
763
764 TRACE("surface %p.\n", surface);
765
766 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
767
768 switch (surface->resource.map_binding)
769 {
770 case WINED3D_LOCATION_SYSMEM:
771 case WINED3D_LOCATION_USER_MEMORY:
772 case WINED3D_LOCATION_DIB:
773 break;
774
775 case WINED3D_LOCATION_BUFFER:
776 context = context_acquire(device, NULL);
777 gl_info = context->gl_info;
778
779 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, surface->pbo));
780 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));
781 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
782 checkGLcall("glUnmapBuffer");
783 context_release(context);
784 break;
785
786 default:
787 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->resource.map_binding));
788 }
789
790 if (surface->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB))
791 {
792 TRACE("Not dirtified, nothing to do.\n");
793 return;
794 }
795
796 if (surface->container->swapchain && surface->container->swapchain->front_buffer == surface->container)
797 {
798 context = context_acquire(device, surface);
799 surface_load_location(surface, context, surface->container->resource.draw_binding);
800 context_release(context);
801 }
802 else if (surface->container->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
803 FIXME("Depth / stencil buffer locking is not implemented.\n");
804 #endif /* STAGING_CSMT */
805 }
806
807 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
808 {
809 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
810 return FALSE;
811 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
812 return FALSE;
813 return TRUE;
814 }
815
816 static void surface_depth_blt_fbo(const struct wined3d_device *device,
817 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
818 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
819 {
820 const struct wined3d_gl_info *gl_info;
821 struct wined3d_context *context;
822 DWORD src_mask, dst_mask;
823 GLbitfield gl_mask;
824
825 TRACE("device %p\n", device);
826 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
827 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect));
828 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
829 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
830
831 src_mask = src_surface->container->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
832 dst_mask = dst_surface->container->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
833
834 if (src_mask != dst_mask)
835 {
836 ERR("Incompatible formats %s and %s.\n",
837 debug_d3dformat(src_surface->resource.format->id),
838 debug_d3dformat(dst_surface->resource.format->id));
839 return;
840 }
841
842 if (!src_mask)
843 {
844 ERR("Not a depth / stencil format: %s.\n",
845 debug_d3dformat(src_surface->resource.format->id));
846 return;
847 }
848
849 gl_mask = 0;
850 if (src_mask & WINED3DFMT_FLAG_DEPTH)
851 gl_mask |= GL_DEPTH_BUFFER_BIT;
852 if (src_mask & WINED3DFMT_FLAG_STENCIL)
853 gl_mask |= GL_STENCIL_BUFFER_BIT;
854
855 context = context_acquire(device, NULL);
856 if (!context->valid)
857 {
858 context_release(context);
859 WARN("Invalid context, skipping blit.\n");
860 return;
861 }
862
863 /* Make sure the locations are up-to-date. Loading the destination
864 * surface isn't required if the entire surface is overwritten. */
865 #if defined(STAGING_CSMT)
866 wined3d_resource_load_location(&src_surface->resource, context, src_location);
867 if (!surface_is_full_rect(dst_surface, dst_rect))
868 wined3d_resource_load_location(&dst_surface->resource, context, dst_location);
869 #else /* STAGING_CSMT */
870 surface_load_location(src_surface, context, src_location);
871 if (!surface_is_full_rect(dst_surface, dst_rect))
872 surface_load_location(dst_surface, context, dst_location);
873 #endif /* STAGING_CSMT */
874 else
875 wined3d_surface_prepare(dst_surface, context, dst_location);
876
877 gl_info = context->gl_info;
878
879 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, src_location);
880 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
881
882 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, dst_location);
883 context_set_draw_buffer(context, GL_NONE);
884 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
885 context_invalidate_state(context, STATE_FRAMEBUFFER);
886
887 if (gl_mask & GL_DEPTH_BUFFER_BIT)
888 {
889 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
890 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
891 }
892 if (gl_mask & GL_STENCIL_BUFFER_BIT)
893 {
894 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
895 {
896 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
897 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
898 }
899 gl_info->gl_ops.gl.p_glStencilMask(~0U);
900 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
901 }
902
903 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
904 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
905
906 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
907 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
908 checkGLcall("glBlitFramebuffer()");
909
910 if (wined3d_settings.strict_draw_ordering)
911 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
912
913 context_release(context);
914 }
915
916 /* Blit between surface locations. Onscreen on different swapchains is not supported.
917 * Depth / stencil is not supported. Context activation is done by the caller. */
918 static void surface_blt_fbo(const struct wined3d_device *device,
919 struct wined3d_context *old_ctx, enum wined3d_texture_filter_type filter,
920 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
921 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
922 {
923 const struct wined3d_gl_info *gl_info;
924 struct wined3d_context *context = old_ctx;
925 struct wined3d_surface *required_rt, *restore_rt = NULL;
926 RECT src_rect, dst_rect;
927 GLenum gl_filter;
928 GLenum buffer;
929
930 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
931 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
932 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect_in));
933 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
934 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect_in));
935
936 src_rect = *src_rect_in;
937 dst_rect = *dst_rect_in;
938
939 switch (filter)
940 {
941 case WINED3D_TEXF_LINEAR:
942 gl_filter = GL_LINEAR;
943 break;
944
945 default:
946 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
947 case WINED3D_TEXF_NONE:
948 case WINED3D_TEXF_POINT:
949 gl_filter = GL_NEAREST;
950 break;
951 }
952
953 /* Resolve the source surface first if needed. */
954 if (src_location == WINED3D_LOCATION_RB_MULTISAMPLE
955 && (src_surface->resource.format->id != dst_surface->resource.format->id
956 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
957 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
958 src_location = WINED3D_LOCATION_RB_RESOLVED;
959
960 /* Make sure the locations are up-to-date. Loading the destination
961 * surface isn't required if the entire surface is overwritten. (And is
962 * in fact harmful if we're being called by surface_load_location() with
963 * the purpose of loading the destination surface.) */
964 #if defined(STAGING_CSMT)
965 wined3d_resource_load_location(&src_surface->resource, old_ctx, src_location);
966 if (!surface_is_full_rect(dst_surface, &dst_rect))
967 wined3d_resource_load_location(&dst_surface->resource, old_ctx, dst_location);
968 #else /* STAGING_CSMT */
969 surface_load_location(src_surface, old_ctx, src_location);
970 if (!surface_is_full_rect(dst_surface, &dst_rect))
971 surface_load_location(dst_surface, old_ctx, dst_location);
972 #endif /* STAGING_CSMT */
973 else
974 wined3d_surface_prepare(dst_surface, old_ctx, dst_location);
975
976
977 if (src_location == WINED3D_LOCATION_DRAWABLE) required_rt = src_surface;
978 else if (dst_location == WINED3D_LOCATION_DRAWABLE) required_rt = dst_surface;
979 else required_rt = NULL;
980
981 if (required_rt && required_rt != old_ctx->current_rt)
982 {
983 restore_rt = old_ctx->current_rt;
984 context = context_acquire(device, required_rt);
985 }
986
987 if (!context->valid)
988 {
989 context_release(context);
990 WARN("Invalid context, skipping blit.\n");
991 return;
992 }
993
994 gl_info = context->gl_info;
995
996 if (src_location == WINED3D_LOCATION_DRAWABLE)
997 {
998 TRACE("Source surface %p is onscreen.\n", src_surface);
999 buffer = surface_get_gl_buffer(src_surface);
1000 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
1001 }
1002 else
1003 {
1004 TRACE("Source surface %p is offscreen.\n", src_surface);
1005 buffer = GL_COLOR_ATTACHMENT0;
1006 }
1007
1008 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
1009 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1010 checkGLcall("glReadBuffer()");
1011 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1012
1013 if (dst_location == WINED3D_LOCATION_DRAWABLE)
1014 {
1015 TRACE("Destination surface %p is onscreen.\n", dst_surface);
1016 buffer = surface_get_gl_buffer(dst_surface);
1017 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
1018 }
1019 else
1020 {
1021 TRACE("Destination surface %p is offscreen.\n", dst_surface);
1022 buffer = GL_COLOR_ATTACHMENT0;
1023 }
1024
1025 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
1026 context_set_draw_buffer(context, buffer);
1027 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1028 context_invalidate_state(context, STATE_FRAMEBUFFER);
1029
1030 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1031 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
1032 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
1033 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
1034 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
1035
1036 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1037 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1038
1039 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
1040 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
1041 checkGLcall("glBlitFramebuffer()");
1042
1043 if (wined3d_settings.strict_draw_ordering
1044 || (dst_location == WINED3D_LOCATION_DRAWABLE
1045 && dst_surface->container->swapchain->front_buffer == dst_surface->container))
1046 gl_info->gl_ops.gl.p_glFlush();
1047
1048 if (restore_rt)
1049 context_restore(context, restore_rt);
1050 }
1051
1052 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
1053 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
1054 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
1055 {
1056 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1057 return FALSE;
1058
1059 /* Source and/or destination need to be on the GL side */
1060 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
1061 return FALSE;
1062
1063 switch (blit_op)
1064 {
1065 case WINED3D_BLIT_OP_COLOR_BLIT:
1066 if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
1067 || (src_usage & WINED3DUSAGE_RENDERTARGET)))
1068 return FALSE;
1069 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
1070 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
1071 return FALSE;
1072 if (!(src_format->id == dst_format->id
1073 || (is_identity_fixup(src_format->color_fixup)
1074 && is_identity_fixup(dst_format->color_fixup))))
1075 return FALSE;
1076 break;
1077
1078 case WINED3D_BLIT_OP_DEPTH_BLIT:
1079 if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1080 return FALSE;
1081 if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1082 return FALSE;
1083 /* Accept pure swizzle fixups for depth formats. In general we
1084 * ignore the stencil component (if present) at the moment and the
1085 * swizzle is not relevant with just the depth component. */
1086 if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
1087 || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
1088 return FALSE;
1089 break;
1090
1091 default:
1092 return FALSE;
1093 }
1094
1095 return TRUE;
1096 }
1097
1098 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
1099 {
1100 const struct wined3d_format *format = surface->resource.format;
1101
1102 switch (format->id)
1103 {
1104 case WINED3DFMT_S1_UINT_D15_UNORM:
1105 *float_depth = depth / (float)0x00007fff;
1106 break;
1107
1108 case WINED3DFMT_D16_UNORM:
1109 *float_depth = depth / (float)0x0000ffff;
1110 break;
1111
1112 case WINED3DFMT_D24_UNORM_S8_UINT:
1113 case WINED3DFMT_X8D24_UNORM:
1114 *float_depth = depth / (float)0x00ffffff;
1115 break;
1116
1117 case WINED3DFMT_D32_UNORM:
1118 *float_depth = depth / (float)0xffffffff;
1119 break;
1120
1121 default:
1122 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1123 return FALSE;
1124 }
1125
1126 return TRUE;
1127 }
1128
1129 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
1130 {
1131 struct wined3d_resource *resource = &surface->container->resource;
1132 struct wined3d_device *device = resource->device;
1133 #if defined(STAGING_CSMT)
1134 struct wined3d_rendertarget_view view;
1135 struct wined3d_texture *texture = surface->container;
1136 #else /* STAGING_CSMT */
1137 struct wined3d_rendertarget_view_desc view_desc;
1138 struct wined3d_rendertarget_view *view;
1139 #endif /* STAGING_CSMT */
1140 const struct blit_shader *blitter;
1141 HRESULT hr;
1142
1143 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
1144 WINED3D_BLIT_OP_DEPTH_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
1145 {
1146 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1147 return WINED3DERR_INVALIDCALL;
1148 }
1149
1150 #if defined(STAGING_CSMT)
1151 view.resource = &surface->container->resource;
1152 view.parent = NULL;
1153 view.parent_ops = &wined3d_null_parent_ops;
1154 view.format = surface->resource.format;
1155 view.buffer_offset = 0;
1156 view.width = surface->resource.width;
1157 view.height = surface->resource.height;
1158 view.depth = 1;
1159 view.sub_resource_idx = surface->texture_layer * texture->level_count + surface->texture_level;
1160
1161 hr = blitter->depth_fill(device, &view, rect, depth);
1162 #else /* STAGING_CSMT */
1163 view_desc.format_id = resource->format->id;
1164 view_desc.u.texture.level_idx = surface->texture_level;
1165 view_desc.u.texture.layer_idx = surface->texture_layer;
1166 view_desc.u.texture.layer_count = 1;
1167 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
1168 resource, NULL, &wined3d_null_parent_ops, &view)))
1169 {
1170 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
1171 return hr;
1172 }
1173
1174 hr = blitter->depth_fill(device, view, rect, depth);
1175 wined3d_rendertarget_view_decref(view);
1176 #endif /* STAGING_CSMT */
1177
1178 return hr;
1179 }
1180
1181 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
1182 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
1183 {
1184 struct wined3d_device *device = src_surface->resource.device;
1185
1186 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
1187 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1188 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1189 return WINED3DERR_INVALIDCALL;
1190
1191 surface_depth_blt_fbo(device, src_surface, src_location, src_rect, dst_surface, dst_location, dst_rect);
1192
1193 surface_modify_ds_location(dst_surface, dst_location,
1194 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
1195
1196 return WINED3D_OK;
1197 }
1198
1199 #if !defined(STAGING_CSMT)
1200 /* Context activation is done by the caller. */
1201 static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
1202 {
1203 GL_EXTCALL(glDeleteBuffers(1, &surface->pbo));
1204 checkGLcall("glDeleteBuffers(1, &surface->pbo)");
1205
1206 surface->pbo = 0;
1207 surface_invalidate_location(surface, WINED3D_LOCATION_BUFFER);
1208 }
1209
1210 #endif /* STAGING_CSMT */
1211 static ULONG surface_resource_incref(struct wined3d_resource *resource)
1212 {
1213 struct wined3d_surface *surface = surface_from_resource(resource);
1214
1215 TRACE("surface %p, container %p.\n", surface, surface->container);
1216
1217 return wined3d_texture_incref(surface->container);
1218 }
1219
1220 static ULONG surface_resource_decref(struct wined3d_resource *resource)
1221 {
1222 struct wined3d_surface *surface = surface_from_resource(resource);
1223
1224 TRACE("surface %p, container %p.\n", surface, surface->container);
1225
1226 return wined3d_texture_decref(surface->container);
1227 }
1228
1229 static void surface_unload(struct wined3d_resource *resource)
1230 {
1231 struct wined3d_surface *surface = surface_from_resource(resource);
1232 struct wined3d_renderbuffer_entry *entry, *entry2;
1233 struct wined3d_device *device = resource->device;
1234 const struct wined3d_gl_info *gl_info;
1235 struct wined3d_context *context;
1236
1237 TRACE("surface %p.\n", surface);
1238
1239 context = context_acquire(device, NULL);
1240 gl_info = context->gl_info;
1241
1242 if (resource->pool == WINED3D_POOL_DEFAULT)
1243 {
1244 #if defined(STAGING_CSMT)
1245 /* Default pool resources are supposed to be destroyed before Reset is called.
1246 * Implicit resources stay however. So this means we have an implicit render target
1247 * or depth stencil. The content may be destroyed, but we still have to tear down
1248 * opengl resources, so we cannot leave early. */
1249 wined3d_resource_validate_location(&surface->resource, WINED3D_LOCATION_DISCARDED);
1250 wined3d_resource_invalidate_location(&surface->resource, ~WINED3D_LOCATION_DISCARDED);
1251 }
1252 else
1253 {
1254 wined3d_resource_prepare_map_memory(&surface->resource, context);
1255 wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
1256 wined3d_resource_invalidate_location(&surface->resource, ~surface->resource.map_binding);
1257 }
1258 #else /* STAGING_CSMT */
1259 /* Default pool resources are supposed to be destroyed before Reset is called.
1260 * Implicit resources stay however. So this means we have an implicit render target
1261 * or depth stencil. The content may be destroyed, but we still have to tear down
1262 * opengl resources, so we cannot leave early.
1263 *
1264 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1265 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1266 * or the depth stencil into an FBO the texture or render buffer will be removed
1267 * and all flags get lost */
1268 if (resource->usage & WINED3DUSAGE_DEPTHSTENCIL)
1269 {
1270 surface_validate_location(surface, WINED3D_LOCATION_DISCARDED);
1271 surface_invalidate_location(surface, ~WINED3D_LOCATION_DISCARDED);
1272 }
1273 else
1274 {
1275 surface_prepare_system_memory(surface);
1276 memset(surface->resource.heap_memory, 0, surface->resource.size);
1277 surface_validate_location(surface, WINED3D_LOCATION_SYSMEM);
1278 surface_invalidate_location(surface, ~WINED3D_LOCATION_SYSMEM);
1279 }
1280 }
1281 else
1282 {
1283 surface_prepare_map_memory(surface);
1284 surface_load_location(surface, context, surface->resource.map_binding);
1285 surface_invalidate_location(surface, ~surface->resource.map_binding);
1286 }
1287
1288 /* Destroy PBOs, but load them into real sysmem before */
1289 if (surface->pbo)
1290 surface_remove_pbo(surface, gl_info);
1291 #endif /* STAGING_CSMT */
1292
1293 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1294 * all application-created targets the application has to release the surface
1295 * before calling _Reset
1296 */
1297 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1298 {
1299 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1300 list_remove(&entry->entry);
1301 HeapFree(GetProcessHeap(), 0, entry);
1302 }
1303 list_init(&surface->renderbuffers);
1304 surface->current_renderbuffer = NULL;
1305
1306 if (surface->rb_multisample)
1307 {
1308 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
1309 surface->rb_multisample = 0;
1310 }
1311 if (surface->rb_resolved)
1312 {
1313 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
1314 surface->rb_resolved = 0;
1315 }
1316
1317 context_release(context);
1318
1319 resource_unload(resource);
1320 }
1321
1322 static HRESULT surface_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx,
1323 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
1324 {
1325 ERR("Not supported on sub-resources.\n");
1326 return WINED3DERR_INVALIDCALL;
1327 }
1328
1329 static HRESULT surface_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
1330 {
1331 ERR("Not supported on sub-resources.\n");
1332 return WINED3DERR_INVALIDCALL;
1333 }
1334
1335 #if defined(STAGING_CSMT)
1336 static void wined3d_surface_location_invalidated(struct wined3d_resource *resource, DWORD location)
1337 {
1338 struct wined3d_surface *surface = surface_from_resource(resource);
1339
1340 if (location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
1341 wined3d_texture_set_dirty(surface->container);
1342
1343 if (surface->container->swapchain && surface->container == surface->container->swapchain->front_buffer)
1344 surface->surface_ops->surface_frontbuffer_updated(surface);
1345 }
1346
1347 static const struct wined3d_surface_ops surface_ops =
1348 {
1349 surface_private_setup,
1350 surface_frontbuffer_updated,
1351 #else /* STAGING_CSMT */
1352 static const struct wined3d_resource_ops surface_resource_ops =
1353 {
1354 surface_resource_incref,
1355 surface_resource_decref,
1356 surface_unload,
1357 surface_resource_sub_resource_map,
1358 surface_resource_sub_resource_unmap,
1359 };
1360
1361 static const struct wined3d_surface_ops surface_ops =
1362 {
1363 surface_private_setup,
1364 surface_unmap,
1365 #endif /* STAGING_CSMT */
1366 };
1367
1368 /*****************************************************************************
1369 * Initializes the GDI surface, aka creates the DIB section we render to
1370 * The DIB section creation is done by calling GetDC, which will create the
1371 * section and releasing the dc to allow the app to use it. The dib section
1372 * will stay until the surface is released
1373 *
1374 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1375 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1376 * avoid confusion in the shared surface code.
1377 *
1378 * Returns:
1379 * WINED3D_OK on success
1380 * The return values of called methods on failure
1381 *
1382 *****************************************************************************/
1383 static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface)
1384 {
1385 HRESULT hr;
1386
1387 TRACE("surface %p.\n", surface);
1388
1389 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
1390 {
1391 ERR("Overlays not yet supported by GDI surfaces.\n");
1392 return WINED3DERR_INVALIDCALL;
1393 }
1394
1395 /* Sysmem textures have memory already allocated - release it,
1396 * this avoids an unnecessary memcpy. */
1397 hr = surface_create_dib_section(surface);
1398 if (FAILED(hr))
1399 return hr;
1400 surface->resource.map_binding = WINED3D_LOCATION_DIB;
1401
1402 /* We don't mind the nonpow2 stuff in GDI. */
1403 surface->pow2Width = surface->resource.width;
1404 surface->pow2Height = surface->resource.height;
1405
1406 return WINED3D_OK;
1407 }
1408
1409 #if defined(STAGING_CSMT)
1410 static void gdi_surface_frontbuffer_updated(struct wined3d_surface *surface)
1411 {
1412 x11_copy_to_screen(surface->container->swapchain, &surface->lockedRect);
1413 }
1414
1415 static const struct wined3d_surface_ops gdi_surface_ops =
1416 {
1417 gdi_surface_private_setup,
1418 gdi_surface_frontbuffer_updated,
1419 #else /* STAGING_CSMT */
1420 static void gdi_surface_unmap(struct wined3d_surface *surface)
1421 {
1422 TRACE("surface %p.\n", surface);
1423
1424 /* Tell the swapchain to update the screen. */
1425 if (surface->container->swapchain && surface->container == surface->container->swapchain->front_buffer)
1426 x11_copy_to_screen(surface->container->swapchain, &surface->lockedRect);
1427
1428 memset(&surface->lockedRect, 0, sizeof(RECT));
1429 }
1430
1431 static const struct wined3d_surface_ops gdi_surface_ops =
1432 {
1433 gdi_surface_private_setup,
1434 gdi_surface_unmap,
1435 #endif /* STAGING_CSMT */
1436 };
1437
1438 /* This call just downloads data, the caller is responsible for binding the
1439 * correct texture. */
1440 /* Context activation is done by the caller. */
1441 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1442 DWORD dst_location)
1443 {
1444 const struct wined3d_format *format = surface->resource.format;
1445 struct wined3d_bo_address data;
1446
1447 /* Only support read back of converted P8 surfaces. */
1448 if (surface->container->flags & WINED3D_TEXTURE_CONVERTED && format->id != WINED3DFMT_P8_UINT)
1449 {
1450 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
1451 return;
1452 }
1453
1454 #if defined(STAGING_CSMT)
1455 wined3d_resource_get_memory(&surface->resource, dst_location, &data);
1456 #else /* STAGING_CSMT */
1457 surface_get_memory(surface, &data, dst_location);
1458 #endif /* STAGING_CSMT */
1459
1460 if (surface->container->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
1461 {
1462 TRACE("(%p) : Calling glGetCompressedTexImage level %d, format %#x, type %#x, data %p.\n",
1463 surface, surface->texture_level, format->glFormat, format->glType, data.addr);
1464
1465 if (data.buffer_object)
1466 {
1467 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1468 checkGLcall("glBindBuffer");
1469 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target, surface->texture_level, NULL));
1470 checkGLcall("glGetCompressedTexImage");
1471 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1472 checkGLcall("glBindBuffer");
1473 }
1474 else
1475 {
1476 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target,
1477 surface->texture_level, data.addr));
1478 checkGLcall("glGetCompressedTexImage");
1479 }
1480 }
1481 else
1482 {
1483 unsigned int dst_row_pitch, dst_slice_pitch;
1484 #if defined(STAGING_CSMT)
1485 unsigned int src_pitch;
1486 GLenum gl_format = format->glFormat;
1487 GLenum gl_type = format->glType;
1488 void *mem;
1489
1490 if (surface->container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1491 {
1492 unsigned char alignment = surface->resource.device->surface_alignment;
1493 src_pitch = format->byte_count * surface->pow2Width;
1494 wined3d_resource_get_pitch(&surface->resource, &dst_row_pitch, &dst_slice_pitch);
1495 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
1496 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
1497 #else /* STAGING_CSMT */
1498 unsigned int src_row_pitch, src_slice_pitch;
1499 GLenum gl_format = format->glFormat;
1500 GLenum gl_type = format->glType;
1501 void *mem;
1502
1503 if (surface->container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1504 {
1505 wined3d_texture_get_pitch(surface->container, surface->texture_level, &dst_row_pitch, &dst_slice_pitch);
1506 wined3d_format_calculate_pitch(format, surface->resource.device->surface_alignment,
1507 surface->pow2Width, surface->pow2Height, &src_row_pitch, &src_slice_pitch);
1508 mem = HeapAlloc(GetProcessHeap(), 0, src_slice_pitch);
1509 #endif /* STAGING_CSMT */
1510 }
1511 else
1512 {
1513 mem = data.addr;
1514 }
1515
1516 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1517 surface, surface->texture_level, gl_format, gl_type, mem);
1518
1519 if (data.buffer_object)
1520 {
1521 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1522 checkGLcall("glBindBuffer");
1523
1524 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1525 gl_format, gl_type, NULL);
1526 checkGLcall("glGetTexImage");
1527
1528 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1529 checkGLcall("glBindBuffer");
1530 }
1531 else
1532 {
1533 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1534 gl_format, gl_type, mem);
1535 checkGLcall("glGetTexImage");
1536 }
1537
1538 if (surface->container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1539 {
1540 const BYTE *src_data;
1541 BYTE *dst_data;
1542 UINT y;
1543 /*
1544 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1545 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1546 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1547 *
1548 * We're doing this...
1549 *
1550 * instead of boxing the texture :
1551 * |<-texture width ->| -->pow2width| /\
1552 * |111111111111111111| | |
1553 * |222 Texture 222222| boxed empty | texture height
1554 * |3333 Data 33333333| | |
1555 * |444444444444444444| | \/
1556 * ----------------------------------- |
1557 * | boxed empty | boxed empty | pow2height
1558 * | | | \/
1559 * -----------------------------------
1560 *
1561 *
1562 * we're repacking the data to the expected texture width
1563 *
1564 * |<-texture width ->| -->pow2width| /\
1565 * |111111111111111111222222222222222| |
1566 * |222333333333333333333444444444444| texture height
1567 * |444444 | |
1568 * | | \/
1569 * | | |
1570 * | empty | pow2height
1571 * | | \/
1572 * -----------------------------------
1573 *
1574 * == is the same as
1575 *
1576 * |<-texture width ->| /\
1577 * |111111111111111111|
1578 * |222222222222222222|texture height
1579 * |333333333333333333|
1580 * |444444444444444444| \/
1581 * --------------------
1582 *
1583 * This also means that any references to surface memory should work with the data as if it were a
1584 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1585 *
1586 * internally the texture is still stored in a boxed format so any references to textureName will
1587 * get a boxed texture with width pow2width and not a texture of width resource.width.
1588 *
1589 * Performance should not be an issue, because applications normally do not lock the surfaces when
1590 * rendering. If an app does, the WINED3D_TEXTURE_DYNAMIC_MAP flag will kick in and the memory copy
1591 * won't be released, and doesn't have to be re-read. */
1592 src_data = mem;
1593 dst_data = data.addr;
1594 #if defined(STAGING_CSMT)
1595 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_row_pitch);
1596 for (y = 0; y < surface->resource.height; ++y)
1597 {
1598 memcpy(dst_data, src_data, dst_row_pitch);
1599 src_data += src_pitch;
1600 #else /* STAGING_CSMT */
1601 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch);
1602 for (y = 0; y < surface->resource.height; ++y)
1603 {
1604 memcpy(dst_data, src_data, dst_row_pitch);
1605 src_data += src_row_pitch;
1606 #endif /* STAGING_CSMT */
1607 dst_data += dst_row_pitch;
1608 }
1609
1610 HeapFree(GetProcessHeap(), 0, mem);
1611 }
1612 }
1613 }
1614
1615 /* This call just uploads data, the caller is responsible for binding the
1616 * correct texture. */
1617 /* Context activation is done by the caller. */
1618 void wined3d_surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1619 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
1620 BOOL srgb, const struct wined3d_const_bo_address *data)
1621 {
1622 UINT update_w = src_rect->right - src_rect->left;
1623 UINT update_h = src_rect->bottom - src_rect->top;
1624
1625 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1626 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
1627 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
1628
1629 if (surface->resource.map_count)
1630 {
1631 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1632 surface->container->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
1633 }
1634
1635 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
1636 {
1637 update_h *= format->height_scale.numerator;
1638 update_h /= format->height_scale.denominator;
1639 }
1640
1641 if (data->buffer_object)
1642 {
1643 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, data->buffer_object));
1644 checkGLcall("glBindBuffer");
1645 }
1646
1647 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1648 {
1649 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1, 1);
1650 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
1651 const BYTE *addr = data->addr;
1652 GLenum internal;
1653
1654 addr += (src_rect->top / format->block_height) * src_pitch;
1655 addr += (src_rect->left / format->block_width) * format->block_byte_count;
1656
1657 if (srgb)
1658 internal = format->glGammaInternal;
1659 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET
1660 && wined3d_resource_is_offscreen(&surface->container->resource))
1661 internal = format->rtInternal;
1662 else
1663 internal = format->glInternal;
1664
1665 TRACE("glCompressedTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, "
1666 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
1667 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
1668
1669 if (row_length == src_pitch)
1670 {
1671 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1672 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
1673 }
1674 else
1675 {
1676 UINT row, y;
1677
1678 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1679 * can't use the unpack row length like for glTexSubImage2D. */
1680 for (row = 0, y = dst_point->y; row < row_count; ++row)
1681 {
1682 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1683 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
1684 y += format->block_height;
1685 addr += src_pitch;
1686 }
1687 }
1688 checkGLcall("glCompressedTexSubImage2D");
1689 }
1690 else
1691 {
1692 const BYTE *addr = data->addr;
1693
1694 addr += src_rect->top * src_pitch;
1695 addr += src_rect->left * format->byte_count;
1696
1697 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1698 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
1699 update_w, update_h, format->glFormat, format->glType, addr);
1700
1701 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
1702 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
1703 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
1704 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1705 checkGLcall("glTexSubImage2D");
1706 }
1707
1708 if (data->buffer_object)
1709 {
1710 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1711 checkGLcall("glBindBuffer");
1712 }
1713
1714 if (wined3d_settings.strict_draw_ordering)
1715 gl_info->gl_ops.gl.p_glFlush();
1716
1717 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1718 {
1719 struct wined3d_device *device = surface->resource.device;
1720 unsigned int i;
1721
1722 for (i = 0; i < device->context_count; ++i)
1723 {
1724 context_surface_update(device->contexts[i], surface);
1725 }
1726 }
1727 }
1728
1729 #if defined(STAGING_CSMT)
1730 static BOOL surface_check_block_align(struct wined3d_surface *surface, const struct wined3d_box *box)
1731 {
1732 if ((box->left >= box->right)
1733 || (box->top >= box->bottom)
1734 || (box->right > surface->resource.width)
1735 || (box->bottom > surface->resource.height))
1736 return FALSE;
1737
1738 return wined3d_resource_check_block_align(&surface->resource, box);
1739 }
1740
1741 static BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
1742 {
1743 struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
1744
1745 return surface_check_block_align(surface, &box);
1746 #else /* STAGING_CSMT */
1747 static BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
1748 {
1749 struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
1750
1751 return wined3d_texture_check_block_align(surface->container, surface->texture_level, &box);
1752 #endif /* STAGING_CSMT */
1753 }
1754
1755 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
1756 struct wined3d_surface *src_surface, const RECT *src_rect)
1757 {
1758 unsigned int src_row_pitch, src_slice_pitch;
1759 const struct wined3d_format *src_format;
1760 const struct wined3d_format *dst_format;
1761 unsigned int src_fmt_flags, dst_fmt_flags;
1762 const struct wined3d_gl_info *gl_info;
1763 struct wined3d_context *context;
1764 struct wined3d_bo_address data;
1765 UINT update_w, update_h;
1766 UINT dst_w, dst_h;
1767 RECT r, dst_rect;
1768 POINT p;
1769
1770 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1771 dst_surface, wine_dbgstr_point(dst_point),
1772 src_surface, wine_dbgstr_rect(src_rect));
1773
1774 src_format = src_surface->resource.format;
1775 dst_format = dst_surface->resource.format;
1776 src_fmt_flags = src_surface->container->resource.format_flags;
1777 dst_fmt_flags = dst_surface->container->resource.format_flags;
1778
1779 if (src_format->id != dst_format->id)
1780 {
1781 WARN("Source and destination surfaces should have the same format.\n");
1782 return WINED3DERR_INVALIDCALL;
1783 }
1784
1785 if (!dst_point)
1786 {
1787 p.x = 0;
1788 p.y = 0;
1789 dst_point = &p;
1790 }
1791 else if (dst_point->x < 0 || dst_point->y < 0)
1792 {
1793 WARN("Invalid destination point.\n");
1794 return WINED3DERR_INVALIDCALL;
1795 }
1796
1797 if (!src_rect)
1798 {
1799 r.left = 0;
1800 r.top = 0;
1801 r.right = src_surface->resource.width;
1802 r.bottom = src_surface->resource.height;
1803 src_rect = &r;
1804 }
1805 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
1806 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
1807 {
1808 WARN("Invalid source rectangle.\n");
1809 return WINED3DERR_INVALIDCALL;
1810 }
1811
1812 dst_w = dst_surface->resource.width;
1813 dst_h = dst_surface->resource.height;
1814
1815 update_w = src_rect->right - src_rect->left;
1816 update_h = src_rect->bottom - src_rect->top;
1817
1818 if (update_w > dst_w || dst_point->x > dst_w - update_w
1819 || update_h > dst_h || dst_point->y > dst_h - update_h)
1820 {
1821 WARN("Destination out of bounds.\n");
1822 return WINED3DERR_INVALIDCALL;
1823 }
1824
1825 if ((src_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(src_surface, src_rect))
1826 {
1827 WARN("Source rectangle not block-aligned.\n");
1828 return WINED3DERR_INVALIDCALL;
1829 }
1830
1831 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
1832 if ((dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(dst_surface, &dst_rect))
1833 {
1834 WARN("Destination rectangle not block-aligned.\n");
1835 return WINED3DERR_INVALIDCALL;
1836 }
1837
1838 #if defined(STAGING_CSMT)
1839 /* Use surface_cpu_blt() instead of uploading directly if we need
1840 * conversion. Avoid calling wined3d_surface_blt() since that goes
1841 * through the CS. */
1842 if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_surface->container, FALSE))
1843 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
1844 #else /* STAGING_CSMT */
1845 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1846 if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_surface->container, FALSE))
1847 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
1848 #endif /* STAGING_CSMT */
1849
1850 context = context_acquire(dst_surface->resource.device, NULL);
1851 gl_info = context->gl_info;
1852
1853 /* Only load the surface for partial updates. For newly allocated texture
1854 * the texture wouldn't be the current location, and we'd upload zeroes
1855 * just to overwrite them again. */
1856 if (update_w == dst_w && update_h == dst_h)
1857 wined3d_texture_prepare_texture(dst_surface->container, context, FALSE);
1858 else
1859 #if defined(STAGING_CSMT)
1860 wined3d_resource_load_location(&dst_surface->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
1861 wined3d_texture_bind_and_dirtify(dst_surface->container, context, FALSE);
1862
1863 wined3d_resource_get_memory(&src_surface->resource, src_surface->resource.locations, &data);
1864 wined3d_resource_get_pitch(&src_surface->resource, &src_row_pitch, &src_slice_pitch);
1865
1866 wined3d_surface_upload_data(dst_surface, gl_info, src_format, src_rect,
1867 src_row_pitch, dst_point, FALSE, wined3d_const_bo_address(&data));
1868
1869 context_release(context);
1870
1871 wined3d_resource_validate_location(&dst_surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
1872 wined3d_resource_invalidate_location(&dst_surface->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
1873 #else /* STAGING_CSMT */
1874 surface_load_location(dst_surface, context, WINED3D_LOCATION_TEXTURE_RGB);
1875 wined3d_texture_bind_and_dirtify(dst_surface->container, context, FALSE);
1876
1877 surface_get_memory(src_surface, &data, src_surface->locations);
1878 wined3d_texture_get_pitch(src_surface->container, src_surface->texture_level, &src_row_pitch, &src_slice_pitch);
1879
1880 wined3d_surface_upload_data(dst_surface, gl_info, src_format, src_rect,
1881 src_row_pitch, dst_point, FALSE, wined3d_const_bo_address(&data));
1882
1883 context_release(context);
1884
1885 surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
1886 surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
1887 #endif /* STAGING_CSMT */
1888
1889 return WINED3D_OK;
1890 }
1891
1892 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1893 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1894 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1895 /* Context activation is done by the caller. */
1896 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
1897 {
1898 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
1899 struct wined3d_renderbuffer_entry *entry;
1900 GLuint renderbuffer = 0;
1901 unsigned int src_width, src_height;
1902 unsigned int width, height;
1903
1904 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
1905 {
1906 width = rt->pow2Width;
1907 height = rt->pow2Height;
1908 }
1909 else
1910 {
1911 width = surface->pow2Width;
1912 height = surface->pow2Height;
1913 }
1914
1915 src_width = surface->pow2Width;
1916 src_height = surface->pow2Height;
1917
1918 /* A depth stencil smaller than the render target is not valid */
1919 if (width > src_width || height > src_height) return;
1920
1921 /* Remove any renderbuffer set if the sizes match */
1922 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1923 || (width == src_width && height == src_height))
1924 {
1925 surface->current_renderbuffer = NULL;
1926 return;
1927 }
1928
1929 /* Look if we've already got a renderbuffer of the correct dimensions */
1930 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1931 {
1932 if (entry->width == width && entry->height == height)
1933 {
1934 renderbuffer = entry->id;
1935 surface->current_renderbuffer = entry;
1936 break;
1937 }
1938 }
1939
1940 if (!renderbuffer)
1941 {
1942 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1943 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1944 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1945 surface->resource.format->glInternal, width, height);
1946
1947 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
1948 entry->width = width;
1949 entry->height = height;
1950 entry->id = renderbuffer;
1951 list_add_head(&surface->renderbuffers, &entry->entry);
1952
1953 surface->current_renderbuffer = entry;
1954 }
1955
1956 checkGLcall("set_compatible_renderbuffer");
1957 }
1958
1959 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
1960 {
1961 const struct wined3d_swapchain *swapchain = surface->container->swapchain;
1962
1963 TRACE("surface %p.\n", surface);
1964
1965 if (!swapchain)
1966 {
1967 ERR("Surface %p is not on a swapchain.\n", surface);
1968 return GL_NONE;
1969 }
1970
1971 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface->container)
1972 {
1973 if (swapchain->render_to_fbo)
1974 {
1975 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1976 return GL_COLOR_ATTACHMENT0;
1977 }
1978 TRACE("Returning GL_BACK\n");
1979 return GL_BACK;
1980 }
1981 else if (surface->container == swapchain->front_buffer)
1982 {
1983 TRACE("Returning GL_FRONT\n");
1984 return GL_FRONT;
1985 }
1986
1987 FIXME("Higher back buffer, returning GL_BACK\n");
1988 return GL_BACK;
1989 }
1990
1991 /* Context activation is done by the caller. */
1992 void surface_load(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
1993 {
1994 DWORD location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1995
1996 TRACE("surface %p, srgb %#x.\n", surface, srgb);
1997
1998 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
1999 ERR("Not supported on scratch surfaces.\n");
2000
2001 #if defined(STAGING_CSMT)
2002 if (surface->resource.locations & location)
2003 {
2004 TRACE("surface is already in texture\n");
2005 return;
2006 }
2007 TRACE("Reloading because surface is dirty.\n");
2008
2009 wined3d_resource_load_location(&surface->resource, context, location);
2010 #else /* STAGING_CSMT */
2011 if (surface->locations & location)
2012 {
2013 TRACE("surface is already in texture\n");
2014 return;
2015 }
2016 TRACE("Reloading because surface is dirty.\n");
2017
2018 surface_load_location(surface, context, location);
2019 #endif /* STAGING_CSMT */
2020 surface_evict_sysmem(surface);
2021 }
2022
2023 /* See also float_16_to_32() in wined3d_private.h */
2024 static inline unsigned short float_32_to_16(const float *in)
2025 {
2026 int exp = 0;
2027 float tmp = fabsf(*in);
2028 unsigned int mantissa;
2029 unsigned short ret;
2030
2031 /* Deal with special numbers */
2032 if (*in == 0.0f)
2033 return 0x0000;
2034 if (isnan(*in))
2035 return 0x7c01;
2036 if (isinf(*in))
2037 return (*in < 0.0f ? 0xfc00 : 0x7c00);
2038
2039 if (tmp < (float)(1u << 10))
2040 {
2041 do
2042 {
2043 tmp = tmp * 2.0f;
2044 exp--;
2045 } while (tmp < (float)(1u << 10));
2046 }
2047 else if (tmp >= (float)(1u << 11))
2048 {
2049 do
2050 {
2051 tmp /= 2.0f;
2052 exp++;
2053 } while (tmp >= (float)(1u << 11));
2054 }
2055
2056 mantissa = (unsigned int)tmp;
2057 if (tmp - mantissa >= 0.5f)
2058 ++mantissa; /* Round to nearest, away from zero. */
2059
2060 exp += 10; /* Normalize the mantissa. */
2061 exp += 15; /* Exponent is encoded with excess 15. */
2062
2063 if (exp > 30) /* too big */
2064 {
2065 ret = 0x7c00; /* INF */
2066 }
2067 else if (exp <= 0)
2068 {
2069 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2070 while (exp <= 0)
2071 {
2072 mantissa = mantissa >> 1;
2073 ++exp;
2074 }
2075 ret = mantissa & 0x3ff;
2076 }
2077 else
2078 {
2079 ret = (exp << 10) | (mantissa & 0x3ff);
2080 }
2081
2082 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
2083 return ret;
2084 }
2085
2086 #if defined(STAGING_CSMT)
2087 HRESULT wined3d_surface_update_desc(struct wined3d_surface *surface,
2088 const struct wined3d_gl_info *gl_info, void *mem, unsigned int pitch)
2089 #else /* STAGING_CSMT */
2090 HRESULT wined3d_surface_update_desc(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2091 #endif /* STAGING_CSMT */
2092 {
2093 struct wined3d_resource *texture_resource = &surface->container->resource;
2094 unsigned int width, height;
2095 BOOL create_dib = FALSE;
2096 DWORD valid_location = 0;
2097 HRESULT hr;
2098
2099 if (surface->flags & SFLAG_DIBSECTION)
2100 {
2101 DeleteDC(surface->hDC);
2102 DeleteObject(surface->dib.DIBsection);
2103 #if defined(STAGING_CSMT)
2104 surface->resource.bitmap_data = NULL;
2105 surface->flags &= ~SFLAG_DIBSECTION;
2106 create_dib = TRUE;
2107 }
2108
2109 surface->resource.locations = 0;
2110 wined3d_resource_free_sysmem(&surface->resource);
2111 surface->resource.map_heap_memory = NULL;
2112 #else /* STAGING_CSMT */
2113 surface->dib.bitmap_data = NULL;
2114 surface->flags &= ~SFLAG_DIBSECTION;
2115 create_dib = TRUE;
2116 }
2117
2118 surface->locations = 0;
2119 wined3d_resource_free_sysmem(&surface->resource);
2120 #endif /* STAGING_CSMT */
2121
2122 width = texture_resource->width;
2123 height = texture_resource->height;
2124 surface->resource.width = width;
2125 surface->resource.height = height;
2126 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
2127 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
2128 {
2129 surface->pow2Width = width;
2130 surface->pow2Height = height;
2131 }
2132 else
2133 {
2134 surface->pow2Width = surface->pow2Height = 1;
2135 while (surface->pow2Width < width)
2136 surface->pow2Width <<= 1;
2137 while (surface->pow2Height < height)
2138 surface->pow2Height <<= 1;
2139 }
2140
2141 #if defined(STAGING_CSMT)
2142 if ((surface->resource.user_memory = mem))
2143 {
2144 surface->resource.map_binding = WINED3D_LOCATION_USER_MEMORY;
2145 valid_location = WINED3D_LOCATION_USER_MEMORY;
2146 }
2147 surface->resource.custom_row_pitch = pitch;
2148 surface->resource.custom_slice_pitch = pitch * surface->resource.height;
2149 surface->resource.format = texture_resource->format;
2150 surface->resource.multisample_type = texture_resource->multisample_type;
2151 surface->resource.multisample_quality = texture_resource->multisample_quality;
2152 if (surface->resource.custom_row_pitch)
2153 {
2154 surface->resource.size = height * surface->resource.custom_row_pitch;
2155 }
2156 else
2157 {
2158 /* User memory surfaces don't have the regular surface alignment. */
2159 surface->resource.size = wined3d_format_calculate_size(texture_resource->format,
2160 1, width, height, 1);
2161 surface->resource.custom_row_pitch = wined3d_format_calculate_pitch(texture_resource->format, width);
2162 }
2163 #else /* STAGING_CSMT */
2164 if (surface->container->user_memory)
2165 {
2166 surface->resource.map_binding = WINED3D_LOCATION_USER_MEMORY;
2167 valid_location = WINED3D_LOCATION_USER_MEMORY;
2168 }
2169 surface->resource.format = texture_resource->format;
2170 surface->resource.multisample_type = texture_resource->multisample_type;
2171 surface->resource.multisample_quality = texture_resource->multisample_quality;
2172 surface->resource.size = surface->container->slice_pitch;
2173 #endif /* STAGING_CSMT */
2174
2175 /* The format might be changed to a format that needs conversion.
2176 * If the surface didn't use PBOs previously but could now, don't
2177 * change it - whatever made us not use PBOs might come back, e.g.
2178 * color keys. */
2179 if (surface->resource.map_binding == WINED3D_LOCATION_BUFFER && !surface_use_pbo(surface))
2180 surface->resource.map_binding = create_dib ? WINED3D_LOCATION_DIB : WINED3D_LOCATION_SYSMEM;
2181
2182 if (create_dib)
2183 {
2184 if (FAILED(hr = surface_create_dib_section(surface)))
2185 {
2186 ERR("Failed to create dib section, hr %#x.\n", hr);
2187 return hr;
2188 }
2189 if (!valid_location)
2190 valid_location = WINED3D_LOCATION_DIB;
2191 }
2192
2193 if (!valid_location)
2194 {
2195 #if defined(STAGING_CSMT)
2196 wined3d_resource_prepare_system_memory(&surface->resource);
2197 valid_location = WINED3D_LOCATION_SYSMEM;
2198 }
2199
2200 wined3d_resource_validate_location(&surface->resource, valid_location);
2201 #else /* STAGING_CSMT */
2202 surface_prepare_system_memory(surface);
2203 valid_location = WINED3D_LOCATION_SYSMEM;
2204 }
2205
2206 surface_validate_location(surface, valid_location);
2207 #endif /* STAGING_CSMT */
2208
2209 return WINED3D_OK;
2210 }
2211
2212 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
2213 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2214 {
2215 unsigned short *dst_s;
2216 const float *src_f;
2217 unsigned int x, y;
2218
2219 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2220
2221 for (y = 0; y < h; ++y)
2222 {
2223 src_f = (const float *)(src + y * pitch_in);
2224 dst_s = (unsigned short *) (dst + y * pitch_out);
2225 for (x = 0; x < w; ++x)
2226 {
2227 dst_s[x] = float_32_to_16(src_f + x);
2228 }
2229 }
2230 }
2231
2232 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
2233 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2234 {
2235 static const unsigned char convert_5to8[] =
2236 {
2237 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2238 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2239 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2240 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2241 };
2242 static const unsigned char convert_6to8[] =
2243 {
2244 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2245 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2246 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2247 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2248 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2249 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2250 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2251 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2252 };
2253 unsigned int x, y;
2254
2255 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2256
2257 for (y = 0; y < h; ++y)
2258 {
2259 const WORD *src_line = (const WORD *)(src + y * pitch_in);
2260 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2261 for (x = 0; x < w; ++x)
2262 {
2263 WORD pixel = src_line[x];
2264 dst_line[x] = 0xff000000u
2265 | convert_5to8[(pixel & 0xf800u) >> 11] << 16
2266 | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
2267 | convert_5to8[(pixel & 0x001fu)];
2268 }
2269 }
2270 }
2271
2272 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2273 * in both cases we're just setting the X / Alpha channel to 0xff. */
2274 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
2275 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2276 {
2277 unsigned int x, y;
2278
2279 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2280
2281 for (y = 0; y < h; ++y)
2282 {
2283 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
2284 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2285
2286 for (x = 0; x < w; ++x)
2287 {
2288 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
2289 }
2290 }
2291 }
2292
2293 static inline BYTE cliptobyte(int x)
2294 {
2295 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
2296 }
2297
2298 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
2299 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2300 {
2301 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
2302 unsigned int x, y;
2303
2304 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2305
2306 for (y = 0; y < h; ++y)
2307 {
2308 const BYTE *src_line = src + y * pitch_in;
2309 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2310 for (x = 0; x < w; ++x)
2311 {
2312 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2313 * C = Y - 16; D = U - 128; E = V - 128;
2314 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2315 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2316 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2317 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2318 * U and V are shared between the pixels. */
2319 if (!(x & 1)) /* For every even pixel, read new U and V. */
2320 {
2321 d = (int) src_line[1] - 128;
2322 e = (int) src_line[3] - 128;
2323 r2 = 409 * e + 128;
2324 g2 = - 100 * d - 208 * e + 128;
2325 b2 = 516 * d + 128;
2326 }
2327 c2 = 298 * ((int) src_line[0] - 16);
2328 dst_line[x] = 0xff000000
2329 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
2330 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
2331 | cliptobyte((c2 + b2) >> 8); /* blue */
2332 /* Scale RGB values to 0..255 range,
2333 * then clip them if still not in range (may be negative),
2334 * then shift them within DWORD if necessary. */
2335 src_line += 2;
2336 }
2337 }
2338 }
2339
2340 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
2341 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2342 {
2343 unsigned int x, y;
2344 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
2345
2346 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
2347
2348 for (y = 0; y < h; ++y)
2349 {
2350 const BYTE *src_line = src + y * pitch_in;
2351 WORD *dst_line = (WORD *)(dst + y * pitch_out);
2352 for (x = 0; x < w; ++x)
2353 {
2354 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2355 * C = Y - 16; D = U - 128; E = V - 128;
2356 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2357 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2358 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2359 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2360 * U and V are shared between the pixels. */
2361 if (!(x & 1)) /* For every even pixel, read new U and V. */
2362 {
2363 d = (int) src_line[1] - 128;
2364 e = (int) src_line[3] - 128;
2365 r2 = 409 * e + 128;
2366 g2 = - 100 * d - 208 * e + 128;
2367 b2 = 516 * d + 128;
2368 }
2369 c2 = 298 * ((int) src_line[0] - 16);
2370 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
2371 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
2372 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
2373 /* Scale RGB values to 0..255 range,
2374 * then clip them if still not in range (may be negative),
2375 * then shift them within DWORD if necessary. */
2376 src_line += 2;
2377 }
2378 }
2379 }
2380
2381 static void convert_dxt1_a8r8g8b8(const BYTE *src, BYTE *dst,
2382 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2383 {
2384 wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
2385 }
2386
2387 static void convert_dxt1_x8r8g8b8(const BYTE *src, BYTE *dst,
2388 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2389 {
2390 wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
2391 }
2392
2393 static void convert_dxt1_a4r4g4b4(const BYTE *src, BYTE *dst,
2394 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2395 {
2396 wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B4G4R4A4_UNORM, w, h);
2397 }
2398
2399 static void convert_dxt1_x4r4g4b4(const BYTE *src, BYTE *dst,
2400 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2401 {
2402 wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B4G4R4X4_UNORM, w, h);
2403 }
2404
2405 static void convert_dxt1_a1r5g5b5(const BYTE *src, BYTE *dst,
2406 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2407 {
2408 wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B5G5R5A1_UNORM, w, h);
2409 }
2410
2411 static void convert_dxt1_x1r5g5b5(const BYTE *src, BYTE *dst,
2412 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2413 {
2414 wined3d_dxt1_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B5G5R5X1_UNORM, w, h);
2415 }
2416
2417 static void convert_dxt3_a8r8g8b8(const BYTE *src, BYTE *dst,
2418 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2419 {
2420 wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
2421 }
2422
2423 static void convert_dxt3_x8r8g8b8(const BYTE *src, BYTE *dst,
2424 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2425 {
2426 wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
2427 }
2428
2429 static void convert_dxt3_a4r4g4b4(const BYTE *src, BYTE *dst,
2430 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2431 {
2432 wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B4G4R4A4_UNORM, w, h);
2433 }
2434
2435 static void convert_dxt3_x4r4g4b4(const BYTE *src, BYTE *dst,
2436 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2437 {
2438 wined3d_dxt3_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B4G4R4X4_UNORM, w, h);
2439 }
2440
2441 static void convert_dxt5_a8r8g8b8(const BYTE *src, BYTE *dst,
2442 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2443 {
2444 wined3d_dxt5_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
2445 }
2446
2447 static void convert_dxt5_x8r8g8b8(const BYTE *src, BYTE *dst,
2448 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2449 {
2450 wined3d_dxt5_decode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
2451 }
2452
2453 static void convert_a8r8g8b8_dxt1(const BYTE *src, BYTE *dst,
2454 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2455 {
2456 wined3d_dxt1_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
2457 }
2458
2459 static void convert_x8r8g8b8_dxt1(const BYTE *src, BYTE *dst,
2460 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2461 {
2462 wined3d_dxt1_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
2463 }
2464
2465 static void convert_a1r5g5b5_dxt1(const BYTE *src, BYTE *dst,
2466 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2467 {
2468 wined3d_dxt1_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B5G5R5A1_UNORM, w, h);
2469 }
2470
2471 static void convert_x1r5g5b5_dxt1(const BYTE *src, BYTE *dst,
2472 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2473 {
2474 wined3d_dxt1_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B5G5R5X1_UNORM, w, h);
2475 }
2476
2477 static void convert_a8r8g8b8_dxt3(const BYTE *src, BYTE *dst,
2478 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2479 {
2480 wined3d_dxt3_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
2481 }
2482
2483 static void convert_x8r8g8b8_dxt3(const BYTE *src, BYTE *dst,
2484 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2485 {
2486 wined3d_dxt3_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
2487 }
2488
2489 static void convert_a8r8g8b8_dxt5(const BYTE *src, BYTE *dst,
2490 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2491 {
2492 wined3d_dxt5_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8A8_UNORM, w, h);
2493 }
2494
2495 static void convert_x8r8g8b8_dxt5(const BYTE *src, BYTE *dst,
2496 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2497 {
2498 wined3d_dxt5_encode(src, dst, pitch_in, pitch_out, WINED3DFMT_B8G8R8X8_UNORM, w, h);
2499 }
2500
2501 struct d3dfmt_converter_desc
2502 {
2503 enum wined3d_format_id from, to;
2504 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
2505 };
2506
2507 static const struct d3dfmt_converter_desc converters[] =
2508 {
2509 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
2510 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
2511 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
2512 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
2513 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
2514 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
2515 };
2516
2517 static const struct d3dfmt_converter_desc dxtn_converters[] =
2518 {
2519 /* decode DXT */
2520 {WINED3DFMT_DXT1, WINED3DFMT_B8G8R8A8_UNORM, convert_dxt1_a8r8g8b8},
2521 {WINED3DFMT_DXT1, WINED3DFMT_B8G8R8X8_UNORM, convert_dxt1_x8r8g8b8},
2522 {WINED3DFMT_DXT1, WINED3DFMT_B4G4R4A4_UNORM, convert_dxt1_a4r4g4b4},
2523 {WINED3DFMT_DXT1, WINED3DFMT_B4G4R4X4_UNORM, convert_dxt1_x4r4g4b4},
2524 {WINED3DFMT_DXT1, WINED3DFMT_B5G5R5A1_UNORM, convert_dxt1_a1r5g5b5},
2525 {WINED3DFMT_DXT1, WINED3DFMT_B5G5R5X1_UNORM, convert_dxt1_x1r5g5b5},
2526 {WINED3DFMT_DXT3, WINED3DFMT_B8G8R8A8_UNORM, convert_dxt3_a8r8g8b8},
2527 {WINED3DFMT_DXT3, WINED3DFMT_B8G8R8X8_UNORM, convert_dxt3_x8r8g8b8},
2528 {WINED3DFMT_DXT3, WINED3DFMT_B4G4R4A4_UNORM, convert_dxt3_a4r4g4b4},
2529 {WINED3DFMT_DXT3, WINED3DFMT_B4G4R4X4_UNORM, convert_dxt3_x4r4g4b4},
2530 {WINED3DFMT_DXT5, WINED3DFMT_B8G8R8A8_UNORM, convert_dxt5_a8r8g8b8},
2531 {WINED3DFMT_DXT5, WINED3DFMT_B8G8R8X8_UNORM, convert_dxt5_x8r8g8b8},
2532
2533 /* encode DXT */
2534 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_DXT1, convert_a8r8g8b8_dxt1},
2535 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_DXT1, convert_x8r8g8b8_dxt1},
2536 {WINED3DFMT_B5G5R5A1_UNORM, WINED3DFMT_DXT1, convert_a1r5g5b5_dxt1},
2537 {WINED3DFMT_B5G5R5X1_UNORM, WINED3DFMT_DXT1, convert_x1r5g5b5_dxt1},
2538 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_DXT3, convert_a8r8g8b8_dxt3},
2539 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_DXT3, convert_x8r8g8b8_dxt3},
2540 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_DXT5, convert_a8r8g8b8_dxt5},
2541 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_DXT5, convert_x8r8g8b8_dxt5}
2542 };
2543
2544 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
2545 enum wined3d_format_id to)
2546 {
2547 unsigned int i;
2548
2549 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
2550 {
2551 if (converters[i].from == from && converters[i].to == to)
2552 return &converters[i];
2553 }
2554
2555 for (i = 0; i < (sizeof(dxtn_converters) / sizeof(*dxtn_converters)); ++i)
2556 {
2557 if (dxtn_converters[i].from == from && dxtn_converters[i].to == to)
2558 return wined3d_dxtn_supported() ? &dxtn_converters[i] : NULL;
2559 }
2560
2561 return NULL;
2562 }
2563
2564 static struct wined3d_texture *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
2565 {
2566 #if defined(STAGING_CSMT)
2567 void *dst_data = NULL, *src_data = NULL;
2568 UINT src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
2569 const struct d3dfmt_converter_desc *conv;
2570 struct wined3d_texture *ret = NULL;
2571 struct wined3d_resource_desc desc;
2572 struct wined3d_surface *dst;
2573 struct wined3d_context *context = NULL;
2574 struct wined3d_device *device = source->resource.device;
2575 #else /* STAGING_CSMT */
2576 struct wined3d_map_desc src_map, dst_map;
2577 const struct d3dfmt_converter_desc *conv;
2578 struct wined3d_texture *ret = NULL;
2579 struct wined3d_resource_desc desc;
2580 struct wined3d_surface *dst;
2581 #endif /* STAGING_CSMT */
2582
2583 conv = find_converter(source->resource.format->id, to_fmt);
2584 if (!conv)
2585 {
2586 FIXME("Cannot find a conversion function from format %s to %s.\n",
2587 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
2588 return NULL;
2589 }
2590
2591 /* FIXME: Multisampled conversion? */
2592 wined3d_resource_get_desc(&source->resource, &desc);
2593 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
2594 desc.format = to_fmt;
2595 desc.usage = 0;
2596 desc.pool = WINED3D_POOL_SCRATCH;
2597 if (FAILED(wined3d_texture_create(source->resource.device, &desc, 1,
2598 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
2599 NULL, NULL, &wined3d_null_parent_ops, &ret)))
2600 {
2601 ERR("Failed to create a destination surface for conversion.\n");
2602 return NULL;
2603 }
2604 dst = surface_from_resource(wined3d_texture_get_sub_resource(ret, 0));
2605
2606 #if defined(STAGING_CSMT)
2607 wined3d_resource_get_pitch(&source->resource, &src_row_pitch, &src_slice_pitch);
2608 wined3d_resource_get_pitch(&ret->resource, &dst_row_pitch, &dst_slice_pitch);
2609
2610 if (device->d3d_initialized)
2611 context = context_acquire(device, NULL);
2612
2613 wined3d_resource_load_location(&source->resource, context, source->resource.map_binding);
2614 src_data = wined3d_resource_get_map_ptr(&source->resource, context, WINED3D_MAP_READONLY);
2615 if (!src_data)
2616 goto error;
2617
2618 if (!wined3d_resource_prepare_map_memory(&dst->resource, context))
2619 goto error;
2620 dst_data = wined3d_resource_get_map_ptr(&dst->resource, context, 0);
2621 if (!dst_data)
2622 goto error;
2623
2624 conv->convert(src_data, dst_data, src_row_pitch, dst_row_pitch,
2625 source->resource.width, source->resource.height);
2626
2627 wined3d_resource_release_map_ptr(&dst->resource, context);
2628 wined3d_resource_release_map_ptr(&source->resource, context);
2629
2630 if (context)
2631 context_release(context);
2632
2633 return ret;
2634
2635 error:
2636 ERR("Surface conversion failed.\n");
2637
2638 if (src_data)
2639 wined3d_resource_release_map_ptr(&source->resource, context);
2640 if (dst_data)
2641 wined3d_resource_release_map_ptr(&ret->resource, context);
2642 if (ret)
2643 wined3d_texture_decref(ret);
2644 if (context)
2645 context_release(context);
2646 return NULL;
2647 #else /* STAGING_CSMT */
2648 memset(&src_map, 0, sizeof(src_map));
2649 memset(&dst_map, 0, sizeof(dst_map));
2650
2651 if (FAILED(wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
2652 {
2653 ERR("Failed to lock the source surface.\n");
2654 wined3d_texture_decref(ret);
2655 return NULL;
2656 }
2657 if (FAILED(wined3d_surface_map(dst, &dst_map, NULL, 0)))
2658 {
2659 ERR("Failed to lock the destination surface.\n");
2660 wined3d_surface_unmap(source);
2661 wined3d_texture_decref(ret);
2662 return NULL;
2663 }
2664
2665 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
2666 source->resource.width, source->resource.height);
2667
2668 wined3d_surface_unmap(dst);
2669 wined3d_surface_unmap(source);
2670
2671 return ret;
2672 #endif /* STAGING_CSMT */
2673 }
2674
2675 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
2676 unsigned int bpp, UINT pitch, DWORD color)
2677 {
2678 BYTE *first;
2679 unsigned int x, y;
2680
2681 /* Do first row */
2682
2683 #define COLORFILL_ROW(type) \
2684 do { \
2685 type *d = (type *)buf; \
2686 for (x = 0; x < width; ++x) \
2687 d[x] = (type)color; \
2688 } while(0)
2689
2690 switch (bpp)
2691 {
2692 case 1:
2693 COLORFILL_ROW(BYTE);
2694 break;
2695
2696 case 2:
2697 COLORFILL_ROW(WORD);
2698 break;
2699
2700 case 3:
2701 {
2702 BYTE *d = buf;
2703 for (x = 0; x < width; ++x, d += 3)
2704 {
2705 d[0] = (color ) & 0xff;
2706 d[1] = (color >> 8) & 0xff;
2707 d[2] = (color >> 16) & 0xff;
2708 }
2709 break;
2710 }
2711 case 4:
2712 COLORFILL_ROW(DWORD);
2713 break;
2714
2715 default:
2716 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
2717 return WINED3DERR_NOTAVAILABLE;
2718 }
2719
2720 #undef COLORFILL_ROW
2721
2722 /* Now copy first row. */
2723 first = buf;
2724 for (y = 1; y < height; ++y)
2725 {
2726 buf += pitch;
2727 memcpy(buf, first, width * bpp);
2728 }
2729
2730 return WINED3D_OK;
2731 }
2732
2733 HRESULT wined3d_surface_unmap(struct wined3d_surface *surface)
2734 {
2735 #if defined(STAGING_CSMT)
2736 HRESULT hr;
2737 TRACE("surface %p.\n", surface);
2738
2739 hr = wined3d_resource_unmap(&surface->resource);
2740 if (FAILED(hr))
2741 return hr;
2742
2743 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
2744
2745 return hr;
2746 #else /* STAGING_CSMT */
2747 TRACE("surface %p.\n", surface);
2748
2749 if (!surface->resource.map_count)
2750 {
2751 WARN("Trying to unmap unmapped surface.\n");
2752 return WINEDDERR_NOTLOCKED;
2753 }
2754 --surface->resource.map_count;
2755
2756 surface->surface_ops->surface_unmap(surface);
2757
2758 return WINED3D_OK;
2759 #endif /* STAGING_CSMT */
2760 }
2761
2762 HRESULT wined3d_surface_map(struct wined3d_surface *surface, struct wined3d_map_desc *map_desc,
2763 const struct wined3d_box *box, DWORD flags)
2764 {
2765 const struct wined3d_format *format = surface->resource.format;
2766 unsigned int fmt_flags = surface->container->resource.format_flags;
2767 #if defined(STAGING_CSMT)
2768
2769 if ((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && box
2770 && !surface_check_block_align(surface, box))
2771 #else /* STAGING_CSMT */
2772 struct wined3d_device *device = surface->resource.device;
2773 struct wined3d_context *context;
2774 const struct wined3d_gl_info *gl_info;
2775 BYTE *base_memory;
2776
2777 TRACE("surface %p, map_desc %p, box %s, flags %#x.\n",
2778 surface, map_desc, debug_box(box), flags);
2779
2780 if (surface->resource.map_count)
2781 {
2782 WARN("Surface is already mapped.\n");
2783 return WINED3DERR_INVALIDCALL;
2784 }
2785
2786 if ((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && box
2787 && !wined3d_texture_check_block_align(surface->container, surface->texture_level, box))
2788 #endif /* STAGING_CSMT */
2789 {
2790 WARN("Map box %s is misaligned for %ux%u blocks.\n",
2791 debug_box(box), format->block_width, format->block_height);
2792
2793 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
2794 return WINED3DERR_INVALIDCALL;
2795 }
2796
2797 #if !defined(STAGING_CSMT)
2798 ++surface->resource.map_count;
2799
2800 if (!(surface->resource.access_flags & WINED3D_RESOURCE_ACCESS_CPU))
2801 WARN("Trying to lock unlockable surface.\n");
2802
2803 #endif /* STAGING_CSMT */
2804 /* Performance optimization: Count how often a surface is mapped, if it is
2805 * mapped regularly do not throw away the system memory copy. This avoids
2806 * the need to download the surface from OpenGL all the time. The surface
2807 * is still downloaded if the OpenGL texture is changed. Note that this
2808 * only really makes sense for managed textures.*/
2809 if (!(surface->container->flags & WINED3D_TEXTURE_DYNAMIC_MAP)
2810 && surface->resource.map_binding == WINED3D_LOCATION_SYSMEM)
2811 {
2812 if (++surface->lockCount > MAXLOCKCOUNT)
2813 {
2814 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
2815 surface->container->flags |= WINED3D_TEXTURE_DYNAMIC_MAP;
2816 }
2817 }
2818
2819 #if defined(STAGING_CSMT)
2820 if (box)
2821 {
2822 surface->lockedRect.left = box->left;
2823 surface->lockedRect.top = box->top;
2824 surface->lockedRect.right = box->right;
2825 surface->lockedRect.bottom = box->bottom;
2826 }
2827 else
2828 {
2829 surface->lockedRect.left = 0;
2830 surface->lockedRect.top = 0;
2831 surface->lockedRect.right = surface->resource.width;
2832 surface->lockedRect.bottom = surface->resource.height;
2833 }
2834
2835 return wined3d_resource_map(&surface->resource, map_desc, box, flags);
2836 }
2837
2838 void wined3d_surface_getdc_cs(struct wined3d_surface *surface)
2839 {
2840 HRESULT hr;
2841 struct wined3d_device *device = surface->resource.device;
2842 struct wined3d_context *context = NULL;
2843
2844 if (device->d3d_initialized)
2845 context = context_acquire(device, NULL);
2846
2847 /* Create a DIB section if there isn't a dc yet. */
2848 if (!surface->hDC)
2849 {
2850 if (FAILED(hr = surface_create_dib_section(surface)))
2851 {
2852 if (context)
2853 context_release(context);
2854 return;
2855 }
2856 if (!(surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY
2857 || surface->container->flags & WINED3D_TEXTURE_PIN_SYSMEM
2858 || surface->resource.buffer))
2859 surface->resource.map_binding = WINED3D_LOCATION_DIB;
2860 }
2861
2862 wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_DIB);
2863 wined3d_resource_invalidate_location(&surface->resource, ~WINED3D_LOCATION_DIB);
2864
2865 if (context)
2866 context_release(context);
2867 }
2868
2869 void wined3d_surface_releasedc_cs(struct wined3d_surface *surface)
2870 {
2871 if (surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY || (surface->container->flags & WINED3D_TEXTURE_PIN_SYSMEM
2872 && surface->resource.map_binding != WINED3D_LOCATION_DIB))
2873 {
2874 /* The game Salammbo modifies the surface contents without mapping the surface between
2875 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
2876 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
2877 * Do not only copy the DIB to the map location, but also make sure the map location is
2878 * copied back to the DIB in the next getdc call.
2879 *
2880 * The same consideration applies to user memory surfaces. */
2881 struct wined3d_device *device = surface->resource.device;
2882 struct wined3d_context *context = NULL;
2883
2884 if (device->d3d_initialized)
2885 context = context_acquire(device, NULL);
2886
2887 wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
2888 wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_DIB);
2889 if (context)
2890 context_release(context);
2891 }
2892 }
2893
2894 static void read_from_framebuffer(struct wined3d_surface *surface,
2895 struct wined3d_context *old_ctx, DWORD dst_location)
2896 {
2897 struct wined3d_device *device = surface->resource.device;
2898 const struct wined3d_gl_info *gl_info;
2899 struct wined3d_context *context = old_ctx;
2900 struct wined3d_surface *restore_rt = NULL;
2901 unsigned int row_pitch, slice_pitch;
2902 BYTE *mem;
2903 BYTE *row, *top, *bottom;
2904 int i;
2905 BOOL srcIsUpsideDown;
2906 struct wined3d_bo_address data;
2907
2908 wined3d_resource_get_memory(&surface->resource, dst_location, &data);
2909 #else /* STAGING_CSMT */
2910 surface_prepare_map_memory(surface);
2911 if (flags & WINED3D_MAP_DISCARD)
2912 {
2913 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2914 wined3d_debug_location(surface->resource.map_binding));
2915 surface_validate_location(surface, surface->resource.map_binding);
2916 }
2917 else
2918 {
2919 struct wined3d_context *context = NULL;
2920
2921 if (surface->resource.usage & WINED3DUSAGE_DYNAMIC)
2922 WARN_(d3d_perf)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
2923
2924 if (surface->resource.device->d3d_initialized)
2925 context = context_acquire(surface->resource.device, NULL);
2926 surface_load_location(surface, context, surface->resource.map_binding);
2927 if (context)
2928 context_release(context);
2929 }
2930
2931 if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
2932 surface_invalidate_location(surface, ~surface->resource.map_binding);
2933
2934 switch (surface->resource.map_binding)
2935 {
2936 case WINED3D_LOCATION_SYSMEM:
2937 base_memory = surface->resource.heap_memory;
2938 break;
2939
2940 case WINED3D_LOCATION_USER_MEMORY:
2941 base_memory = surface->container->user_memory;
2942 break;
2943
2944 case WINED3D_LOCATION_DIB:
2945 base_memory = surface->dib.bitmap_data;
2946 break;
2947
2948 case WINED3D_LOCATION_BUFFER:
2949 context = context_acquire(device, NULL);
2950 gl_info = context->gl_info;
2951
2952 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, surface->pbo));
2953 base_memory = GL_EXTCALL(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE));
2954 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2955 checkGLcall("map PBO");
2956
2957 context_release(context);
2958 break;
2959
2960 default:
2961 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->resource.map_binding));
2962 base_memory = NULL;
2963 }
2964
2965 if (fmt_flags & WINED3DFMT_FLAG_BROKEN_PITCH)
2966 {
2967 map_desc->row_pitch = surface->resource.width * format->byte_count;
2968 map_desc->slice_pitch = surface->resource.height * map_desc->row_pitch;
2969 }
2970 else
2971 {
2972 wined3d_texture_get_pitch(surface->container, surface->texture_level,
2973 &map_desc->row_pitch, &map_desc->slice_pitch);
2974 }
2975
2976 if (!box)
2977 {
2978 map_desc->data = base_memory;
2979 surface->lockedRect.left = 0;
2980 surface->lockedRect.top = 0;
2981 surface->lockedRect.right = surface->resource.width;
2982 surface->lockedRect.bottom = surface->resource.height;
2983 }
2984 else
2985 {
2986 if ((fmt_flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
2987 {
2988 /* Compressed textures are block based, so calculate the offset of
2989 * the block that contains the top-left pixel of the locked rectangle. */
2990 map_desc->data = base_memory
2991 + ((box->top / format->block_height) * map_desc->row_pitch)
2992 + ((box->left / format->block_width) * format->block_byte_count);
2993 }
2994 else
2995 {
2996 map_desc->data = base_memory
2997 + (map_desc->row_pitch * box->top)
2998 + (box->left * format->byte_count);
2999 }
3000 surface->lockedRect.left = box->left;
3001 surface->lockedRect.top = box->top;
3002 surface->lockedRect.right = box->right;
3003 surface->lockedRect.bottom = box->bottom;
3004 }
3005
3006 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3007 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
3008
3009 return WINED3D_OK;
3010 }
3011
3012 static void read_from_framebuffer(struct wined3d_surface *surface,
3013 struct wined3d_context *old_ctx, DWORD dst_location)
3014 {
3015 struct wined3d_device *device = surface->resource.device;
3016 const struct wined3d_gl_info *gl_info;
3017 struct wined3d_context *context = old_ctx;
3018 struct wined3d_surface *restore_rt = NULL;
3019 unsigned int row_pitch, slice_pitch;
3020 BYTE *mem;
3021 BYTE *row, *top, *bottom;
3022 int i;
3023 BOOL srcIsUpsideDown;
3024 struct wined3d_bo_address data;
3025
3026 surface_get_memory(surface, &data, dst_location);
3027 #endif /* STAGING_CSMT */
3028
3029 if (surface != old_ctx->current_rt)
3030 {
3031 restore_rt = old_ctx->current_rt;
3032 context = context_acquire(device, surface);
3033 }
3034
3035 context_apply_blit_state(context, device);
3036 gl_info = context->gl_info;
3037
3038 /* Select the correct read buffer, and give some debug output.
3039 * There is no need to keep track of the current read buffer or reset it, every part of the code
3040 * that reads sets the read buffer as desired.
3041 */
3042 if (wined3d_resource_is_offscreen(&surface->container->resource))
3043 {
3044 /* Mapping the primary render target which is not on a swapchain.
3045 * Read from the back buffer. */
3046 TRACE("Mapping offscreen render target.\n");
3047 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
3048 srcIsUpsideDown = TRUE;
3049 }
3050 else
3051 {
3052 /* Onscreen surfaces are always part of a swapchain */
3053 GLenum buffer = surface_get_gl_buffer(surface);
3054 TRACE("Mapping %#x buffer.\n", buffer);
3055 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
3056 checkGLcall("glReadBuffer");
3057 srcIsUpsideDown = FALSE;
3058 }
3059
3060 if (data.buffer_object)
3061 {
3062 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
3063 checkGLcall("glBindBuffer");
3064 }
3065
3066 #if defined(STAGING_CSMT)
3067 wined3d_resource_get_pitch(&surface->resource, &row_pitch, &slice_pitch);
3068 #else /* STAGING_CSMT */
3069 wined3d_texture_get_pitch(surface->container, surface->texture_level, &row_pitch, &slice_pitch);
3070 #endif /* STAGING_CSMT */
3071
3072 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3073 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / surface->resource.format->byte_count);
3074 checkGLcall("glPixelStorei");
3075
3076 gl_info->gl_ops.gl.p_glReadPixels(0, 0,
3077 surface->resource.width, surface->resource.height,
3078 surface->resource.format->glFormat,
3079 surface->resource.format->glType, data.addr);
3080 checkGLcall("glReadPixels");
3081
3082 /* Reset previous pixel store pack state */
3083 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
3084 checkGLcall("glPixelStorei");
3085
3086 if (!srcIsUpsideDown)
3087 {
3088 /* glReadPixels returns the image upside down, and there is no way to
3089 * prevent this. Flip the lines in software. */
3090
3091 if (!(row = HeapAlloc(GetProcessHeap(), 0, row_pitch)))
3092 goto error;
3093
3094 if (data.buffer_object)
3095 {
3096 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
3097 checkGLcall("glMapBuffer");
3098 }
3099 else
3100 mem = data.addr;
3101
3102 top = mem;
3103 bottom = mem + row_pitch * (surface->resource.height - 1);
3104 for (i = 0; i < surface->resource.height / 2; i++)
3105 {
3106 memcpy(row, top, row_pitch);
3107 memcpy(top, bottom, row_pitch);
3108 memcpy(bottom, row, row_pitch);
3109 top += row_pitch;
3110 bottom -= row_pitch;
3111 }
3112 HeapFree(GetProcessHeap(), 0, row);
3113
3114 if (data.buffer_object)
3115 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
3116 }
3117
3118 error:
3119 if (data.buffer_object)
3120 {
3121 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
3122 checkGLcall("glBindBuffer");
3123 }
3124
3125 if (restore_rt)
3126 context_restore(context, restore_rt);
3127 }
3128
3129 /* Read the framebuffer contents into a texture. Note that this function
3130 * doesn't do any kind of flipping. Using this on an onscreen surface will
3131 * result in a flipped D3D texture.
3132 *
3133 * Context activation is done by the caller. This function may temporarily
3134 * switch to a different context and restore the original one before return. */
3135 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct wined3d_context *old_ctx)
3136 {
3137 struct wined3d_device *device = surface->resource.device;
3138 const struct wined3d_gl_info *gl_info;
3139 struct wined3d_context *context = old_ctx;
3140 struct wined3d_surface *restore_rt = NULL;
3141
3142 if (old_ctx->current_rt != surface)
3143 {
3144 restore_rt = old_ctx->current_rt;
3145 context = context_acquire(device, surface);
3146 }
3147
3148 gl_info = context->gl_info;
3149 device_invalidate_state(device, STATE_FRAMEBUFFER);
3150
3151 wined3d_texture_prepare_texture(surface->container, context, srgb);
3152 wined3d_texture_bind_and_dirtify(surface->container, context, srgb);
3153
3154 TRACE("Reading back offscreen render target %p.\n", surface);
3155
3156 if (wined3d_resource_is_offscreen(&surface->container->resource))
3157 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
3158 else
3159 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
3160 checkGLcall("glReadBuffer");
3161
3162 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
3163 0, 0, 0, 0, surface->resource.width, surface->resource.height);
3164 checkGLcall("glCopyTexSubImage2D");
3165
3166 if (restore_rt)
3167 context_restore(context, restore_rt);
3168 }
3169
3170 static void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
3171 {
3172 if (multisample)
3173 {
3174 DWORD samples;
3175
3176 if (surface->rb_multisample)
3177 return;
3178
3179 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
3180 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
3181 * to GL_NV_framebuffer_multisample_coverage.
3182 *
3183 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
3184 * but it does not have an equivalent OpenGL extension. */
3185
3186 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
3187 * as the count of advertised multisample types for the surface format. */
3188 if (surface->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE)
3189 {
3190 const struct wined3d_format *format = surface->resource.format;
3191 unsigned int i, count = 0;
3192
3193 for (i = 0; i < sizeof(format->multisample_types) * 8; ++i)
3194 {
3195 if (format->multisample_types & 1u << i)
3196 {
3197 if (surface->resource.multisample_quality == count++)
3198 break;
3199 }
3200 }
3201 samples = i + 1;
3202 }
3203 else
3204 {
3205 samples = surface->resource.multisample_type;
3206 }
3207
3208 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
3209 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
3210 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
3211 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
3212 checkGLcall("glRenderbufferStorageMultisample()");
3213 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
3214 }
3215 else
3216 {
3217 if (surface->rb_resolved)
3218 return;
3219
3220 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
3221 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
3222 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
3223 surface->pow2Width, surface->pow2Height);
3224 checkGLcall("glRenderbufferStorage()");
3225 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
3226 }
3227 }
3228
3229 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3230 * pixel copy calls. */
3231 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
3232 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
3233 {
3234 struct wined3d_device *device = dst_surface->resource.device;
3235 const struct wined3d_gl_info *gl_info;
3236 float xrel, yrel;
3237 struct wined3d_context *context;
3238 BOOL upsidedown = FALSE;
3239 RECT dst_rect = *dst_rect_in;
3240
3241 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3242 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3243 */
3244 if(dst_rect.top > dst_rect.bottom) {
3245 UINT tmp = dst_rect.bottom;
3246 dst_rect.bottom = dst_rect.top;
3247 dst_rect.top = tmp;
3248 upsidedown = TRUE;
3249 }
3250
3251 context = context_acquire(device, src_surface);
3252 gl_info = context->gl_info;
3253 context_apply_blit_state(context, device);
3254 wined3d_texture_load(dst_surface->container, context, FALSE);
3255
3256 /* Bind the target texture */
3257 context_bind_texture(context, dst_surface->container->target, dst_surface->container->texture_rgb.name);
3258 if (wined3d_resource_is_offscreen(&src_surface->container->resource))
3259 {
3260 TRACE("Reading from an offscreen target\n");
3261 upsidedown = !upsidedown;
3262 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
3263 }
3264 else
3265 {
3266 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
3267 }
3268 checkGLcall("glReadBuffer");
3269
3270 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
3271 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
3272
3273 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3274 {
3275 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3276
3277 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
3278 ERR("Texture filtering not supported in direct blit.\n");
3279 }
3280 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
3281 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3282 {
3283 ERR("Texture filtering not supported in direct blit\n");
3284 }
3285
3286 if (upsidedown
3287 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3288 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3289 {
3290 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3291 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3292 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
3293 src_rect->left, src_surface->resource.height - src_rect->bottom,
3294 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3295 }
3296 else
3297 {
3298 LONG row;
3299 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
3300 /* I have to process this row by row to swap the image,
3301 * otherwise it would be upside down, so stretching in y direction
3302 * doesn't cost extra time
3303 *
3304 * However, stretching in x direction can be avoided if not necessary
3305 */
3306 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
3307 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3308 {
3309 /* Well, that stuff works, but it's very slow.
3310 * find a better way instead
3311 */
3312 LONG col;
3313
3314 for (col = dst_rect.left; col < dst_rect.right; ++col)
3315 {
3316 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3317 dst_rect.left + col /* x offset */, row /* y offset */,
3318 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
3319 }
3320 }
3321 else
3322 {
3323 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3324 dst_rect.left /* x offset */, row /* y offset */,
3325 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
3326 }
3327 }
3328 }
3329 checkGLcall("glCopyTexSubImage2D");
3330
3331 context_release(context);
3332
3333 /* The texture is now most up to date - If the surface is a render target
3334 * and has a drawable, this path is never entered. */
3335 #if defined(STAGING_CSMT)
3336 wined3d_resource_validate_location(&dst_surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
3337 wined3d_resource_invalidate_location(&dst_surface->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
3338 #else /* STAGING_CSMT */
3339 surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
3340 surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
3341 #endif /* STAGING_CSMT */
3342 }
3343
3344 /* Uses the hardware to stretch and flip the image */
3345 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
3346 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
3347 {
3348 struct wined3d_device *device = dst_surface->resource.device;
3349 GLuint src, backup = 0;
3350 float left, right, top, bottom; /* Texture coordinates */
3351 UINT fbwidth = src_surface->resource.width;
3352 UINT fbheight = src_surface->resource.height;
3353 const struct wined3d_gl_info *gl_info;
3354 struct wined3d_context *context;
3355 GLenum drawBuffer = GL_BACK;
3356 GLenum texture_target;
3357 BOOL noBackBufferBackup;
3358 BOOL src_offscreen;
3359 BOOL upsidedown = FALSE;
3360 RECT dst_rect = *dst_rect_in;
3361
3362 TRACE("Using hwstretch blit\n");
3363 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3364 context = context_acquire(device, src_surface);
3365 gl_info = context->gl_info;
3366 context_apply_blit_state(context, device);
3367 wined3d_texture_load(dst_surface->container, context, FALSE);
3368
3369 src_offscreen = wined3d_resource_is_offscreen(&src_surface->container->resource);
3370 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
3371 if (!noBackBufferBackup && !src_surface->container->texture_rgb.name)
3372 {
3373 /* Get it a description */
3374 wined3d_texture_load(src_surface->container, context, FALSE);
3375 }
3376
3377 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3378 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3379 */
3380 if (context->aux_buffers >= 2)
3381 {
3382 /* Got more than one aux buffer? Use the 2nd aux buffer */
3383 drawBuffer = GL_AUX1;
3384 }
3385 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
3386 {
3387 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3388 drawBuffer = GL_AUX0;
3389 }
3390
3391 if (noBackBufferBackup)
3392 {
3393 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
3394 checkGLcall("glGenTextures");
3395 context_bind_texture(context, GL_TEXTURE_2D, backup);
3396 texture_target = GL_TEXTURE_2D;
3397 }
3398 else
3399 {
3400 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3401 * we are reading from the back buffer, the backup can be used as source texture
3402 */
3403 texture_target = src_surface->texture_target;
3404 context_bind_texture(context, texture_target, src_surface->container->texture_rgb.name);
3405 gl_info->gl_ops.gl.p_glEnable(texture_target);
3406 checkGLcall("glEnable(texture_target)");
3407
3408 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3409 #if defined(STAGING_CSMT)
3410 wined3d_resource_invalidate_location(&src_surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
3411 #else /* STAGING_CSMT */
3412 src_surface->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
3413 #endif /* STAGING_CSMT */
3414 }
3415
3416 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3417 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3418 */
3419 if(dst_rect.top > dst_rect.bottom) {
3420 UINT tmp = dst_rect.bottom;
3421 dst_rect.bottom = dst_rect.top;
3422 dst_rect.top = tmp;
3423 upsidedown = TRUE;
3424 }
3425
3426 if (src_offscreen)
3427 {
3428 TRACE("Reading from an offscreen target\n");
3429 upsidedown = !upsidedown;
3430 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
3431 }
3432 else
3433 {
3434 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
3435 }
3436
3437 /* TODO: Only back up the part that will be overwritten */
3438 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
3439
3440 checkGLcall("glCopyTexSubImage2D");
3441
3442 /* No issue with overriding these - the sampler is dirty due to blit usage */
3443 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
3444 checkGLcall("glTexParameteri");
3445 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
3446 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
3447 checkGLcall("glTexParameteri");
3448
3449 if (!src_surface->container->swapchain
3450 || src_surface->container == src_surface->container->swapchain->back_buffers[0])
3451 {
3452 src = backup ? backup : src_surface->container->texture_rgb.name;
3453 }
3454 else
3455 {
3456 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
3457 checkGLcall("glReadBuffer(GL_FRONT)");
3458
3459 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
3460 checkGLcall("glGenTextures(1, &src)");
3461 context_bind_texture(context, GL_TEXTURE_2D, src);
3462
3463 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3464 * out for power of 2 sizes
3465 */
3466 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
3467 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
3468 checkGLcall("glTexImage2D");
3469 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
3470
3471 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3472 checkGLcall("glTexParameteri");
3473 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3474 checkGLcall("glTexParameteri");
3475
3476 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
3477 checkGLcall("glReadBuffer(GL_BACK)");
3478
3479 if (texture_target != GL_TEXTURE_2D)
3480 {
3481 gl_info->gl_ops.gl.p_glDisable(texture_target);
3482 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
3483 texture_target = GL_TEXTURE_2D;
3484 }
3485 }
3486 checkGLcall("glEnd and previous");
3487
3488 left = src_rect->left;
3489 right = src_rect->right;
3490
3491 if (!upsidedown)
3492 {
3493 top = src_surface->resource.height - src_rect->top;
3494 bottom = src_surface->resource.height - src_rect->bottom;
3495 }
3496 else
3497 {
3498 top = src_surface->resource.height - src_rect->bottom;
3499 bottom = src_surface->resource.height - src_rect->top;
3500 }
3501
3502 if (src_surface->container->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
3503 {
3504 left /= src_surface->pow2Width;
3505 right /= src_surface->pow2Width;
3506 top /= src_surface->pow2Height;
3507 bottom /= src_surface->pow2Height;
3508 }
3509
3510 /* draw the source texture stretched and upside down. The correct surface is bound already */
3511 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3512 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3513
3514 context_set_draw_buffer(context, drawBuffer);
3515 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
3516
3517 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
3518 /* bottom left */
3519 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
3520 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
3521
3522 /* top left */
3523 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
3524 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
3525
3526 /* top right */
3527 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
3528 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3529
3530 /* bottom right */
3531 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
3532 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
3533 gl_info->gl_ops.gl.p_glEnd();
3534 checkGLcall("glEnd and previous");
3535
3536 if (texture_target != dst_surface->texture_target)
3537 {
3538 gl_info->gl_ops.gl.p_glDisable(texture_target);
3539 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
3540 texture_target = dst_surface->texture_target;
3541 }
3542
3543 /* Now read the stretched and upside down image into the destination texture */
3544 context_bind_texture(context, texture_target, dst_surface->container->texture_rgb.name);
3545 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
3546 0,
3547 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
3548 0, 0, /* We blitted the image to the origin */
3549 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3550 checkGLcall("glCopyTexSubImage2D");
3551
3552 if (drawBuffer == GL_BACK)
3553 {
3554 /* Write the back buffer backup back. */
3555 if (backup)
3556 {
3557 if (texture_target != GL_TEXTURE_2D)
3558 {
3559 gl_info->gl_ops.gl.p_glDisable(texture_target);
3560 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
3561 texture_target = GL_TEXTURE_2D;
3562 }
3563 context_bind_texture(context, GL_TEXTURE_2D, backup);
3564 }
3565 else
3566 {
3567 if (texture_target != src_surface->texture_target)
3568 {
3569 gl_info->gl_ops.gl.p_glDisable(texture_target);
3570 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
3571 texture_target = src_surface->texture_target;
3572 }
3573 context_bind_texture(context, src_surface->texture_target, src_surface->container->texture_rgb.name);
3574 }
3575
3576 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
3577 /* top left */
3578 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
3579 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
3580
3581 /* bottom left */
3582 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
3583 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
3584
3585 /* bottom right */
3586 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
3587 (float)fbheight / (float)src_surface->pow2Height);
3588 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
3589
3590 /* top right */
3591 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
3592 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
3593 gl_info->gl_ops.gl.p_glEnd();
3594 }
3595 gl_info->gl_ops.gl.p_glDisable(texture_target);
3596 checkGLcall("glDisable(texture_target)");
3597
3598 /* Cleanup */
3599 if (src != src_surface->container->texture_rgb.name && src != backup)
3600 {
3601 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
3602 checkGLcall("glDeleteTextures(1, &src)");
3603 }
3604 if (backup)
3605 {
3606 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
3607 checkGLcall("glDeleteTextures(1, &backup)");
3608 }
3609
3610 #if defined(STAGING_CSMT)
3611 if (wined3d_settings.cs_multithreaded)
3612 gl_info->gl_ops.gl.p_glFinish();
3613 else if (wined3d_settings.strict_draw_ordering)
3614 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
3615
3616 context_release(context);
3617
3618 /* The texture is now most up to date - If the surface is a render target
3619 * and has a drawable, this path is never entered. */
3620 wined3d_resource_validate_location(&dst_surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
3621 wined3d_resource_invalidate_location(&dst_surface->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
3622 #else /* STAGING_CSMT */
3623 if (wined3d_settings.strict_draw_ordering)
3624 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
3625
3626 context_release(context);
3627
3628 /* The texture is now most up to date - If the surface is a render target
3629 * and has a drawable, this path is never entered. */
3630 surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
3631 surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
3632 #endif /* STAGING_CSMT */
3633 }
3634
3635 /* Front buffer coordinates are always full screen coordinates, but our GL
3636 * drawable is limited to the window's client area. The sysmem and texture
3637 * copies do have the full screen size. Note that GL has a bottom-left
3638 * origin, while D3D has a top-left origin. */
3639 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
3640 {
3641 UINT drawable_height;
3642
3643 if (surface->container->swapchain && surface->container == surface->container->swapchain->front_buffer)
3644 {
3645 POINT offset = {0, 0};
3646 RECT windowsize;
3647
3648 ScreenToClient(window, &offset);
3649 OffsetRect(rect, offset.x, offset.y);
3650
3651 GetClientRect(window, &windowsize);
3652 drawable_height = windowsize.bottom - windowsize.top;
3653 }
3654 else
3655 {
3656 drawable_height = surface->resource.height;
3657 }
3658
3659 rect->top = drawable_height - rect->top;
3660 rect->bottom = drawable_height - rect->bottom;
3661 }
3662
3663 /* Context activation is done by the caller. */
3664 static void surface_blt_to_drawable(const struct wined3d_device *device,
3665 struct wined3d_context *old_ctx,
3666 enum wined3d_texture_filter_type filter, BOOL alpha_test,
3667 struct wined3d_surface *src_surface, const RECT *src_rect_in,
3668 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
3669 {
3670 const struct wined3d_gl_info *gl_info;
3671 struct wined3d_context *context = old_ctx;
3672 struct wined3d_surface *restore_rt = NULL;
3673 RECT src_rect, dst_rect;
3674
3675 src_rect = *src_rect_in;
3676 dst_rect = *dst_rect_in;
3677
3678
3679 if (old_ctx->current_rt != dst_surface)
3680 {
3681 restore_rt = old_ctx->current_rt;
3682 context = context_acquire(device, dst_surface);
3683 }
3684
3685 gl_info = context->gl_info;
3686
3687 #if defined(STAGING_CSMT)
3688 /* Make sure the surface is up-to-date. This should probably use
3689 * wined3d_resource_load_location() and worry about the destination
3690 * surface too, unless we're overwriting it completely. */
3691 #else /* STAGING_CSMT */
3692 /* Make sure the surface is up-to-date. This should probably use
3693 * surface_load_location() and worry about the destination surface too,
3694 * unless we're overwriting it completely. */
3695 #endif /* STAGING_CSMT */
3696 wined3d_texture_load(src_surface->container, context, FALSE);
3697
3698 /* Activate the destination context, set it up for blitting */
3699 context_apply_blit_state(context, device);
3700
3701 if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
3702 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
3703
3704 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
3705
3706 if (alpha_test)
3707 {
3708 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
3709 checkGLcall("glEnable(GL_ALPHA_TEST)");
3710
3711 /* For P8 surfaces, the alpha component contains the palette index.
3712 * Which means that the colorkey is one of the palette entries. In
3713 * other cases pixels that should be masked away have alpha set to 0. */
3714 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT)
3715 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
3716 (float)src_surface->container->async.src_blt_color_key.color_space_low_value / 255.0f);
3717 else
3718 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
3719 checkGLcall("glAlphaFunc");
3720 }
3721 else
3722 {
3723 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
3724 checkGLcall("glDisable(GL_ALPHA_TEST)");
3725 }
3726
3727 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
3728
3729 if (alpha_test)
3730 {
3731 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
3732 checkGLcall("glDisable(GL_ALPHA_TEST)");
3733 }
3734
3735 /* Leave the opengl state valid for blitting */
3736 device->blitter->unset_shader(context->gl_info);
3737
3738 #if defined(STAGING_CSMT)
3739 if (wined3d_settings.cs_multithreaded)
3740 gl_info->gl_ops.gl.p_glFinish();
3741 else if (wined3d_settings.strict_draw_ordering
3742 #else /* STAGING_CSMT */
3743 if (wined3d_settings.strict_draw_ordering
3744 #endif /* STAGING_CSMT */
3745 || (dst_surface->container->swapchain
3746 && dst_surface->container->swapchain->front_buffer == dst_surface->container))
3747 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
3748
3749 if (restore_rt)
3750 context_restore(context, restore_rt);
3751 }
3752
3753 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
3754 {
3755 struct wined3d_resource *resource = &s->container->resource;
3756 struct wined3d_device *device = resource->device;
3757 #if defined(STAGING_CSMT)
3758 struct wined3d_rendertarget_view view;
3759 struct wined3d_texture *texture = s->container;
3760 #else /* STAGING_CSMT */
3761 struct wined3d_rendertarget_view_desc view_desc;
3762 struct wined3d_rendertarget_view *view;
3763 #endif /* STAGING_CSMT */
3764 const struct blit_shader *blitter;
3765 HRESULT hr;
3766
3767 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
3768 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
3769 {
3770 FIXME("No blitter is capable of performing the requested color fill operation.\n");
3771 return WINED3DERR_INVALIDCALL;
3772 }
3773
3774 #if defined(STAGING_CSMT)
3775 /* Can't incref / decref the resource here. This is executed inside the worker
3776 * thread. Playing with the refcount here makes the worker thread visible to
3777 * the client lib. Problems occur when the worker thread happens to hold the
3778 * last reference and the resource destruction callbacks are called from the
3779 * wrong thread. */
3780 view.resource = &texture->resource;
3781 view.parent = NULL;
3782 view.parent_ops = &wined3d_null_parent_ops;
3783 view.format = s->resource.format;
3784 view.buffer_offset = 0;
3785 view.width = s->resource.width;
3786 view.height = s->resource.height;
3787 view.depth = 1;
3788 view.sub_resource_idx = s->texture_layer * texture->level_count + s->texture_level;
3789
3790 hr = blitter->color_fill(device, &view, rect, color);
3791 #else /* STAGING_CSMT */
3792 view_desc.format_id = resource->format->id;
3793 view_desc.u.texture.level_idx = s->texture_level;
3794 view_desc.u.texture.layer_idx = s->texture_layer;
3795 view_desc.u.texture.layer_count = 1;
3796 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
3797 resource, NULL, &wined3d_null_parent_ops, &view)))
3798 {
3799 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
3800 return hr;
3801 }
3802
3803 hr = blitter->color_fill(device, view, rect, color);
3804 wined3d_rendertarget_view_decref(view);
3805 #endif /* STAGING_CSMT */
3806
3807 return hr;
3808 }
3809
3810 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
3811 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
3812 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
3813 {
3814 struct wined3d_device *device = dst_surface->resource.device;
3815 #if defined(STAGING_CSMT)
3816 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
3817 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->state.fb.render_targets[0]);
3818 #else /* STAGING_CSMT */
3819 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
3820 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
3821 #endif /* STAGING_CSMT */
3822
3823 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
3824 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
3825 flags, fx, debug_d3dtexturefiltertype(filter));
3826
3827 /* Get the swapchain. One of the surfaces has to be a primary surface */
3828 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
3829 {
3830 WARN("Destination is in sysmem, rejecting gl blt\n");
3831 return WINED3DERR_INVALIDCALL;
3832 }
3833
3834 dst_swapchain = dst_surface->container->swapchain;
3835
3836 if (src_surface)
3837 {
3838 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
3839 {
3840 WARN("Src is in sysmem, rejecting gl blt\n");
3841 return WINED3DERR_INVALIDCALL;
3842 }
3843
3844 src_swapchain = src_surface->container->swapchain;
3845 }
3846 else
3847 {
3848 src_swapchain = NULL;
3849 }
3850
3851 /* Early sort out of cases where no render target is used */
3852 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
3853 {
3854 TRACE("No surface is render target, not using hardware blit.\n");
3855 return WINED3DERR_INVALIDCALL;
3856 }
3857
3858 /* No destination color keying supported */
3859 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
3860 {
3861 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3862 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3863 return WINED3DERR_INVALIDCALL;
3864 }
3865
3866 if (dst_swapchain && dst_swapchain == src_swapchain)
3867 {
3868 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3869 return WINED3DERR_INVALIDCALL;
3870 }
3871
3872 if (dst_swapchain && src_swapchain)
3873 {
3874 FIXME("Implement hardware blit between two different swapchains\n");
3875 return WINED3DERR_INVALIDCALL;
3876 }
3877
3878 if (dst_swapchain)
3879 {
3880 /* Handled with regular texture -> swapchain blit */
3881 if (src_surface == rt)
3882 TRACE("Blit from active render target to a swapchain\n");
3883 }
3884 else if (src_swapchain && dst_surface == rt)
3885 {
3886 FIXME("Implement blit from a swapchain to the active render target\n");
3887 return WINED3DERR_INVALIDCALL;
3888 }
3889
3890 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
3891 {
3892 /* Blit from render target to texture */
3893 BOOL stretchx;
3894
3895 /* P8 read back is not implemented */
3896 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
3897 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
3898 {
3899 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3900 return WINED3DERR_INVALIDCALL;
3901 }
3902
3903 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
3904 {
3905 TRACE("Color keying not supported by frame buffer to texture blit\n");
3906 return WINED3DERR_INVALIDCALL;
3907 /* Destination color key is checked above */
3908 }
3909
3910 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
3911 stretchx = TRUE;
3912 else
3913 stretchx = FALSE;
3914
3915 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3916 * flip the image nor scale it.
3917 *
3918 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3919 * -> If the app wants an image width an unscaled width, copy it line per line
3920 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
3921 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3922 * back buffer. This is slower than reading line per line, thus not used for flipping
3923 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3924 * pixel by pixel. */
3925 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
3926 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
3927 {
3928 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
3929 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
3930 }
3931 else
3932 {
3933 TRACE("Using hardware stretching to flip / stretch the texture.\n");
3934 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
3935 }
3936
3937 surface_evict_sysmem(dst_surface);
3938
3939 return WINED3D_OK;
3940 }
3941
3942 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3943 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3944 return WINED3DERR_INVALIDCALL;
3945 }
3946
3947 /* Context activation is done by the caller. */
3948 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
3949 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
3950 {
3951 struct wined3d_device *device = surface->resource.device;
3952 const struct wined3d_gl_info *gl_info = context->gl_info;
3953 GLint compare_mode = GL_NONE;
3954 struct blt_info info;
3955 GLint old_binding = 0;
3956 RECT rect;
3957
3958 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
3959
3960 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
3961 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
3962 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
3963 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
3964 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
3965 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
3966 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
3967 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
3968 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
3969 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
3970 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
3971
3972 SetRect(&rect, 0, h, w, 0);
3973 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
3974 context_active_texture(context, context->gl_info, 0);
3975 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
3976 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
3977 if (gl_info->supported[ARB_SHADOW])
3978 {
3979 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
3980 if (compare_mode != GL_NONE)
3981 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
3982 }
3983
3984 device->shader_backend->shader_select_depth_blt(device->shader_priv,
3985 gl_info, info.tex_type, &surface->ds_current_size);
3986
3987 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
3988 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
3989 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
3990 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
3991 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
3992 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
3993 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
3994 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
3995 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
3996 gl_info->gl_ops.gl.p_glEnd();
3997
3998 if (compare_mode != GL_NONE)
3999 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
4000 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
4001
4002 gl_info->gl_ops.gl.p_glPopAttrib();
4003
4004 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
4005 }
4006
4007 void surface_modify_ds_location(struct wined3d_surface *surface,
4008 DWORD location, UINT w, UINT h)
4009 {
4010 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
4011
4012 #if defined(STAGING_CSMT)
4013 if (((surface->resource.locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
4014 || (!(surface->resource.locations & WINED3D_LOCATION_TEXTURE_RGB)
4015 && (location & WINED3D_LOCATION_TEXTURE_RGB)))
4016 wined3d_texture_set_dirty(surface->container);
4017
4018 surface->ds_current_size.cx = w;
4019 surface->ds_current_size.cy = h;
4020 surface->resource.locations = location;
4021 #else /* STAGING_CSMT */
4022 if (((surface->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
4023 || (!(surface->locations & WINED3D_LOCATION_TEXTURE_RGB) && (location & WINED3D_LOCATION_TEXTURE_RGB)))
4024 wined3d_texture_set_dirty(surface->container);
4025
4026 surface->ds_current_size.cx = w;
4027 surface->ds_current_size.cy = h;
4028 surface->locations = location;
4029 #endif /* STAGING_CSMT */
4030 }
4031
4032 /* Context activation is done by the caller. */
4033 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4034 {
4035 const struct wined3d_gl_info *gl_info = context->gl_info;
4036 struct wined3d_device *device = surface->resource.device;
4037 GLsizei w, h;
4038
4039 TRACE("surface %p, context %p, new location %#x.\n", surface, context, location);
4040
4041 /* TODO: Make this work for modes other than FBO */
4042 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
4043
4044 #if defined(STAGING_CSMT)
4045 if (!(surface->resource.locations & location))
4046 #else /* STAGING_CSMT */
4047 if (!(surface->locations & location))
4048 #endif /* STAGING_CSMT */
4049 {
4050 w = surface->ds_current_size.cx;
4051 h = surface->ds_current_size.cy;
4052 surface->ds_current_size.cx = 0;
4053 surface->ds_current_size.cy = 0;
4054 }
4055 else
4056 {
4057 w = surface->resource.width;
4058 h = surface->resource.height;
4059 }
4060
4061 if (surface->ds_current_size.cx == surface->resource.width
4062 && surface->ds_current_size.cy == surface->resource.height)
4063 {
4064 TRACE("Location (%#x) is already up to date.\n", location);
4065 return;
4066 }
4067
4068 if (surface->current_renderbuffer)
4069 {
4070 FIXME("Not supported with fixed up depth stencil.\n");
4071 return;
4072 }
4073
4074 wined3d_surface_prepare(surface, context, location);
4075 #if defined(STAGING_CSMT)
4076 if (surface->resource.locations & WINED3D_LOCATION_DISCARDED)
4077 {
4078 TRACE("Surface was discarded, no need copy data.\n");
4079 surface->resource.locations &= ~WINED3D_LOCATION_DISCARDED;
4080 surface->resource.locations |= location;
4081 surface->ds_current_size.cx = surface->resource.width;
4082 surface->ds_current_size.cy = surface->resource.height;
4083 return;
4084 }
4085
4086 if (!surface->resource.locations)
4087 {
4088 FIXME("No up to date depth stencil location.\n");
4089 surface->resource.locations |= location;
4090 #else /* STAGING_CSMT */
4091 if (surface->locations & WINED3D_LOCATION_DISCARDED)
4092 {
4093 TRACE("Surface was discarded, no need copy data.\n");
4094 surface->locations &= ~WINED3D_LOCATION_DISCARDED;
4095 surface->locations |= location;
4096 surface->ds_current_size.cx = surface->resource.width;
4097 surface->ds_current_size.cy = surface->resource.height;
4098 return;
4099 }
4100
4101 if (!surface->locations)
4102 {
4103 FIXME("No up to date depth stencil location.\n");
4104 surface->locations |= location;
4105 #endif /* STAGING_CSMT */
4106 surface->ds_current_size.cx = surface->resource.width;
4107 surface->ds_current_size.cy = surface->resource.height;
4108 return;
4109 }
4110
4111 if (location == WINED3D_LOCATION_TEXTURE_RGB)
4112 {
4113 GLint old_binding = 0;
4114 GLenum bind_target;
4115
4116 /* The render target is allowed to be smaller than the depth/stencil
4117 * buffer, so the onscreen depth/stencil buffer is potentially smaller
4118 * than the offscreen surface. Don't overwrite the offscreen surface
4119 * with undefined data. */
4120 w = min(w, context->swapchain->desc.backbuffer_width);
4121 h = min(h, context->swapchain->desc.backbuffer_height);
4122
4123 TRACE("Copying onscreen depth buffer to depth texture.\n");
4124
4125 if (!device->depth_blt_texture)
4126 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
4127
4128 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4129 * directly on the FBO texture. That's because we need to flip. */
4130 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
4131 surface_from_resource(wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)),
4132 NULL, WINED3D_LOCATION_DRAWABLE);
4133 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
4134 {
4135 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
4136 bind_target = GL_TEXTURE_RECTANGLE_ARB;
4137 }
4138 else
4139 {
4140 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
4141 bind_target = GL_TEXTURE_2D;
4142 }
4143 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
4144 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
4145 * internal format, because the internal format might include stencil
4146 * data. In principle we should copy stencil data as well, but unless
4147 * the driver supports stencil export it's hard to do, and doesn't
4148 * seem to be needed in practice. If the hardware doesn't support
4149 * writing stencil data, the glCopyTexImage2D() call might trigger
4150 * software fallbacks. */
4151 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
4152 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4153 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4154 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4155 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4156 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
4157 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
4158
4159 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
4160 NULL, surface, WINED3D_LOCATION_TEXTURE_RGB);
4161 context_set_draw_buffer(context, GL_NONE);
4162
4163 /* Do the actual blit */
4164 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
4165 checkGLcall("depth_blt");
4166
4167 context_invalidate_state(context, STATE_FRAMEBUFFER);
4168
4169 #if defined(STAGING_CSMT)
4170 if (wined3d_settings.cs_multithreaded)
4171 gl_info->gl_ops.gl.p_glFinish();
4172 else if (wined3d_settings.strict_draw_ordering)
4173 #else /* STAGING_CSMT */
4174 if (wined3d_settings.strict_draw_ordering)
4175 #endif /* STAGING_CSMT */
4176 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
4177 }
4178 else if (location == WINED3D_LOCATION_DRAWABLE)
4179 {
4180 TRACE("Copying depth texture to onscreen depth buffer.\n");
4181
4182 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
4183 surface_from_resource(wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)),
4184 NULL, WINED3D_LOCATION_DRAWABLE);
4185 surface_depth_blt(surface, context, surface->container->texture_rgb.name,
4186 0, surface->pow2Height - h, w, h, surface->texture_target);
4187 checkGLcall("depth_blt");
4188
4189 context_invalidate_state(context, STATE_FRAMEBUFFER);
4190
4191 #if defined(STAGING_CSMT)
4192 if (wined3d_settings.cs_multithreaded)
4193 gl_info->gl_ops.gl.p_glFinish();
4194 else if (wined3d_settings.strict_draw_ordering)
4195 #else /* STAGING_CSMT */
4196 if (wined3d_settings.strict_draw_ordering)
4197 #endif /* STAGING_CSMT */
4198 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
4199 }
4200 else
4201 {
4202 ERR("Invalid location (%#x) specified.\n", location);
4203 }
4204
4205 #if defined(STAGING_CSMT)
4206 surface->resource.locations |= location;
4207 surface->ds_current_size.cx = surface->resource.width;
4208 surface->ds_current_size.cy = surface->resource.height;
4209 }
4210
4211 /* Context activation is done by the caller. */
4212 static void surface_load_sysmem(struct wined3d_surface *surface,
4213 struct wined3d_context *context, DWORD dst_location)
4214 {
4215 const struct wined3d_gl_info *gl_info = context->gl_info;
4216
4217 if (surface->resource.locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
4218 wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
4219
4220 /* Download the surface to system memory. */
4221 if (surface->resource.locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
4222 {
4223 wined3d_texture_bind_and_dirtify(surface->container, context,
4224 !(surface->resource.locations & WINED3D_LOCATION_TEXTURE_RGB));
4225 surface_download_data(surface, gl_info, dst_location);
4226
4227 return;
4228 }
4229
4230 if (surface->resource.locations & WINED3D_LOCATION_DRAWABLE)
4231 {
4232 read_from_framebuffer(surface, context, dst_location);
4233 return;
4234 }
4235
4236 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4237 surface, wined3d_debug_location(surface->resource.locations));
4238 #else /* STAGING_CSMT */
4239 surface->locations |= location;
4240 surface->ds_current_size.cx = surface->resource.width;
4241 surface->ds_current_size.cy = surface->resource.height;
4242 }
4243
4244 void surface_validate_location(struct wined3d_surface *surface, DWORD location)
4245 {
4246 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
4247
4248 surface->locations |= location;
4249 }
4250
4251 void surface_invalidate_location(struct wined3d_surface *surface, DWORD location)
4252 {
4253 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
4254
4255 if (location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
4256 wined3d_texture_set_dirty(surface->container);
4257 surface->locations &= ~location;
4258
4259 if (!surface->locations)
4260 ERR("Surface %p does not have any up to date location.\n", surface);
4261 }
4262
4263 static DWORD resource_access_from_location(DWORD location)
4264 {
4265 switch (location)
4266 {
4267 case WINED3D_LOCATION_SYSMEM:
4268 case WINED3D_LOCATION_USER_MEMORY:
4269 case WINED3D_LOCATION_DIB:
4270 case WINED3D_LOCATION_BUFFER:
4271 return WINED3D_RESOURCE_ACCESS_CPU;
4272
4273 case WINED3D_LOCATION_DRAWABLE:
4274 case WINED3D_LOCATION_TEXTURE_SRGB:
4275 case WINED3D_LOCATION_TEXTURE_RGB:
4276 case WINED3D_LOCATION_RB_MULTISAMPLE:
4277 case WINED3D_LOCATION_RB_RESOLVED:
4278 return WINED3D_RESOURCE_ACCESS_GPU;
4279
4280 default:
4281 FIXME("Unhandled location %#x.\n", location);
4282 return 0;
4283 }
4284 }
4285
4286 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
4287 {
4288 struct wined3d_device *device = surface->resource.device;
4289 struct wined3d_context *context;
4290 const struct wined3d_gl_info *gl_info;
4291 struct wined3d_bo_address dst, src;
4292 UINT size = surface->resource.size;
4293
4294 surface_get_memory(surface, &dst, location);
4295 surface_get_memory(surface, &src, surface->locations);
4296
4297 if (dst.buffer_object)
4298 {
4299 context = context_acquire(device, NULL);
4300 gl_info = context->gl_info;
4301 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
4302 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
4303 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
4304 checkGLcall("Upload PBO");
4305 context_release(context);
4306 return;
4307 }
4308 if (src.buffer_object)
4309 {
4310 context = context_acquire(device, NULL);
4311 gl_info = context->gl_info;
4312 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
4313 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
4314 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
4315 checkGLcall("Download PBO");
4316 context_release(context);
4317 return;
4318 }
4319 memcpy(dst.addr, src.addr, size);
4320 }
4321
4322 /* Context activation is done by the caller. */
4323 static void surface_load_sysmem(struct wined3d_surface *surface,
4324 struct wined3d_context *context, DWORD dst_location)
4325 {
4326 const struct wined3d_gl_info *gl_info = context->gl_info;
4327
4328 if (surface->locations & surface_simple_locations)
4329 {
4330 surface_copy_simple_location(surface, dst_location);
4331 return;
4332 }
4333
4334 if (surface->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
4335 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
4336
4337 /* Download the surface to system memory. */
4338 if (surface->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
4339 {
4340 wined3d_texture_bind_and_dirtify(surface->container, context,
4341 !(surface->locations & WINED3D_LOCATION_TEXTURE_RGB));
4342 surface_download_data(surface, gl_info, dst_location);
4343
4344 return;
4345 }
4346
4347 if (surface->locations & WINED3D_LOCATION_DRAWABLE)
4348 {
4349 read_from_framebuffer(surface, context, dst_location);
4350 return;
4351 }
4352
4353 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4354 surface, wined3d_debug_location(surface->locations));
4355 #endif /* STAGING_CSMT */
4356 }
4357
4358 /* Context activation is done by the caller. */
4359 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
4360 struct wined3d_context *context)
4361 {
4362 RECT r;
4363
4364 #if defined(STAGING_CSMT)
4365 if (surface->resource.locations & WINED3D_LOCATION_DISCARDED)
4366 {
4367 TRACE("Surface was discarded, nothing to do.\n");
4368 return WINED3D_OK;
4369 }
4370
4371 #endif /* STAGING_CSMT */
4372 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
4373 && wined3d_resource_is_offscreen(&surface->container->resource))
4374 {
4375 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4376 return WINED3DERR_INVALIDCALL;
4377 }
4378
4379 surface_get_rect(surface, NULL, &r);
4380 #if defined(STAGING_CSMT)
4381 wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
4382 #else /* STAGING_CSMT */
4383 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
4384 #endif /* STAGING_CSMT */
4385 surface_blt_to_drawable(surface->resource.device, context,
4386 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
4387
4388 return WINED3D_OK;
4389 }
4390
4391 static HRESULT surface_load_texture(struct wined3d_surface *surface,
4392 struct wined3d_context *context, BOOL srgb)
4393 {
4394 #if defined(STAGING_CSMT)
4395 unsigned int width, src_row_pitch, src_slice_pitch, dst_pitch;
4396 #else /* STAGING_CSMT */
4397 unsigned int width, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
4398 #endif /* STAGING_CSMT */
4399 const RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
4400 const struct wined3d_gl_info *gl_info = context->gl_info;
4401 struct wined3d_device *device = surface->resource.device;
4402 const struct wined3d_color_key_conversion *conversion;
4403 struct wined3d_texture *texture = surface->container;
4404 struct wined3d_bo_address data;
4405 struct wined3d_format format;
4406 POINT dst_point = {0, 0};
4407 BYTE *mem = NULL;
4408 #if defined(STAGING_CSMT)
4409 const DWORD simple_locations =
4410 WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_USER_MEMORY
4411 | WINED3D_LOCATION_DIB | WINED3D_LOCATION_BUFFER;
4412
4413 if (surface->resource.locations & WINED3D_LOCATION_DISCARDED)
4414 {
4415 TRACE("Surface was discarded, nothing to do.\n");
4416 wined3d_texture_prepare_texture(texture, context, srgb);
4417 return WINED3D_OK;
4418 }
4419
4420 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
4421 && wined3d_resource_is_offscreen(&texture->resource)
4422 && (surface->resource.locations & WINED3D_LOCATION_DRAWABLE))
4423 {
4424 surface_load_fb_texture(surface, srgb, context);
4425
4426 return WINED3D_OK;
4427 }
4428
4429 if (surface->resource.locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
4430 #else /* STAGING_CSMT */
4431
4432 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
4433 && wined3d_resource_is_offscreen(&texture->resource)
4434 && (surface->locations & WINED3D_LOCATION_DRAWABLE))
4435 {
4436 surface_load_fb_texture(surface, srgb, context);
4437
4438 return WINED3D_OK;
4439 }
4440
4441 if (surface->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
4442 #endif /* STAGING_CSMT */
4443 && (surface->container->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
4444 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4445 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
4446 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
4447 {
4448 if (srgb)
4449 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
4450 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
4451 else
4452 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
4453 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
4454
4455 return WINED3D_OK;
4456 }
4457
4458 #if defined(STAGING_CSMT)
4459 if (surface->resource.locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
4460 && (!srgb || (surface->container->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
4461 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4462 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
4463 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
4464 {
4465 DWORD src_location = surface->resource.locations & WINED3D_LOCATION_RB_RESOLVED ?
4466 #else /* STAGING_CSMT */
4467 if (surface->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
4468 && (!srgb || (surface->container->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
4469 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4470 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
4471 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
4472 {
4473 DWORD src_location = surface->locations & WINED3D_LOCATION_RB_RESOLVED ?
4474 #endif /* STAGING_CSMT */
4475 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
4476 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
4477 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
4478
4479 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
4480 &rect, surface, dst_location, &rect);
4481
4482 return WINED3D_OK;
4483 }
4484
4485 /* Upload from system memory */
4486
4487 if (srgb)
4488 {
4489 #if defined(STAGING_CSMT)
4490 if ((surface->resource.locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
4491 == WINED3D_LOCATION_TEXTURE_RGB)
4492 {
4493 /* Performance warning... */
4494 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
4495 wined3d_resource_prepare_map_memory(&surface->resource, context);
4496 wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
4497 }
4498 }
4499 else
4500 {
4501 if ((surface->resource.locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
4502 == WINED3D_LOCATION_TEXTURE_SRGB)
4503 {
4504 /* Performance warning... */
4505 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
4506 wined3d_resource_prepare_map_memory(&surface->resource, context);
4507 wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
4508 }
4509 }
4510
4511 if (!(surface->resource.locations & simple_locations))
4512 {
4513 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4514 /* Lets hope we get it from somewhere... */
4515 wined3d_resource_prepare_system_memory(&surface->resource);
4516 wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_SYSMEM);
4517 }
4518
4519 wined3d_texture_prepare_texture(texture, context, srgb);
4520 wined3d_texture_bind_and_dirtify(texture, context, srgb);
4521 wined3d_resource_get_pitch(&surface->resource, &src_row_pitch, &src_slice_pitch);
4522 #else /* STAGING_CSMT */
4523 if ((surface->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
4524 == WINED3D_LOCATION_TEXTURE_RGB)
4525 {
4526 /* Performance warning... */
4527 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
4528 surface_prepare_map_memory(surface);
4529 surface_load_location(surface, context, surface->resource.map_binding);
4530 }
4531 }
4532 else
4533 {
4534 if ((surface->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
4535 == WINED3D_LOCATION_TEXTURE_SRGB)
4536 {
4537 /* Performance warning... */
4538 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
4539 surface_prepare_map_memory(surface);
4540 surface_load_location(surface, context, surface->resource.map_binding);
4541 }
4542 }
4543
4544 if (!(surface->locations & surface_simple_locations))
4545 {
4546 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4547 /* Lets hope we get it from somewhere... */
4548 surface_prepare_system_memory(surface);
4549 surface_load_location(surface, context, WINED3D_LOCATION_SYSMEM);
4550 }
4551
4552 wined3d_texture_prepare_texture(texture, context, srgb);
4553 wined3d_texture_bind_and_dirtify(texture, context, srgb);
4554 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
4555 #endif /* STAGING_CSMT */
4556
4557 width = surface->resource.width;
4558
4559 format = *texture->resource.format;
4560 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
4561 format = *wined3d_get_format(gl_info, conversion->dst_format);
4562
4563 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4564 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
4565 * getting called. */
4566 #if defined(STAGING_CSMT)
4567 if ((format.convert || conversion) && surface->resource.buffer)
4568 #else /* STAGING_CSMT */
4569 if ((format.convert || conversion) && surface->pbo)
4570 #endif /* STAGING_CSMT */
4571 {
4572 TRACE("Removing the pbo attached to surface %p.\n", surface);
4573
4574 if (surface->flags & SFLAG_DIBSECTION)
4575 surface->resource.map_binding = WINED3D_LOCATION_DIB;
4576 else
4577 surface->resource.map_binding = WINED3D_LOCATION_SYSMEM;
4578
4579 #if defined(STAGING_CSMT)
4580 wined3d_resource_prepare_map_memory(&surface->resource, context);
4581 wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
4582 wined3d_resource_free_bo(&surface->resource);
4583 wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_BUFFER);
4584 }
4585
4586 wined3d_resource_get_memory(&surface->resource, surface->resource.locations, &data);
4587 if (format.convert)
4588 {
4589 /* This code is entered for texture formats which need a fixup. */
4590 UINT height = surface->resource.height;
4591
4592 format.byte_count = format.conv_byte_count;
4593 dst_pitch = wined3d_format_calculate_pitch(&format, width);
4594
4595 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
4596 {
4597 ERR("Out of memory (%u).\n", dst_pitch * height);
4598 context_release(context);
4599 return E_OUTOFMEMORY;
4600 }
4601 format.convert(data.addr, mem, src_row_pitch, src_slice_pitch,
4602 dst_pitch, dst_pitch * height, width, height, 1);
4603 src_row_pitch = dst_pitch;
4604 #else /* STAGING_CSMT */
4605 surface_prepare_map_memory(surface);
4606 surface_load_location(surface, context, surface->resource.map_binding);
4607 surface_remove_pbo(surface, gl_info);
4608 }
4609
4610 surface_get_memory(surface, &data, surface->locations);
4611 if (format.convert)
4612 {
4613 /* This code is entered for texture formats which need a fixup. */
4614 UINT height = surface->resource.height;
4615
4616 format.byte_count = format.conv_byte_count;
4617 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
4618
4619 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
4620 {
4621 ERR("Out of memory (%u).\n", dst_slice_pitch);
4622 context_release(context);
4623 return E_OUTOFMEMORY;
4624 }
4625 format.convert(data.addr, mem, src_row_pitch, src_slice_pitch,
4626 dst_row_pitch, dst_slice_pitch, width, height, 1);
4627 src_row_pitch = dst_row_pitch;
4628 #endif /* STAGING_CSMT */
4629 data.addr = mem;
4630 }
4631 else if (conversion)
4632 {
4633 /* This code is only entered for color keying fixups */
4634 struct wined3d_palette *palette = NULL;
4635 UINT height = surface->resource.height;
4636
4637 #if defined(STAGING_CSMT)
4638 dst_pitch = wined3d_format_calculate_pitch(&format, width);
4639 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4640
4641 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
4642 {
4643 ERR("Out of memory (%u).\n", dst_pitch * height);
4644 context_release(context);
4645 return E_OUTOFMEMORY;
4646 }
4647 if (texture->swapchain && texture->swapchain->palette)
4648 palette = texture->swapchain->palette;
4649 conversion->convert(data.addr, src_row_pitch, mem, dst_pitch,
4650 width, height, palette, &texture->async.gl_color_key);
4651 src_row_pitch = dst_pitch;
4652 #else /* STAGING_CSMT */
4653 wined3d_format_calculate_pitch(&format, device->surface_alignment,
4654 width, height, &dst_row_pitch, &dst_slice_pitch);
4655
4656 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
4657 {
4658 ERR("Out of memory (%u).\n", dst_slice_pitch);
4659 context_release(context);
4660 return E_OUTOFMEMORY;
4661 }
4662 if (texture->swapchain && texture->swapchain->palette)
4663 palette = texture->swapchain->palette;
4664 conversion->convert(data.addr, src_row_pitch, mem, dst_row_pitch,
4665 width, height, palette, &texture->async.gl_color_key);
4666 src_row_pitch = dst_row_pitch;
4667 #endif /* STAGING_CSMT */
4668 data.addr = mem;
4669 }
4670
4671 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
4672 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
4673
4674 HeapFree(GetProcessHeap(), 0, mem);
4675
4676 return WINED3D_OK;
4677 }
4678
4679 /* Context activation is done by the caller. */
4680 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
4681 DWORD dst_location)
4682 {
4683 const RECT rect = {0, 0, surface->resource.width, surface->resource.height};
4684 DWORD src_location;
4685
4686 #if defined(STAGING_CSMT)
4687 if (surface->resource.locations & WINED3D_LOCATION_RB_MULTISAMPLE)
4688 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
4689 else if (surface->resource.locations & WINED3D_LOCATION_RB_RESOLVED)
4690 src_location = WINED3D_LOCATION_RB_RESOLVED;
4691 else if (surface->resource.locations & WINED3D_LOCATION_TEXTURE_SRGB)
4692 #else /* STAGING_CSMT */
4693 if (surface->locations & WINED3D_LOCATION_RB_MULTISAMPLE)
4694 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
4695 else if (surface->locations & WINED3D_LOCATION_RB_RESOLVED)
4696 src_location = WINED3D_LOCATION_RB_RESOLVED;
4697 else if (surface->locations & WINED3D_LOCATION_TEXTURE_SRGB)
4698 #endif /* STAGING_CSMT */
4699 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
4700 else /* surface_blt_fbo will load the source location if necessary. */
4701 src_location = WINED3D_LOCATION_TEXTURE_RGB;
4702
4703 surface_blt_fbo(surface->resource.device, context, WINED3D_TEXF_POINT,
4704 surface, src_location, &rect, surface, dst_location, &rect);
4705 }
4706
4707 #if defined(STAGING_CSMT)
4708 /* Context activation is done by the caller. */
4709 static void wined3d_surface_load_location(struct wined3d_resource *resource,
4710 struct wined3d_context *context, DWORD location)
4711 {
4712 struct wined3d_surface *surface = surface_from_resource(resource);
4713 #else /* STAGING_CSMT */
4714 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
4715 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4716 {
4717 #endif /* STAGING_CSMT */
4718 HRESULT hr;
4719
4720 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
4721
4722 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4723 {
4724 if (location == WINED3D_LOCATION_TEXTURE_RGB
4725 #if defined(STAGING_CSMT)
4726 && surface->resource.locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_DISCARDED))
4727 {
4728 surface_load_ds_location(surface, context, location);
4729 return;
4730 }
4731 else if (location & surface->resource.locations
4732 && surface->container->resource.draw_binding != WINED3D_LOCATION_DRAWABLE)
4733 {
4734 /* Already up to date, nothing to do. */
4735 return;
4736 }
4737 else
4738 {
4739 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4740 wined3d_debug_location(surface->resource.locations), wined3d_debug_location(location));
4741 return;
4742 }
4743 }
4744
4745 if (!surface->resource.locations)
4746 {
4747 ERR("Surface %p does not have any up to date location.\n", surface);
4748 return;
4749 #else /* STAGING_CSMT */
4750 && surface->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_DISCARDED))
4751 {
4752 surface_load_ds_location(surface, context, location);
4753 return WINED3D_OK;
4754 }
4755 else if (location & surface->locations
4756 && surface->container->resource.draw_binding != WINED3D_LOCATION_DRAWABLE)
4757 {
4758 /* Already up to date, nothing to do. */
4759 return WINED3D_OK;
4760 }
4761 else
4762 {
4763 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4764 wined3d_debug_location(surface->locations), wined3d_debug_location(location));
4765 return WINED3DERR_INVALIDCALL;
4766 }
4767 }
4768
4769 if (surface->locations & location)
4770 {
4771 TRACE("Location already up to date.\n");
4772 return WINED3D_OK;
4773 }
4774
4775 if (WARN_ON(d3d_surface))
4776 {
4777 DWORD required_access = resource_access_from_location(location);
4778 if ((surface->resource.access_flags & required_access) != required_access)
4779 WARN("Operation requires %#x access, but surface only has %#x.\n",
4780 required_access, surface->resource.access_flags);
4781 }
4782
4783 if (!surface->locations)
4784 {
4785 ERR("Surface %p does not have any up to date location.\n", surface);
4786 return WINED3DERR_INVALIDCALL;
4787 #endif /* STAGING_CSMT */
4788 }
4789
4790 switch (location)
4791 {
4792 case WINED3D_LOCATION_DIB:
4793 case WINED3D_LOCATION_USER_MEMORY:
4794 case WINED3D_LOCATION_SYSMEM:
4795 case WINED3D_LOCATION_BUFFER:
4796 surface_load_sysmem(surface, context, location);
4797 break;
4798
4799 case WINED3D_LOCATION_DRAWABLE:
4800 if (FAILED(hr = surface_load_drawable(surface, context)))
4801 #if defined(STAGING_CSMT)
4802 return;
4803 #else /* STAGING_CSMT */
4804 return hr;
4805 #endif /* STAGING_CSMT */
4806 break;
4807
4808 case WINED3D_LOCATION_RB_RESOLVED:
4809 case WINED3D_LOCATION_RB_MULTISAMPLE:
4810 surface_load_renderbuffer(surface, context, location);
4811 break;
4812
4813 case WINED3D_LOCATION_TEXTURE_RGB:
4814 case WINED3D_LOCATION_TEXTURE_SRGB:
4815 if (FAILED(hr = surface_load_texture(surface, context,
4816 location == WINED3D_LOCATION_TEXTURE_SRGB)))
4817 #if defined(STAGING_CSMT)
4818 return;
4819 #else /* STAGING_CSMT */
4820 return hr;
4821 #endif /* STAGING_CSMT */
4822 break;
4823
4824 default:
4825 ERR("Don't know how to handle location %#x.\n", location);
4826 break;
4827 }
4828
4829 #if defined(STAGING_CSMT)
4830 wined3d_resource_validate_location(&surface->resource, location);
4831
4832 if (location != WINED3D_LOCATION_SYSMEM && (surface->resource.locations & WINED3D_LOCATION_SYSMEM))
4833 surface_evict_sysmem(surface);
4834
4835 return;
4836 #else /* STAGING_CSMT */
4837 surface_validate_location(surface, location);
4838
4839 if (location != WINED3D_LOCATION_SYSMEM && (surface->locations & WINED3D_LOCATION_SYSMEM))
4840 surface_evict_sysmem(surface);
4841
4842 return WINED3D_OK;
4843 #endif /* STAGING_CSMT */
4844 }
4845
4846 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
4847 /* Context activation is done by the caller. */
4848 static void ffp_blit_free(struct wined3d_device *device) { }
4849
4850 /* Context activation is done by the caller. */
4851 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
4852 const struct wined3d_color_key *color_key)
4853 {
4854 const struct wined3d_gl_info *gl_info = context->gl_info;
4855
4856 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
4857 checkGLcall("glEnable(target)");
4858
4859 return WINED3D_OK;
4860 }
4861
4862 /* Context activation is done by the caller. */
4863 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
4864 {
4865 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
4866 checkGLcall("glDisable(GL_TEXTURE_2D)");
4867 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
4868 {
4869 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
4870 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4871 }
4872 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
4873 {
4874 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
4875 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4876 }
4877 }
4878
4879 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
4880 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
4881 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
4882 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
4883 {
4884 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
4885 {
4886 TRACE("Source or destination is in system memory.\n");
4887 return FALSE;
4888 }
4889
4890 switch (blit_op)
4891 {
4892 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
4893 if (d3d_info->shader_color_key)
4894 {
4895 TRACE("Color keying requires converted textures.\n");
4896 return FALSE;
4897 }
4898 case WINED3D_BLIT_OP_COLOR_BLIT:
4899 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
4900 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
4901 {
4902 TRACE("Checking support for fixup:\n");
4903 dump_color_fixup_desc(src_format->color_fixup);
4904 }
4905
4906 /* We only support identity conversions. */
4907 if (!is_identity_fixup(src_format->color_fixup)
4908 || !is_identity_fixup(dst_format->color_fixup))
4909 {
4910 TRACE("Fixups are not supported.\n");
4911 return FALSE;
4912 }
4913
4914 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
4915 {
4916 TRACE("Can only blit to render targets.\n");
4917 return FALSE;
4918 }
4919 return TRUE;
4920
4921 case WINED3D_BLIT_OP_COLOR_FILL:
4922 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4923 {
4924 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
4925 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
4926 return FALSE;
4927 }
4928 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
4929 {
4930 TRACE("Color fill not supported\n");
4931 return FALSE;
4932 }
4933
4934 /* FIXME: We should reject color fills on formats with fixups,
4935 * but this would break P8 color fills for example. */
4936
4937 return TRUE;
4938
4939 case WINED3D_BLIT_OP_DEPTH_FILL:
4940 return TRUE;
4941
4942 default:
4943 TRACE("Unsupported blit_op=%d\n", blit_op);
4944 return FALSE;
4945 }
4946 }
4947
4948 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
4949 const RECT *rect, const struct wined3d_color *color)
4950 {
4951 const RECT draw_rect = {0, 0, view->width, view->height};
4952 #if defined(STAGING_CSMT)
4953 struct wined3d_fb_state fb = {&view, NULL, 1};
4954 #else /* STAGING_CSMT */
4955 struct wined3d_fb_state fb = {&view, NULL};
4956 #endif /* STAGING_CSMT */
4957
4958 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
4959
4960 return WINED3D_OK;
4961 }
4962
4963 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
4964 struct wined3d_rendertarget_view *view, const RECT *rect, float depth)
4965 {
4966 const RECT draw_rect = {0, 0, view->width, view->height};
4967 struct wined3d_fb_state fb = {NULL, view};
4968
4969 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
4970
4971 return WINED3D_OK;
4972 }
4973
4974 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
4975 struct wined3d_surface *src_surface, const RECT *src_rect,
4976 struct wined3d_surface *dst_surface, const RECT *dst_rect,
4977 const struct wined3d_color_key *color_key)
4978 {
4979 struct wined3d_context *context;
4980
4981 /* Blit from offscreen surface to render target */
4982 struct wined3d_color_key old_blt_key = src_surface->container->async.src_blt_color_key;
4983 DWORD old_color_key_flags = src_surface->container->async.color_key_flags;
4984
4985 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
4986
4987 wined3d_texture_set_color_key(src_surface->container, WINED3D_CKEY_SRC_BLT, color_key);
4988
4989 context = context_acquire(device, dst_surface);
4990
4991 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
4992 glEnable(GL_ALPHA_TEST);
4993
4994 surface_blt_to_drawable(device, context, filter,
4995 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
4996
4997 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
4998 glDisable(GL_ALPHA_TEST);
4999
5000 context_release(context);
5001
5002 /* Restore the color key parameters */
5003 wined3d_texture_set_color_key(src_surface->container, WINED3D_CKEY_SRC_BLT,
5004 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
5005
5006 #if defined(STAGING_CSMT)
5007 wined3d_resource_validate_location(&dst_surface->resource, dst_surface->container->resource.draw_binding);
5008 wined3d_resource_invalidate_location(&dst_surface->resource, ~dst_surface->container->resource.draw_binding);
5009 #else /* STAGING_CSMT */
5010 surface_validate_location(dst_surface, dst_surface->container->resource.draw_binding);
5011 surface_invalidate_location(dst_surface, ~dst_surface->container->resource.draw_binding);
5012 #endif /* STAGING_CSMT */
5013 }
5014
5015 const struct blit_shader ffp_blit = {
5016 ffp_blit_alloc,
5017 ffp_blit_free,
5018 ffp_blit_set,
5019 ffp_blit_unset,
5020 ffp_blit_supported,
5021 ffp_blit_color_fill,
5022 ffp_blit_depth_fill,
5023 ffp_blit_blit_surface,
5024 };
5025
5026 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
5027 {
5028 return WINED3D_OK;
5029 }
5030
5031 /* Context activation is done by the caller. */
5032 static void cpu_blit_free(struct wined3d_device *device)
5033 {
5034 }
5035
5036 /* Context activation is done by the caller. */
5037 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
5038 const struct wined3d_color_key *color_key)
5039 {
5040 return WINED3D_OK;
5041 }
5042
5043 /* Context activation is done by the caller. */
5044 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
5045 {
5046 }
5047
5048 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
5049 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
5050 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
5051 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
5052 {
5053 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
5054 {
5055 return TRUE;
5056 }
5057
5058 return FALSE;
5059 }
5060
5061 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
5062 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
5063 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
5064 {
5065 UINT row_block_count;
5066 const BYTE *src_row;
5067 BYTE *dst_row;
5068 UINT x, y;
5069
5070 src_row = src_data;
5071 dst_row = dst_data;
5072
5073 row_block_count = (update_w + format->block_width - 1) / format->block_width;
5074
5075 if (!flags)
5076 {
5077 for (y = 0; y < update_h; y += format->block_height)
5078 {
5079 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
5080 src_row += src_pitch;
5081 dst_row += dst_pitch;
5082 }
5083
5084 return WINED3D_OK;
5085 }
5086
5087 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
5088 {
5089 src_row += (((update_h / format->block_height) - 1) * src_pitch);
5090
5091 switch (format->id)
5092 {
5093 case WINED3DFMT_DXT1:
5094 for (y = 0; y < update_h; y += format->block_height)
5095 {
5096 struct block
5097 {
5098 WORD color[2];
5099 BYTE control_row[4];
5100 };
5101
5102 const struct block *s = (const struct block *)src_row;
5103 struct block *d = (struct block *)dst_row;
5104
5105 for (x = 0; x < row_block_count; ++x)
5106 {
5107 d[x].color[0] = s[x].color[0];
5108 d[x].color[1] = s[x].color[1];
5109 d[x].control_row[0] = s[x].control_row[3];
5110 d[x].control_row[1] = s[x].control_row[2];
5111 d[x].control_row[2] = s[x].control_row[1];
5112 d[x].control_row[3] = s[x].control_row[0];
5113 }
5114 src_row -= src_pitch;
5115 dst_row += dst_pitch;
5116 }
5117 return WINED3D_OK;
5118
5119 case WINED3DFMT_DXT2:
5120 case WINED3DFMT_DXT3:
5121 for (y = 0; y < update_h; y += format->block_height)
5122 {
5123 struct block
5124 {
5125 WORD alpha_row[4];
5126 WORD color[2];
5127 BYTE control_row[4];
5128 };
5129
5130 const struct block *s = (const struct block *)src_row;
5131 struct block *d = (struct block *)dst_row;
5132
5133 for (x = 0; x < row_block_count; ++x)
5134 {
5135 d[x].alpha_row[0] = s[x].alpha_row[3];
5136 d[x].alpha_row[1] = s[x].alpha_row[2];
5137 d[x].alpha_row[2] = s[x].alpha_row[1];
5138 d[x].alpha_row[3] = s[x].alpha_row[0];
5139 d[x].color[0] = s[x].color[0];
5140 d[x].color[1] = s[x].color[1];
5141 d[x].control_row[0] = s[x].control_row[3];
5142 d[x].control_row[1] = s[x].control_row[2];
5143 d[x].control_row[2] = s[x].control_row[1];
5144 d[x].control_row[3] = s[x].control_row[0];
5145 }
5146 src_row -= src_pitch;
5147 dst_row += dst_pitch;
5148 }
5149 return WINED3D_OK;
5150
5151 default:
5152 FIXME("Compressed flip not implemented for format %s.\n",
5153 debug_d3dformat(format->id));
5154 return E_NOTIMPL;
5155 }
5156 }
5157
5158 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
5159 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
5160
5161 return E_NOTIMPL;
5162 }
5163
5164 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5165 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
5166 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
5167 {
5168 #if defined(STAGING_CSMT)
5169 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
5170 const struct wined3d_format *src_format, *dst_format;
5171 unsigned int src_fmt_flags, dst_fmt_flags;
5172 struct wined3d_texture *src_texture = NULL;
5173 void *src_data = NULL, *dst_data = NULL;
5174 UINT src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
5175 const BYTE *sbase = NULL;
5176 HRESULT hr = WINED3D_OK;
5177 const BYTE *sbuf;
5178 BYTE *dbuf;
5179 int x, y;
5180 struct wined3d_device *device = dst_surface->resource.device;
5181 struct wined3d_context *context = NULL;
5182
5183 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5184 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5185 flags, fx, debug_d3dtexturefiltertype(filter));
5186
5187 if (device->d3d_initialized)
5188 context = context_acquire(device, NULL);
5189
5190 if (!wined3d_resource_prepare_map_memory(&dst_surface->resource, context))
5191 {
5192 hr = E_OUTOFMEMORY;
5193 goto error;
5194 }
5195 wined3d_resource_load_location(&dst_surface->resource, context, dst_surface->resource.map_binding);
5196
5197 if (src_surface == dst_surface)
5198 {
5199 dst_data = wined3d_resource_get_map_ptr(&dst_surface->resource, context, 0);
5200 wined3d_resource_get_pitch(&dst_surface->resource, &dst_row_pitch, &dst_slice_pitch);
5201 src_data = dst_data;
5202 src_row_pitch = dst_row_pitch;
5203 #else /* STAGING_CSMT */
5204 const struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
5205 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
5206 const struct wined3d_format *src_format, *dst_format;
5207 unsigned int src_fmt_flags, dst_fmt_flags;
5208 struct wined3d_texture *src_texture = NULL;
5209 struct wined3d_map_desc dst_map, src_map;
5210 const BYTE *sbase = NULL;
5211 HRESULT hr = WINED3D_OK;
5212 const BYTE *sbuf;
5213 BYTE *dbuf;
5214 int x, y;
5215
5216 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5217 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5218 flags, fx, debug_d3dtexturefiltertype(filter));
5219
5220 if (src_surface == dst_surface)
5221 {
5222 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
5223 src_map = dst_map;
5224 #endif /* STAGING_CSMT */
5225 src_format = dst_surface->resource.format;
5226 dst_format = src_format;
5227 dst_fmt_flags = dst_surface->container->resource.format_flags;
5228 src_fmt_flags = dst_fmt_flags;
5229 }
5230 else
5231 {
5232 dst_format = dst_surface->resource.format;
5233 dst_fmt_flags = dst_surface->container->resource.format_flags;
5234 if (src_surface)
5235 {
5236 #if defined(STAGING_CSMT)
5237 if (!wined3d_resource_prepare_map_memory(&src_surface->resource, context))
5238 {
5239 hr = E_OUTOFMEMORY;
5240 goto error;
5241 }
5242
5243 #endif /* STAGING_CSMT */
5244 if (dst_surface->resource.format->id != src_surface->resource.format->id)
5245 {
5246 if (!(src_texture = surface_convert_format(src_surface, dst_format->id)))
5247 {
5248 /* The conv function writes a FIXME */
5249 WARN("Cannot convert source surface format to dest format.\n");
5250 goto release;
5251 }
5252 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, 0));
5253 }
5254 #if defined(STAGING_CSMT)
5255 wined3d_resource_load_location(&src_surface->resource, context, src_surface->resource.map_binding);
5256 wined3d_resource_get_pitch(&src_surface->resource, &src_row_pitch, &src_slice_pitch);
5257 src_data = wined3d_resource_get_map_ptr(&src_surface->resource, context, 0);
5258 #else /* STAGING_CSMT */
5259 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
5260 #endif /* STAGING_CSMT */
5261 src_format = src_surface->resource.format;
5262 src_fmt_flags = src_surface->container->resource.format_flags;
5263 }
5264 else
5265 {
5266 src_format = dst_format;
5267 src_fmt_flags = dst_fmt_flags;
5268 }
5269
5270 #if defined(STAGING_CSMT)
5271 wined3d_resource_get_pitch(&dst_surface->resource, &dst_row_pitch, &dst_slice_pitch);
5272 dst_data = wined3d_resource_get_map_ptr(&dst_surface->resource, context, 0);
5273 #else /* STAGING_CSMT */
5274 wined3d_surface_map(dst_surface, &dst_map, &dst_box, 0);
5275 #endif /* STAGING_CSMT */
5276 }
5277
5278 bpp = dst_surface->resource.format->byte_count;
5279 srcheight = src_rect->bottom - src_rect->top;
5280 srcwidth = src_rect->right - src_rect->left;
5281 dstheight = dst_rect->bottom - dst_rect->top;
5282 dstwidth = dst_rect->right - dst_rect->left;
5283 width = (dst_rect->right - dst_rect->left) * bpp;
5284
5285 if (src_surface)
5286 #if defined(STAGING_CSMT)
5287 sbase = (BYTE *)src_data
5288 + ((src_rect->top / src_format->block_height) * src_row_pitch)
5289 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
5290 dbuf = (BYTE *)dst_data
5291 + ((dst_rect->top / dst_format->block_height) * dst_row_pitch)
5292 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
5293 #else /* STAGING_CSMT */
5294 sbase = (BYTE *)src_map.data
5295 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
5296 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
5297 if (src_surface != dst_surface)
5298 dbuf = dst_map.data;
5299 else
5300 dbuf = (BYTE *)dst_map.data
5301 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
5302 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
5303 #endif /* STAGING_CSMT */
5304
5305 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
5306 {
5307 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
5308
5309 if (src_surface == dst_surface)
5310 {
5311 FIXME("Only plain blits supported on compressed surfaces.\n");
5312 hr = E_NOTIMPL;
5313 goto release;
5314 }
5315
5316 if (srcheight != dstheight || srcwidth != dstwidth)
5317 {
5318 WARN("Stretching not supported on compressed surfaces.\n");
5319 hr = WINED3DERR_INVALIDCALL;
5320 goto release;
5321 }
5322
5323 if (!surface_check_block_align_rect(src_surface, src_rect))
5324 {
5325 WARN("Source rectangle not block-aligned.\n");
5326 hr = WINED3DERR_INVALIDCALL;
5327 goto release;
5328 }
5329
5330 if (!surface_check_block_align_rect(dst_surface, dst_rect))
5331 {
5332 WARN("Destination rectangle not block-aligned.\n");
5333 hr = WINED3DERR_INVALIDCALL;
5334 goto release;
5335 }
5336
5337 hr = surface_cpu_blt_compressed(sbase, dbuf,
5338 #if defined(STAGING_CSMT)
5339 src_row_pitch, dst_row_pitch, dstwidth, dstheight,
5340 #else /* STAGING_CSMT */
5341 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
5342 #endif /* STAGING_CSMT */
5343 src_format, flags, fx);
5344 goto release;
5345 }
5346
5347 /* First, all the 'source-less' blits */
5348 if (flags & WINED3D_BLT_COLOR_FILL)
5349 {
5350 #if defined(STAGING_CSMT)
5351 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_row_pitch, fx->fill_color);
5352 #else /* STAGING_CSMT */
5353 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->fill_color);
5354 #endif /* STAGING_CSMT */
5355 flags &= ~WINED3D_BLT_COLOR_FILL;
5356 }
5357
5358 if (flags & WINED3D_BLT_DEPTH_FILL)
5359 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
5360
5361 /* Now the 'with source' blits. */
5362 if (src_surface)
5363 {
5364 int sx, xinc, sy, yinc;
5365
5366 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
5367 goto release;
5368
5369 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
5370 && (srcwidth != dstwidth || srcheight != dstheight))
5371 {
5372 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
5373 static int once;
5374 if (!once++) FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
5375 }
5376
5377 xinc = (srcwidth << 16) / dstwidth;
5378 yinc = (srcheight << 16) / dstheight;
5379
5380 if (!flags)
5381 {
5382 /* No effects, we can cheat here. */
5383 if (dstwidth == srcwidth)
5384 {
5385 if (dstheight == srcheight)
5386 {
5387 /* No stretching in either direction. This needs to be as
5388 * fast as possible. */
5389 sbuf = sbase;
5390
5391 /* Check for overlapping surfaces. */
5392 if (src_surface != dst_surface || dst_rect->top < src_rect->top
5393 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
5394 {
5395 /* No overlap, or dst above src, so copy from top downwards. */
5396 for (y = 0; y < dstheight; ++y)
5397 {
5398 memcpy(dbuf, sbuf, width);
5399 #if defined(STAGING_CSMT)
5400 sbuf += src_row_pitch;
5401 dbuf += dst_row_pitch;
5402 }
5403 }
5404 else if (dst_rect->top > src_rect->top)
5405 {
5406 /* Copy from bottom upwards. */
5407 sbuf += src_row_pitch * dstheight;
5408 dbuf += dst_row_pitch * dstheight;
5409 for (y = 0; y < dstheight; ++y)
5410 {
5411 sbuf -= src_row_pitch;
5412 dbuf -= dst_row_pitch;
5413 #else /* STAGING_CSMT */
5414 sbuf += src_map.row_pitch;
5415 dbuf += dst_map.row_pitch;
5416 }
5417 }
5418 else if (dst_rect->top > src_rect->top)
5419 {
5420 /* Copy from bottom upwards. */
5421 sbuf += src_map.row_pitch * dstheight;
5422 dbuf += dst_map.row_pitch * dstheight;
5423 for (y = 0; y < dstheight; ++y)
5424 {
5425 sbuf -= src_map.row_pitch;
5426 dbuf -= dst_map.row_pitch;
5427 #endif /* STAGING_CSMT */
5428 memcpy(dbuf, sbuf, width);
5429 }
5430 }
5431 else
5432 {
5433 /* Src and dst overlapping on the same line, use memmove. */
5434 for (y = 0; y < dstheight; ++y)
5435 {
5436 memmove(dbuf, sbuf, width);
5437 #if defined(STAGING_CSMT)
5438 sbuf += src_row_pitch;
5439 dbuf += dst_row_pitch;
5440 #else /* STAGING_CSMT */
5441 sbuf += src_map.row_pitch;
5442 dbuf += dst_map.row_pitch;
5443 #endif /* STAGING_CSMT */
5444 }
5445 }
5446 }
5447 else
5448 {
5449 /* Stretching in y direction only. */
5450 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
5451 {
5452 #if defined(STAGING_CSMT)
5453 sbuf = sbase + (sy >> 16) * src_row_pitch;
5454 memcpy(dbuf, sbuf, width);
5455 dbuf += dst_row_pitch;
5456 #else /* STAGING_CSMT */
5457 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
5458 memcpy(dbuf, sbuf, width);
5459 dbuf += dst_map.row_pitch;
5460 #endif /* STAGING_CSMT */
5461 }
5462 }
5463 }
5464 else
5465 {
5466 /* Stretching in X direction. */
5467 int last_sy = -1;
5468 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
5469 {
5470 #if defined(STAGING_CSMT)
5471 sbuf = sbase + (sy >> 16) * src_row_pitch;
5472
5473 if ((sy >> 16) == (last_sy >> 16))
5474 {
5475 /* This source row is the same as last source row -
5476 * Copy the already stretched row. */
5477 memcpy(dbuf, dbuf - dst_row_pitch, width);
5478 #else /* STAGING_CSMT */
5479 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
5480
5481 if ((sy >> 16) == (last_sy >> 16))
5482 {
5483 /* This source row is the same as last source row -
5484 * Copy the already stretched row. */
5485 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
5486 #endif /* STAGING_CSMT */
5487 }
5488 else
5489 {
5490 #define STRETCH_ROW(type) \
5491 do { \
5492 const type *s = (const type *)sbuf; \
5493 type *d = (type *)dbuf; \
5494 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5495 d[x] = s[sx >> 16]; \
5496 } while(0)
5497
5498 switch(bpp)
5499 {
5500 case 1:
5501 STRETCH_ROW(BYTE);
5502 break;
5503 case 2:
5504 STRETCH_ROW(WORD);
5505 break;
5506 case 4:
5507 STRETCH_ROW(DWORD);
5508 break;
5509 case 3:
5510 {
5511 const BYTE *s;
5512 BYTE *d = dbuf;
5513 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
5514 {
5515 DWORD pixel;
5516
5517 s = sbuf + 3 * (sx >> 16);
5518 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
5519 d[0] = (pixel ) & 0xff;
5520 d[1] = (pixel >> 8) & 0xff;
5521 d[2] = (pixel >> 16) & 0xff;
5522 d += 3;
5523 }
5524 break;
5525 }
5526 default:
5527 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
5528 hr = WINED3DERR_NOTAVAILABLE;
5529 goto error;
5530 }
5531 #undef STRETCH_ROW
5532 }
5533 #if defined(STAGING_CSMT)
5534 dbuf += dst_row_pitch;
5535 last_sy = sy;
5536 }
5537 }
5538 }
5539 else
5540 {
5541 LONG dstyinc = dst_row_pitch, dstxinc = bpp;
5542 #else /* STAGING_CSMT */
5543 dbuf += dst_map.row_pitch;
5544 last_sy = sy;
5545 }
5546 }
5547 }
5548 else
5549 {
5550 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
5551 #endif /* STAGING_CSMT */
5552 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
5553 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
5554 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
5555 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
5556 {
5557 /* The color keying flags are checked for correctness in ddraw */
5558 if (flags & WINED3D_BLT_SRC_CKEY)
5559 {
5560 keylow = src_surface->container->async.src_blt_color_key.color_space_low_value;
5561 keyhigh = src_surface->container->async.src_blt_color_key.color_space_high_value;
5562 }
5563 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
5564 {
5565 keylow = fx->src_color_key.color_space_low_value;
5566 keyhigh = fx->src_color_key.color_space_high_value;
5567 }
5568
5569 if (flags & WINED3D_BLT_DST_CKEY)
5570 {
5571 /* Destination color keys are taken from the source surface! */
5572 destkeylow = src_surface->container->async.dst_blt_color_key.color_space_low_value;
5573 destkeyhigh = src_surface->container->async.dst_blt_color_key.color_space_high_value;
5574 }
5575 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
5576 {
5577 destkeylow = fx->dst_color_key.color_space_low_value;
5578 destkeyhigh = fx->dst_color_key.color_space_high_value;
5579 }
5580
5581 if (bpp == 1)
5582 {
5583 keymask = 0xff;
5584 }
5585 else
5586 {
5587 DWORD masks[3];
5588 get_color_masks(src_format, masks);
5589 keymask = masks[0]
5590 | masks[1]
5591 | masks[2];
5592 }
5593 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
5594 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
5595 }
5596
5597 if (flags & WINED3D_BLT_FX)
5598 {
5599 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
5600 LONG tmpxy;
5601 dTopLeft = dbuf;
5602 dTopRight = dbuf + ((dstwidth - 1) * bpp);
5603 #if defined(STAGING_CSMT)
5604 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_row_pitch);
5605 #else /* STAGING_CSMT */
5606 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
5607 #endif /* STAGING_CSMT */
5608 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
5609
5610 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
5611 {
5612 /* I don't think we need to do anything about this flag */
5613 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
5614 }
5615 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
5616 {
5617 tmp = dTopRight;
5618 dTopRight = dTopLeft;
5619 dTopLeft = tmp;
5620 tmp = dBottomRight;
5621 dBottomRight = dBottomLeft;
5622 dBottomLeft = tmp;
5623 dstxinc = dstxinc * -1;
5624 }
5625 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
5626 {
5627 tmp = dTopLeft;
5628 dTopLeft = dBottomLeft;
5629 dBottomLeft = tmp;
5630 tmp = dTopRight;
5631 dTopRight = dBottomRight;
5632 dBottomRight = tmp;
5633 dstyinc = dstyinc * -1;
5634 }
5635 if (fx->fx & WINEDDBLTFX_NOTEARING)
5636 {
5637 /* I don't think we need to do anything about this flag */
5638 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
5639 }
5640 if (fx->fx & WINEDDBLTFX_ROTATE180)
5641 {
5642 tmp = dBottomRight;
5643 dBottomRight = dTopLeft;
5644 dTopLeft = tmp;
5645 tmp = dBottomLeft;
5646 dBottomLeft = dTopRight;
5647 dTopRight = tmp;
5648 dstxinc = dstxinc * -1;
5649 dstyinc = dstyinc * -1;
5650 }
5651 if (fx->fx & WINEDDBLTFX_ROTATE270)
5652 {
5653 tmp = dTopLeft;
5654 dTopLeft = dBottomLeft;
5655 dBottomLeft = dBottomRight;
5656 dBottomRight = dTopRight;
5657 dTopRight = tmp;
5658 tmpxy = dstxinc;
5659 dstxinc = dstyinc;
5660 dstyinc = tmpxy;
5661 dstxinc = dstxinc * -1;
5662 }
5663 if (fx->fx & WINEDDBLTFX_ROTATE90)
5664 {
5665 tmp = dTopLeft;
5666 dTopLeft = dTopRight;
5667 dTopRight = dBottomRight;
5668 dBottomRight = dBottomLeft;
5669 dBottomLeft = tmp;
5670 tmpxy = dstxinc;
5671 dstxinc = dstyinc;
5672 dstyinc = tmpxy;
5673 dstyinc = dstyinc * -1;
5674 }
5675 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
5676 {
5677 /* I don't think we need to do anything about this flag */
5678 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
5679 }
5680 dbuf = dTopLeft;
5681 flags &= ~(WINED3D_BLT_FX);
5682 }
5683
5684 #if defined(STAGING_CSMT)
5685 #define COPY_COLORKEY_FX(type) \
5686 do { \
5687 const type *s; \
5688 type *d = (type *)dbuf, *dx, tmp; \
5689 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5690 { \
5691 s = (const type *)(sbase + (sy >> 16) * src_row_pitch); \
5692 dx = d; \
5693 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5694 { \
5695 tmp = s[sx >> 16]; \
5696 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5697 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5698 { \
5699 dx[0] = tmp; \
5700 } \
5701 dx = (type *)(((BYTE *)dx) + dstxinc); \
5702 } \
5703 d = (type *)(((BYTE *)d) + dstyinc); \
5704 } \
5705 } while(0)
5706 #else /* STAGING_CSMT */
5707 #define COPY_COLORKEY_FX(type) \
5708 do { \
5709 const type *s; \
5710 type *d = (type *)dbuf, *dx, tmp; \
5711 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5712 { \
5713 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5714 dx = d; \
5715 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5716 { \
5717 tmp = s[sx >> 16]; \
5718 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5719 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5720 { \
5721 dx[0] = tmp; \
5722 } \
5723 dx = (type *)(((BYTE *)dx) + dstxinc); \
5724 } \
5725 d = (type *)(((BYTE *)d) + dstyinc); \
5726 } \
5727 } while(0)
5728 #endif /* STAGING_CSMT */
5729
5730 switch (bpp)
5731 {
5732 case 1:
5733 COPY_COLORKEY_FX(BYTE);
5734 break;
5735 case 2:
5736 COPY_COLORKEY_FX(WORD);
5737 break;
5738 case 4:
5739 COPY_COLORKEY_FX(DWORD);
5740 break;
5741 case 3:
5742 {
5743 const BYTE *s;
5744 BYTE *d = dbuf, *dx;
5745 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
5746 {
5747 #if defined(STAGING_CSMT)
5748 sbuf = sbase + (sy >> 16) * src_row_pitch;
5749 #else /* STAGING_CSMT */
5750 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
5751 #endif /* STAGING_CSMT */
5752 dx = d;
5753 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
5754 {
5755 DWORD pixel, dpixel = 0;
5756 s = sbuf + 3 * (sx>>16);
5757 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
5758 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
5759 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
5760 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
5761 {
5762 dx[0] = (pixel ) & 0xff;
5763 dx[1] = (pixel >> 8) & 0xff;
5764 dx[2] = (pixel >> 16) & 0xff;
5765 }
5766 dx += dstxinc;
5767 }
5768 d += dstyinc;
5769 }
5770 break;
5771 }
5772 default:
5773 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5774 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
5775 hr = WINED3DERR_NOTAVAILABLE;
5776 goto error;
5777 #undef COPY_COLORKEY_FX
5778 }
5779 }
5780 }
5781
5782 #if defined(STAGING_CSMT)
5783 wined3d_resource_invalidate_location(&dst_surface->resource, ~dst_surface->resource.map_binding);
5784 if (dst_surface->container)
5785 wined3d_texture_set_dirty(dst_surface->container);
5786
5787 #endif /* STAGING_CSMT */
5788 error:
5789 if (flags && FIXME_ON(d3d_surface))
5790 {
5791 FIXME("\tUnsupported flags: %#x.\n", flags);
5792 }
5793
5794 release:
5795 #if defined(STAGING_CSMT)
5796 if (dst_data)
5797 {
5798 wined3d_resource_release_map_ptr(&dst_surface->resource, context);
5799
5800 if (dst_surface->container->swapchain
5801 && dst_surface->container == dst_surface->container->swapchain->front_buffer)
5802 {
5803 dst_surface->lockedRect = *dst_rect;
5804 dst_surface->surface_ops->surface_frontbuffer_updated(dst_surface);
5805 }
5806 }
5807 if (src_surface && src_surface != dst_surface && src_data)
5808 wined3d_resource_release_map_ptr(&src_surface->resource, context);
5809 /* Release the converted surface, if any. */
5810 if (src_texture)
5811 wined3d_texture_decref(src_texture);
5812 if (context)
5813 context_release(context);
5814 #else /* STAGING_CSMT */
5815 wined3d_surface_unmap(dst_surface);
5816 if (src_surface && src_surface != dst_surface)
5817 wined3d_surface_unmap(src_surface);
5818 /* Release the converted surface, if any. */
5819 if (src_texture)
5820 wined3d_texture_decref(src_texture);
5821 #endif /* STAGING_CSMT */
5822
5823 return hr;
5824 }
5825
5826 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
5827 const RECT *rect, const struct wined3d_color *color)
5828 {
5829 struct wined3d_surface *surface = wined3d_rendertarget_view_get_surface(view);
5830 static const RECT src_rect;
5831 struct wined3d_blt_fx fx;
5832
5833 fx.fill_color = wined3d_format_convert_from_float(surface, color);
5834 return surface_cpu_blt(surface, rect, NULL, &src_rect,
5835 WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
5836 }
5837
5838 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
5839 struct wined3d_rendertarget_view *view, const RECT *rect, float depth)
5840 {
5841 FIXME("Depth filling not implemented by cpu_blit.\n");
5842 return WINED3DERR_INVALIDCALL;
5843 }
5844
5845 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
5846 struct wined3d_surface *src_surface, const RECT *src_rect,
5847 struct wined3d_surface *dst_surface, const RECT *dst_rect,
5848 const struct wined3d_color_key *color_key)
5849 {
5850 /* FIXME: Remove error returns from surface_blt_cpu. */
5851 ERR("Blit method not implemented by cpu_blit.\n");
5852 }
5853
5854 const struct blit_shader cpu_blit = {
5855 cpu_blit_alloc,
5856 cpu_blit_free,
5857 cpu_blit_set,
5858 cpu_blit_unset,
5859 cpu_blit_supported,
5860 cpu_blit_color_fill,
5861 cpu_blit_depth_fill,
5862 cpu_blit_blit_surface,
5863 };
5864
5865 #if defined(STAGING_CSMT)
5866 void surface_blt_ugly(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5867 #else /* STAGING_CSMT */
5868 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5869 #endif /* STAGING_CSMT */
5870 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
5871 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
5872 {
5873 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
5874 struct wined3d_device *device = dst_surface->resource.device;
5875 DWORD src_ds_flags, dst_ds_flags;
5876 BOOL scale, convert;
5877
5878 static const DWORD simple_blit = WINED3D_BLT_ASYNC
5879 | WINED3D_BLT_COLOR_FILL
5880 | WINED3D_BLT_SRC_CKEY
5881 | WINED3D_BLT_SRC_CKEY_OVERRIDE
5882 | WINED3D_BLT_WAIT
5883 | WINED3D_BLT_DEPTH_FILL
5884 | WINED3D_BLT_DO_NOT_WAIT
5885 | WINED3D_BLT_ALPHA_TEST;
5886
5887 #if !defined(STAGING_CSMT)
5888 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5889 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5890 flags, fx, debug_d3dtexturefiltertype(filter));
5891 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
5892
5893 if (fx)
5894 {
5895 TRACE("fx %#x.\n", fx->fx);
5896 TRACE("fill_color 0x%08x.\n", fx->fill_color);
5897 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
5898 fx->dst_color_key.color_space_low_value,
5899 fx->dst_color_key.color_space_high_value);
5900 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
5901 fx->src_color_key.color_space_low_value,
5902 fx->src_color_key.color_space_high_value);
5903 }
5904
5905 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
5906 {
5907 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5908 return WINEDDERR_SURFACEBUSY;
5909 }
5910
5911 if (dst_rect->left >= dst_rect->right || dst_rect->top >= dst_rect->bottom
5912 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
5913 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
5914 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
5915 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0)
5916 {
5917 WARN("The application gave us a bad destination rectangle.\n");
5918 return WINEDDERR_INVALIDRECT;
5919 }
5920
5921 if (src_surface)
5922 {
5923 if (src_rect->left >= src_rect->right || src_rect->top >= src_rect->bottom
5924 || src_rect->left > src_surface->resource.width || src_rect->left < 0
5925 || src_rect->top > src_surface->resource.height || src_rect->top < 0
5926 || src_rect->right > src_surface->resource.width || src_rect->right < 0
5927 || src_rect->bottom > src_surface->resource.height || src_rect->bottom < 0)
5928 {
5929 WARN("The application gave us a bad source rectangle.\n");
5930 return WINEDDERR_INVALIDRECT;
5931 }
5932 }
5933
5934 if (!fx || !(fx->fx))
5935 flags &= ~WINED3D_BLT_FX;
5936
5937 if (flags & WINED3D_BLT_WAIT)
5938 flags &= ~WINED3D_BLT_WAIT;
5939
5940 if (flags & WINED3D_BLT_ASYNC)
5941 {
5942 static unsigned int once;
5943
5944 if (!once++)
5945 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
5946 flags &= ~WINED3D_BLT_ASYNC;
5947 }
5948
5949 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
5950 if (flags & WINED3D_BLT_DO_NOT_WAIT)
5951 {
5952 static unsigned int once;
5953
5954 if (!once++)
5955 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
5956 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
5957 }
5958
5959 #endif /* STAGING_CSMT */
5960 if (!device->d3d_initialized)
5961 {
5962 WARN("D3D not initialized, using fallback.\n");
5963 goto cpu;
5964 }
5965
5966 /* We want to avoid invalidating the sysmem location for converted
5967 * surfaces, since otherwise we'd have to convert the data back when
5968 * locking them. */
5969 if (dst_surface->container->flags & WINED3D_TEXTURE_CONVERTED
5970 || dst_surface->container->resource.format->convert
5971 || wined3d_format_get_color_key_conversion(dst_surface->container, TRUE))
5972 {
5973 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
5974 goto cpu;
5975 }
5976
5977 if (flags & ~simple_blit)
5978 {
5979 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
5980 goto fallback;
5981 }
5982
5983 if (src_surface)
5984 src_swapchain = src_surface->container->swapchain;
5985 else
5986 src_swapchain = NULL;
5987
5988 dst_swapchain = dst_surface->container->swapchain;
5989
5990 /* This isn't strictly needed. FBO blits for example could deal with
5991 * cross-swapchain blits by first downloading the source to a texture
5992 * before switching to the destination context. We just have this here to
5993 * not have to deal with the issue, since cross-swapchain blits should be
5994 * rare. */
5995 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
5996 {
5997 FIXME("Using fallback for cross-swapchain blit.\n");
5998 goto fallback;
5999 }
6000
6001 scale = src_surface
6002 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
6003 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
6004 convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
6005
6006 dst_ds_flags = dst_surface->container->resource.format_flags
6007 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
6008 if (src_surface)
6009 src_ds_flags = src_surface->container->resource.format_flags
6010 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
6011 else
6012 src_ds_flags = 0;
6013
6014 if (src_ds_flags || dst_ds_flags)
6015 {
6016 if (flags & WINED3D_BLT_DEPTH_FILL)
6017 {
6018 float depth;
6019
6020 TRACE("Depth fill.\n");
6021
6022 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
6023 #if defined(STAGING_CSMT)
6024 return;
6025
6026 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
6027 return;
6028 }
6029 else
6030 {
6031 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_surface->container->resource.draw_binding,
6032 src_rect, dst_surface, dst_surface->container->resource.draw_binding, dst_rect)))
6033 return;
6034 #else /* STAGING_CSMT */
6035 return WINED3DERR_INVALIDCALL;
6036
6037 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
6038 return WINED3D_OK;
6039 }
6040 else
6041 {
6042 if (src_ds_flags != dst_ds_flags)
6043 {
6044 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
6045 return WINED3DERR_INVALIDCALL;
6046 }
6047
6048 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_surface->container->resource.draw_binding,
6049 src_rect, dst_surface, dst_surface->container->resource.draw_binding, dst_rect)))
6050 return WINED3D_OK;
6051 #endif /* STAGING_CSMT */
6052 }
6053 }
6054 else
6055 {
6056 const struct blit_shader *blitter;
6057
6058 /* In principle this would apply to depth blits as well, but we don't
6059 * implement those in the CPU blitter at the moment. */
6060 #if defined(STAGING_CSMT)
6061 if ((dst_surface->resource.locations & dst_surface->resource.map_binding)
6062 && (!src_surface || (src_surface->resource.locations & src_surface->resource.map_binding)))
6063 #else /* STAGING_CSMT */
6064 if ((dst_surface->locations & dst_surface->resource.map_binding)
6065 && (!src_surface || (src_surface->locations & src_surface->resource.map_binding)))
6066 #endif /* STAGING_CSMT */
6067 {
6068 if (scale)
6069 TRACE("Not doing sysmem blit because of scaling.\n");
6070 else if (convert)
6071 TRACE("Not doing sysmem blit because of format conversion.\n");
6072 else
6073 goto cpu;
6074 }
6075
6076 if (flags & WINED3D_BLT_COLOR_FILL)
6077 {
6078 struct wined3d_color color;
6079 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
6080
6081 TRACE("Color fill.\n");
6082
6083 if (!wined3d_format_convert_color_to_float(dst_surface->resource.format,
6084 palette, fx->fill_color, &color))
6085 goto fallback;
6086
6087 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
6088 #if defined(STAGING_CSMT)
6089 return;
6090 #else /* STAGING_CSMT */
6091 return WINED3D_OK;
6092 #endif /* STAGING_CSMT */
6093 }
6094 else
6095 {
6096 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
6097 const struct wined3d_color_key *color_key = NULL;
6098
6099 TRACE("Color blit.\n");
6100 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
6101 {
6102 color_key = &fx->src_color_key;
6103 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
6104 }
6105 else if (flags & WINED3D_BLT_SRC_CKEY)
6106 {
6107 color_key = &src_surface->container->async.src_blt_color_key;
6108 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
6109 }
6110 else if (flags & WINED3D_BLT_ALPHA_TEST)
6111 {
6112 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
6113 }
6114 #if defined(STAGING_CSMT)
6115 else if ((src_surface->resource.locations & WINED3D_LOCATION_SYSMEM)
6116 && !(dst_surface->resource.locations & WINED3D_LOCATION_SYSMEM))
6117 #else /* STAGING_CSMT */
6118 else if ((src_surface->locations & WINED3D_LOCATION_SYSMEM)
6119 && !(dst_surface->locations & WINED3D_LOCATION_SYSMEM))
6120 #endif /* STAGING_CSMT */
6121 {
6122 /* Upload */
6123 if (scale)
6124 TRACE("Not doing upload because of scaling.\n");
6125 else if (convert)
6126 TRACE("Not doing upload because of format conversion.\n");
6127 else
6128 {
6129 POINT dst_point = {dst_rect->left, dst_rect->top};
6130
6131 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
6132 {
6133 if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
6134 {
6135 struct wined3d_context *context = context_acquire(device, dst_surface);
6136 #if defined(STAGING_CSMT)
6137 wined3d_resource_load_location(&dst_surface->resource, context,
6138 dst_surface->container->resource.draw_binding);
6139 context_release(context);
6140 }
6141 return;
6142 #else /* STAGING_CSMT */
6143 surface_load_location(dst_surface, context, dst_surface->container->resource.draw_binding);
6144 context_release(context);
6145 }
6146 return WINED3D_OK;
6147 #endif /* STAGING_CSMT */
6148 }
6149 }
6150 }
6151 else if (dst_swapchain && dst_swapchain->back_buffers
6152 && dst_surface->container == dst_swapchain->front_buffer
6153 && src_surface->container == dst_swapchain->back_buffers[0])
6154 {
6155 /* Use present for back -> front blits. The idea behind this is
6156 * that present is potentially faster than a blit, in particular
6157 * when FBO blits aren't available. Some ddraw applications like
6158 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
6159 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
6160 * applications can't blit directly to the frontbuffer. */
6161 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
6162
6163 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
6164
6165 /* Set the swap effect to COPY, we don't want the backbuffer
6166 * to become undefined. */
6167 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
6168 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
6169 dst_swapchain->desc.swap_effect = swap_effect;
6170
6171 #if defined(STAGING_CSMT)
6172 return;
6173 #else /* STAGING_CSMT */
6174 return WINED3D_OK;
6175 #endif /* STAGING_CSMT */
6176 }
6177
6178 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
6179 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
6180 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
6181 {
6182 struct wined3d_context *context;
6183 TRACE("Using FBO blit.\n");
6184
6185 context = context_acquire(device, NULL);
6186 surface_blt_fbo(device, context, filter,
6187 src_surface, src_surface->container->resource.draw_binding, src_rect,
6188 dst_surface, dst_surface->container->resource.draw_binding, dst_rect);
6189 context_release(context);
6190
6191 #if defined(STAGING_CSMT)
6192 wined3d_resource_validate_location(&dst_surface->resource, dst_surface->container->resource.draw_binding);
6193 wined3d_resource_invalidate_location(&dst_surface->resource, ~dst_surface->container->resource.draw_binding);
6194
6195 return;
6196 #else /* STAGING_CSMT */
6197 surface_validate_location(dst_surface, dst_surface->container->resource.draw_binding);
6198 surface_invalidate_location(dst_surface, ~dst_surface->container->resource.draw_binding);
6199
6200 return WINED3D_OK;
6201 #endif /* STAGING_CSMT */
6202 }
6203
6204 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
6205 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
6206 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format);
6207 if (blitter)
6208 {
6209 blitter->blit_surface(device, blit_op, filter, src_surface,
6210 src_rect, dst_surface, dst_rect, color_key);
6211 #if defined(STAGING_CSMT)
6212 return;
6213 }
6214 }
6215 }
6216
6217 fallback:
6218 /* Special cases for render targets. */
6219 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
6220 || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)))
6221 {
6222 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
6223 return;
6224 }
6225
6226 cpu:
6227 surface_cpu_blt(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter);
6228 return;
6229 }
6230
6231 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
6232 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
6233 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
6234 {
6235 struct wined3d_device *device = dst_surface->resource.device;
6236
6237 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6238 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
6239 flags, fx, debug_d3dtexturefiltertype(filter));
6240 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
6241
6242 if (fx)
6243 {
6244 TRACE("fx %#x.\n", fx->fx);
6245 TRACE("fill_color 0x%08x.\n", fx->fill_color);
6246 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
6247 fx->dst_color_key.color_space_low_value,
6248 fx->dst_color_key.color_space_high_value);
6249 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
6250 fx->src_color_key.color_space_low_value,
6251 fx->src_color_key.color_space_high_value);
6252 }
6253
6254 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
6255 {
6256 /* TODO: Separate application maps from internal maps */
6257 if (!wined3d_settings.cs_multithreaded)
6258 {
6259 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
6260 return WINEDDERR_SURFACEBUSY;
6261 }
6262
6263 wined3d_cs_emit_glfinish(dst_surface->resource.device->cs);
6264 dst_surface->resource.device->cs->ops->finish(dst_surface->resource.device->cs);
6265
6266 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
6267 {
6268 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
6269 return WINEDDERR_SURFACEBUSY;
6270 }
6271 }
6272
6273 if (dst_rect->left >= dst_rect->right || dst_rect->top >= dst_rect->bottom
6274 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
6275 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
6276 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
6277 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0)
6278 {
6279 WARN("The application gave us a bad destination rectangle.\n");
6280 return WINEDDERR_INVALIDRECT;
6281 }
6282
6283 if (src_surface)
6284 {
6285 DWORD src_ds_flags, dst_ds_flags;
6286
6287 if (src_rect->left >= src_rect->right || src_rect->top >= src_rect->bottom
6288 || src_rect->left > src_surface->resource.width || src_rect->left < 0
6289 || src_rect->top > src_surface->resource.height || src_rect->top < 0
6290 || src_rect->right > src_surface->resource.width || src_rect->right < 0
6291 || src_rect->bottom > src_surface->resource.height || src_rect->bottom < 0)
6292 {
6293 WARN("The application gave us a bad source rectangle.\n");
6294 return WINEDDERR_INVALIDRECT;
6295 }
6296
6297 dst_ds_flags = dst_surface->container->resource.format_flags
6298 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
6299 src_ds_flags = src_surface->container->resource.format_flags
6300 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
6301 if (src_ds_flags != dst_ds_flags)
6302 {
6303 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
6304 return WINED3DERR_INVALIDCALL;
6305 }
6306 }
6307
6308 /* FIXME: We should select the blitter in the main thread, that way we can return an error if the blit
6309 * is unsupported without duplicating all the checks... */
6310 if (flags & WINED3D_BLT_COLOR_FILL && (dst_surface->container->resource.format_flags & WINED3DFMT_FLAG_BLOCKS))
6311 {
6312 WARN("Block color fill, returning WINED3DERR_INVALIDCALL\n");
6313 return WINED3DERR_INVALIDCALL;
6314 }
6315
6316 if (!fx || !(fx->fx))
6317 flags &= ~WINED3D_BLT_FX;
6318
6319 if (flags & WINED3D_BLT_WAIT)
6320 flags &= ~WINED3D_BLT_WAIT;
6321
6322 if (flags & WINED3D_BLT_ASYNC)
6323 {
6324 static unsigned int once;
6325
6326 if (!once++)
6327 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
6328 flags &= ~WINED3D_BLT_ASYNC;
6329 }
6330
6331 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
6332 if (flags & WINED3D_BLT_DO_NOT_WAIT)
6333 {
6334 static unsigned int once;
6335
6336 if (!once++)
6337 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
6338 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
6339 }
6340
6341 TRACE("Emitting blit %p <== %p\n", dst_surface, src_surface);
6342 wined3d_cs_emit_blt(device->cs, dst_surface, dst_rect, src_surface, src_rect,
6343 flags, fx, filter);
6344
6345 return WINED3D_OK;
6346 }
6347
6348 static const struct wined3d_resource_ops surface_resource_ops =
6349 {
6350 surface_resource_incref,
6351 surface_resource_decref,
6352 surface_unload,
6353 surface_resource_sub_resource_map,
6354 surface_resource_sub_resource_unmap,
6355 wined3d_surface_location_invalidated,
6356 wined3d_surface_load_location,
6357 };
6358 #else /* STAGING_CSMT */
6359 return WINED3D_OK;
6360 }
6361 }
6362 }
6363
6364 fallback:
6365 /* Special cases for render targets. */
6366 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
6367 return WINED3D_OK;
6368
6369 cpu:
6370 return surface_cpu_blt(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter);
6371 }
6372 #endif /* STAGING_CSMT */
6373
6374 static HRESULT surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
6375 const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags)
6376 {
6377 struct wined3d_device *device = container->resource.device;
6378 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6379 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format);
6380 BOOL lockable = flags & WINED3D_TEXTURE_CREATE_MAPPABLE;
6381 UINT multisample_quality = desc->multisample_quality;
6382 unsigned int resource_size;
6383 HRESULT hr;
6384
6385 /* Quick lockable sanity check.
6386 * TODO: remove this after surfaces, usage and lockability have been debugged properly
6387 * this function is too deep to need to care about things like this.
6388 * Levels need to be checked too, since they all affect what can be done. */
6389 switch (desc->pool)
6390 {
6391 case WINED3D_POOL_MANAGED:
6392 if (desc->usage & WINED3DUSAGE_DYNAMIC)
6393 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
6394 break;
6395
6396 case WINED3D_POOL_DEFAULT:
6397 if (lockable && !(desc->usage & (WINED3DUSAGE_DYNAMIC
6398 | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
6399 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
6400 break;
6401
6402 case WINED3D_POOL_SCRATCH:
6403 case WINED3D_POOL_SYSTEM_MEM:
6404 break;
6405
6406 default:
6407 FIXME("Unknown pool %#x.\n", desc->pool);
6408 break;
6409 };
6410
6411 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->pool != WINED3D_POOL_DEFAULT)
6412 FIXME("Trying to create a render target that isn't in the default pool.\n");
6413
6414 /* FIXME: Check that the format is supported by the device. */
6415
6416 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, 1);
6417 if (!resource_size)
6418 return WINED3DERR_INVALIDCALL;
6419
6420 if (device->wined3d->flags & WINED3D_NO3D)
6421 surface->surface_ops = &gdi_surface_ops;
6422 else
6423 surface->surface_ops = &surface_ops;
6424
6425 if (FAILED(hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE,
6426 format, desc->multisample_type, multisample_quality, desc->usage, desc->pool, desc->width, desc->height,
6427 1, resource_size, NULL, &wined3d_null_parent_ops, &surface_resource_ops)))
6428 {
6429 WARN("Failed to initialize resource, returning %#x.\n", hr);
6430 return hr;
6431 }
6432
6433 surface->container = container;
6434 #if defined(STAGING_CSMT)
6435 wined3d_resource_validate_location(&surface->resource, WINED3D_LOCATION_SYSMEM);
6436 #else /* STAGING_CSMT */
6437 surface_validate_location(surface, WINED3D_LOCATION_SYSMEM);
6438 #endif /* STAGING_CSMT */
6439 list_init(&surface->renderbuffers);
6440 list_init(&surface->overlays);
6441
6442 /* Flags */
6443 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
6444 surface->flags |= SFLAG_DISCARD;
6445 if (lockable || desc->format == WINED3DFMT_D16_LOCKABLE)
6446 surface->resource.access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
6447
6448 surface->texture_target = target;
6449 surface->texture_level = level;
6450 surface->texture_layer = layer;
6451
6452 /* Call the private setup routine */
6453 if (FAILED(hr = surface->surface_ops->surface_private_setup(surface)))
6454 {
6455 ERR("Private setup failed, hr %#x.\n", hr);
6456 surface_cleanup(surface);
6457 return hr;
6458 }
6459
6460 /* Similar to lockable rendertargets above, creating the DIB section
6461 * during surface initialization prevents the sysmem pointer from changing
6462 * after a wined3d_texture_get_dc() call. */
6463 if ((desc->usage & WINED3DUSAGE_OWNDC) && !surface->hDC
6464 && SUCCEEDED(surface_create_dib_section(surface)))
6465 surface->resource.map_binding = WINED3D_LOCATION_DIB;
6466
6467 if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
6468 {
6469 wined3d_resource_free_sysmem(&surface->resource);
6470 #if defined(STAGING_CSMT)
6471 surface->resource.map_heap_memory = NULL;
6472 wined3d_resource_validate_location(&surface->resource, WINED3D_LOCATION_DIB);
6473 wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_SYSMEM);
6474 #else /* STAGING_CSMT */
6475 surface_validate_location(surface, WINED3D_LOCATION_DIB);
6476 surface_invalidate_location(surface, WINED3D_LOCATION_SYSMEM);
6477 #endif /* STAGING_CSMT */
6478 }
6479
6480 return hr;
6481 }
6482
6483 HRESULT wined3d_surface_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc,
6484 GLenum target, unsigned int level, unsigned int layer, DWORD flags, struct wined3d_surface **surface)
6485 {
6486 struct wined3d_device_parent *device_parent = container->resource.device->device_parent;
6487 const struct wined3d_parent_ops *parent_ops;
6488 struct wined3d_surface *object;
6489 void *parent;
6490 HRESULT hr;
6491
6492 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
6493 "multisample_type %#x, multisample_quality %u, target %#x, level %u, layer %u, flags %#x, surface %p.\n",
6494 container, desc->width, desc->height, debug_d3dformat(desc->format),
6495 debug_d3dusage(desc->usage), desc->usage, debug_d3dpool(desc->pool),
6496 desc->multisample_type, desc->multisample_quality, target, level, layer, flags, surface);
6497
6498 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
6499 return E_OUTOFMEMORY;
6500
6501 if (FAILED(hr = surface_init(object, container, desc, target, level, layer, flags)))
6502 {
6503 WARN("Failed to initialize surface, returning %#x.\n", hr);
6504 #if defined(STAGING_CSMT)
6505 /* The command stream takes care of freeing the memory. */
6506 #else /* STAGING_CSMT */
6507 HeapFree(GetProcessHeap(), 0, object);
6508 #endif /* STAGING_CSMT */
6509 return hr;
6510 }
6511
6512 if (FAILED(hr = device_parent->ops->surface_created(device_parent,
6513 container, layer * container->level_count + level, &parent, &parent_ops)))
6514 {
6515 WARN("Failed to create surface parent, hr %#x.\n", hr);
6516 wined3d_surface_destroy(object);
6517 return hr;
6518 }
6519
6520 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object, parent, parent_ops);
6521
6522 object->resource.parent = parent;
6523 object->resource.parent_ops = parent_ops;
6524 *surface = object;
6525
6526 return hr;
6527 }
6528
6529 /* Context activation is done by the caller. */
6530 void wined3d_surface_prepare(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
6531 {
6532 switch (location)
6533 {
6534 case WINED3D_LOCATION_TEXTURE_RGB:
6535 wined3d_texture_prepare_texture(surface->container, context, FALSE);
6536 break;
6537
6538 case WINED3D_LOCATION_TEXTURE_SRGB:
6539 wined3d_texture_prepare_texture(surface->container, context, TRUE);
6540 break;
6541
6542 case WINED3D_LOCATION_RB_MULTISAMPLE:
6543 surface_prepare_rb(surface, context->gl_info, TRUE);
6544 break;
6545
6546 case WINED3D_LOCATION_RB_RESOLVED:
6547 surface_prepare_rb(surface, context->gl_info, FALSE);
6548 break;
6549 }
6550 }