wined3d: Introduce wined3d_texture_invalidate_location().
[wine.git] / dlls / wined3d / surface.c
blob6d0e1471e3dad5203e20b746cc76fa11b03b3fbc
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
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.
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.
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
29 #include "config.h"
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
36 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
38 static const DWORD surface_simple_locations =
39 WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_USER_MEMORY
40 | WINED3D_LOCATION_DIB | WINED3D_LOCATION_BUFFER;
42 void wined3d_surface_cleanup(struct wined3d_surface *surface)
44 struct wined3d_surface *overlay, *cur;
46 TRACE("surface %p.\n", surface);
48 if (surface->rb_multisample || surface->rb_resolved || !list_empty(&surface->renderbuffers))
50 struct wined3d_device *device = surface->container->resource.device;
51 struct wined3d_renderbuffer_entry *entry, *entry2;
52 const struct wined3d_gl_info *gl_info;
53 struct wined3d_context *context;
55 context = context_acquire(device, NULL);
56 gl_info = context->gl_info;
58 if (surface->rb_multisample)
60 TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
61 context_gl_resource_released(device, surface->rb_multisample, TRUE);
62 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
65 if (surface->rb_resolved)
67 TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved);
68 context_gl_resource_released(device, surface->rb_resolved, TRUE);
69 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
72 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
74 TRACE("Deleting renderbuffer %u.\n", entry->id);
75 context_gl_resource_released(device, entry->id, TRUE);
76 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
77 HeapFree(GetProcessHeap(), 0, entry);
80 context_release(context);
83 if (surface->flags & SFLAG_DIBSECTION)
85 DeleteDC(surface->hDC);
86 DeleteObject(surface->dib.DIBsection);
87 surface->dib.bitmap_data = NULL;
90 if (surface->overlay_dest)
91 list_remove(&surface->overlay_entry);
93 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry)
95 list_remove(&overlay->overlay_entry);
96 overlay->overlay_dest = NULL;
99 resource_cleanup(&surface->resource);
102 void surface_get_drawable_size(const struct wined3d_surface *surface, const struct wined3d_context *context,
103 unsigned int *width, unsigned int *height)
105 if (surface->container->swapchain)
107 /* The drawable size of an onscreen drawable is the surface size.
108 * (Actually: The window size, but the surface is created in window
109 * size.) */
110 *width = context->current_rt.texture->resource.width;
111 *height = context->current_rt.texture->resource.height;
113 else if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER)
115 const struct wined3d_swapchain *swapchain = context->swapchain;
117 /* The drawable size of a backbuffer / aux buffer offscreen target is
118 * the size of the current context's drawable, which is the size of
119 * the back buffer of the swapchain the active context belongs to. */
120 *width = swapchain->desc.backbuffer_width;
121 *height = swapchain->desc.backbuffer_height;
123 else
125 struct wined3d_surface *rt;
127 /* The drawable size of an FBO target is the OpenGL texture size,
128 * which is the power of two size. */
129 rt = context->current_rt.texture->sub_resources[context->current_rt.sub_resource_idx].u.surface;
130 *width = rt->pow2Width;
131 *height = rt->pow2Height;
135 struct blt_info
137 GLenum binding;
138 GLenum bind_target;
139 enum wined3d_gl_resource_type tex_type;
140 GLfloat coords[4][3];
143 struct float_rect
145 float l;
146 float t;
147 float r;
148 float b;
151 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
153 f->l = ((r->left * 2.0f) / w) - 1.0f;
154 f->t = ((r->top * 2.0f) / h) - 1.0f;
155 f->r = ((r->right * 2.0f) / w) - 1.0f;
156 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
159 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
161 GLfloat (*coords)[3] = info->coords;
162 struct float_rect f;
164 switch (target)
166 default:
167 FIXME("Unsupported texture target %#x\n", target);
168 /* Fall back to GL_TEXTURE_2D */
169 case GL_TEXTURE_2D:
170 info->binding = GL_TEXTURE_BINDING_2D;
171 info->bind_target = GL_TEXTURE_2D;
172 info->tex_type = WINED3D_GL_RES_TYPE_TEX_2D;
173 coords[0][0] = (float)rect->left / w;
174 coords[0][1] = (float)rect->top / h;
175 coords[0][2] = 0.0f;
177 coords[1][0] = (float)rect->right / w;
178 coords[1][1] = (float)rect->top / h;
179 coords[1][2] = 0.0f;
181 coords[2][0] = (float)rect->left / w;
182 coords[2][1] = (float)rect->bottom / h;
183 coords[2][2] = 0.0f;
185 coords[3][0] = (float)rect->right / w;
186 coords[3][1] = (float)rect->bottom / h;
187 coords[3][2] = 0.0f;
188 break;
190 case GL_TEXTURE_RECTANGLE_ARB:
191 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
192 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
193 info->tex_type = WINED3D_GL_RES_TYPE_TEX_RECT;
194 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
195 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
196 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
197 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
198 break;
200 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
201 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
202 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
203 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
204 cube_coords_float(rect, w, h, &f);
206 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
207 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
208 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
209 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
210 break;
212 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
213 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
214 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
215 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
216 cube_coords_float(rect, w, h, &f);
218 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
219 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
220 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
221 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
222 break;
224 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
225 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
226 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
227 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
228 cube_coords_float(rect, w, h, &f);
230 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
231 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
232 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
233 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
234 break;
236 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
237 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
238 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
239 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
240 cube_coords_float(rect, w, h, &f);
242 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
243 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
244 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
245 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
246 break;
248 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
249 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
250 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
251 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
252 cube_coords_float(rect, w, h, &f);
254 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
255 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
256 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
257 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
258 break;
260 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
261 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
262 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
263 info->tex_type = WINED3D_GL_RES_TYPE_TEX_CUBE;
264 cube_coords_float(rect, w, h, &f);
266 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
267 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
268 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
269 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
270 break;
274 static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
276 if (rect_in)
277 *rect_out = *rect_in;
278 else
280 rect_out->left = 0;
281 rect_out->top = 0;
282 rect_out->right = surface->resource.width;
283 rect_out->bottom = surface->resource.height;
287 /* Context activation is done by the caller. */
288 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
289 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
291 const struct wined3d_gl_info *gl_info = context->gl_info;
292 struct wined3d_texture *texture = src_surface->container;
293 struct blt_info info;
295 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
297 gl_info->gl_ops.gl.p_glEnable(info.bind_target);
298 checkGLcall("glEnable(bind_target)");
300 context_bind_texture(context, info.bind_target, texture->texture_rgb.name);
302 /* Filtering for StretchRect */
303 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
304 checkGLcall("glTexParameteri");
305 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
306 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
307 checkGLcall("glTexParameteri");
308 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
309 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
310 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
311 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
312 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
313 checkGLcall("glTexEnvi");
315 /* Draw a quad */
316 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
317 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
318 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->top);
320 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
321 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->top);
323 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
324 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->bottom);
326 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
327 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->bottom);
328 gl_info->gl_ops.gl.p_glEnd();
330 /* Unbind the texture */
331 context_bind_texture(context, info.bind_target, 0);
333 /* We changed the filtering settings on the texture. Inform the
334 * container about this to get the filters reset properly next draw. */
335 texture->texture_rgb.sampler_desc.mag_filter = WINED3D_TEXF_POINT;
336 texture->texture_rgb.sampler_desc.min_filter = WINED3D_TEXF_POINT;
337 texture->texture_rgb.sampler_desc.mip_filter = WINED3D_TEXF_NONE;
338 texture->texture_rgb.sampler_desc.srgb_decode = FALSE;
341 /* Works correctly only for <= 4 bpp formats. */
342 static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
344 masks[0] = ((1u << format->red_size) - 1) << format->red_offset;
345 masks[1] = ((1u << format->green_size) - 1) << format->green_offset;
346 masks[2] = ((1u << format->blue_size) - 1) << format->blue_offset;
349 HRESULT surface_create_dib_section(struct wined3d_surface *surface)
351 struct wined3d_texture *texture = surface->container;
352 const struct wined3d_format *format = texture->resource.format;
353 unsigned int format_flags = texture->resource.format_flags;
354 unsigned int row_pitch, slice_pitch;
355 BITMAPINFO *b_info;
356 DWORD *masks;
358 TRACE("surface %p.\n", surface);
360 if (!(format_flags & WINED3DFMT_FLAG_GETDC))
362 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
363 return WINED3DERR_INVALIDCALL;
366 switch (format->byte_count)
368 case 2:
369 case 4:
370 /* Allocate extra space to store the RGB bit masks. */
371 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO, bmiColors[3]));
372 break;
374 case 3:
375 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO, bmiColors[0]));
376 break;
378 default:
379 /* Allocate extra space for a palette. */
380 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
381 FIELD_OFFSET(BITMAPINFO, bmiColors[1u << (format->byte_count * 8)]));
382 break;
385 if (!b_info)
386 return E_OUTOFMEMORY;
388 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
389 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
390 b_info->bmiHeader.biWidth = row_pitch / format->byte_count;
391 b_info->bmiHeader.biHeight = 0 - surface->resource.height;
392 b_info->bmiHeader.biSizeImage = slice_pitch;
393 b_info->bmiHeader.biPlanes = 1;
394 b_info->bmiHeader.biBitCount = format->byte_count * 8;
396 b_info->bmiHeader.biXPelsPerMeter = 0;
397 b_info->bmiHeader.biYPelsPerMeter = 0;
398 b_info->bmiHeader.biClrUsed = 0;
399 b_info->bmiHeader.biClrImportant = 0;
401 /* Get the bit masks */
402 masks = (DWORD *)b_info->bmiColors;
403 switch (format->id)
405 case WINED3DFMT_B8G8R8_UNORM:
406 b_info->bmiHeader.biCompression = BI_RGB;
407 break;
409 case WINED3DFMT_B5G5R5X1_UNORM:
410 case WINED3DFMT_B5G5R5A1_UNORM:
411 case WINED3DFMT_B4G4R4A4_UNORM:
412 case WINED3DFMT_B4G4R4X4_UNORM:
413 case WINED3DFMT_B2G3R3_UNORM:
414 case WINED3DFMT_B2G3R3A8_UNORM:
415 case WINED3DFMT_R10G10B10A2_UNORM:
416 case WINED3DFMT_R8G8B8A8_UNORM:
417 case WINED3DFMT_R8G8B8X8_UNORM:
418 case WINED3DFMT_B10G10R10A2_UNORM:
419 case WINED3DFMT_B5G6R5_UNORM:
420 case WINED3DFMT_R16G16B16A16_UNORM:
421 b_info->bmiHeader.biCompression = BI_BITFIELDS;
422 get_color_masks(format, masks);
423 break;
425 default:
426 /* Don't know palette */
427 b_info->bmiHeader.biCompression = BI_RGB;
428 break;
431 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
432 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
433 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
434 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
436 if (!surface->dib.DIBsection)
438 ERR("Failed to create DIB section.\n");
439 HeapFree(GetProcessHeap(), 0, b_info);
440 return HRESULT_FROM_WIN32(GetLastError());
443 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
444 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
446 HeapFree(GetProcessHeap(), 0, b_info);
448 /* Now allocate a DC. */
449 surface->hDC = CreateCompatibleDC(0);
450 SelectObject(surface->hDC, surface->dib.DIBsection);
452 surface->flags |= SFLAG_DIBSECTION;
454 return WINED3D_OK;
457 static void surface_get_memory(const struct wined3d_surface *surface, struct wined3d_bo_address *data,
458 DWORD location)
460 if (location & WINED3D_LOCATION_BUFFER)
462 data->addr = NULL;
463 data->buffer_object = surface->container->sub_resources[surface_get_sub_resource_idx(surface)].buffer_object;
464 return;
466 if (location & WINED3D_LOCATION_USER_MEMORY)
468 data->addr = surface->container->user_memory;
469 data->buffer_object = 0;
470 return;
472 if (location & WINED3D_LOCATION_DIB)
474 data->addr = surface->dib.bitmap_data;
475 data->buffer_object = 0;
476 return;
478 if (location & WINED3D_LOCATION_SYSMEM)
480 data->addr = surface->resource.heap_memory;
481 data->buffer_object = 0;
482 return;
485 ERR("Unexpected locations %s.\n", wined3d_debug_location(location));
486 data->addr = NULL;
487 data->buffer_object = 0;
490 static void surface_prepare_system_memory(struct wined3d_surface *surface)
492 TRACE("surface %p.\n", surface);
494 if (surface->resource.heap_memory)
495 return;
497 /* Whatever surface we have, make sure that there is memory allocated
498 * for the downloaded copy, or a PBO to map. */
499 if (!wined3d_resource_allocate_sysmem(&surface->resource))
500 ERR("Failed to allocate system memory.\n");
502 if (surface_get_sub_resource(surface)->locations & WINED3D_LOCATION_SYSMEM)
503 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
506 static void surface_evict_sysmem(struct wined3d_surface *surface)
508 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
509 struct wined3d_texture *texture = surface->container;
511 if (surface->resource.map_count || texture->download_count > MAXLOCKCOUNT
512 || texture->flags & (WINED3D_TEXTURE_CONVERTED | WINED3D_TEXTURE_PIN_SYSMEM))
513 return;
515 wined3d_resource_free_sysmem(&surface->resource);
516 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
519 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
521 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
522 return FALSE;
523 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
524 return FALSE;
525 return TRUE;
528 static void surface_depth_blt_fbo(const struct wined3d_device *device,
529 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
530 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
532 const struct wined3d_gl_info *gl_info;
533 struct wined3d_context *context;
534 DWORD src_mask, dst_mask;
535 GLbitfield gl_mask;
537 TRACE("device %p\n", device);
538 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
539 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect));
540 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
541 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
543 src_mask = src_surface->container->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
544 dst_mask = dst_surface->container->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
546 if (src_mask != dst_mask)
548 ERR("Incompatible formats %s and %s.\n",
549 debug_d3dformat(src_surface->container->resource.format->id),
550 debug_d3dformat(dst_surface->container->resource.format->id));
551 return;
554 if (!src_mask)
556 ERR("Not a depth / stencil format: %s.\n",
557 debug_d3dformat(src_surface->container->resource.format->id));
558 return;
561 gl_mask = 0;
562 if (src_mask & WINED3DFMT_FLAG_DEPTH)
563 gl_mask |= GL_DEPTH_BUFFER_BIT;
564 if (src_mask & WINED3DFMT_FLAG_STENCIL)
565 gl_mask |= GL_STENCIL_BUFFER_BIT;
567 context = context_acquire(device, NULL);
568 if (!context->valid)
570 context_release(context);
571 WARN("Invalid context, skipping blit.\n");
572 return;
575 /* Make sure the locations are up-to-date. Loading the destination
576 * surface isn't required if the entire surface is overwritten. */
577 surface_load_location(src_surface, context, src_location);
578 if (!surface_is_full_rect(dst_surface, dst_rect))
579 surface_load_location(dst_surface, context, dst_location);
580 else
581 wined3d_surface_prepare(dst_surface, context, dst_location);
583 gl_info = context->gl_info;
585 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, src_location);
586 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
588 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, dst_location);
589 context_set_draw_buffer(context, GL_NONE);
590 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
591 context_invalidate_state(context, STATE_FRAMEBUFFER);
593 if (gl_mask & GL_DEPTH_BUFFER_BIT)
595 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
596 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
598 if (gl_mask & GL_STENCIL_BUFFER_BIT)
600 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
602 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
603 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
605 gl_info->gl_ops.gl.p_glStencilMask(~0U);
606 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
609 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
610 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
612 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
613 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
614 checkGLcall("glBlitFramebuffer()");
616 if (wined3d_settings.strict_draw_ordering)
617 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
619 context_release(context);
622 /* Blit between surface locations. Onscreen on different swapchains is not supported.
623 * Depth / stencil is not supported. Context activation is done by the caller. */
624 static void surface_blt_fbo(const struct wined3d_device *device,
625 struct wined3d_context *old_ctx, enum wined3d_texture_filter_type filter,
626 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
627 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
629 const struct wined3d_gl_info *gl_info;
630 struct wined3d_context *context = old_ctx;
631 struct wined3d_surface *required_rt, *restore_rt = NULL;
632 RECT src_rect, dst_rect;
633 GLenum gl_filter;
634 GLenum buffer;
636 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
637 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
638 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect_in));
639 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
640 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect_in));
642 src_rect = *src_rect_in;
643 dst_rect = *dst_rect_in;
645 switch (filter)
647 case WINED3D_TEXF_LINEAR:
648 gl_filter = GL_LINEAR;
649 break;
651 default:
652 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
653 case WINED3D_TEXF_NONE:
654 case WINED3D_TEXF_POINT:
655 gl_filter = GL_NEAREST;
656 break;
659 /* Resolve the source surface first if needed. */
660 if (src_location == WINED3D_LOCATION_RB_MULTISAMPLE
661 && (src_surface->container->resource.format->id != dst_surface->container->resource.format->id
662 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
663 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
664 src_location = WINED3D_LOCATION_RB_RESOLVED;
666 /* Make sure the locations are up-to-date. Loading the destination
667 * surface isn't required if the entire surface is overwritten. (And is
668 * in fact harmful if we're being called by surface_load_location() with
669 * the purpose of loading the destination surface.) */
670 surface_load_location(src_surface, old_ctx, src_location);
671 if (!surface_is_full_rect(dst_surface, &dst_rect))
672 surface_load_location(dst_surface, old_ctx, dst_location);
673 else
674 wined3d_surface_prepare(dst_surface, old_ctx, dst_location);
677 if (src_location == WINED3D_LOCATION_DRAWABLE) required_rt = src_surface;
678 else if (dst_location == WINED3D_LOCATION_DRAWABLE) required_rt = dst_surface;
679 else required_rt = NULL;
681 restore_rt = context_get_rt_surface(old_ctx);
682 if (restore_rt != required_rt)
683 context = context_acquire(device, required_rt);
684 else
685 restore_rt = NULL;
687 if (!context->valid)
689 context_release(context);
690 WARN("Invalid context, skipping blit.\n");
691 return;
694 gl_info = context->gl_info;
696 if (src_location == WINED3D_LOCATION_DRAWABLE)
698 TRACE("Source surface %p is onscreen.\n", src_surface);
699 buffer = wined3d_texture_get_gl_buffer(src_surface->container);
700 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
702 else
704 TRACE("Source surface %p is offscreen.\n", src_surface);
705 buffer = GL_COLOR_ATTACHMENT0;
708 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
709 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
710 checkGLcall("glReadBuffer()");
711 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
713 if (dst_location == WINED3D_LOCATION_DRAWABLE)
715 TRACE("Destination surface %p is onscreen.\n", dst_surface);
716 buffer = wined3d_texture_get_gl_buffer(dst_surface->container);
717 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
719 else
721 TRACE("Destination surface %p is offscreen.\n", dst_surface);
722 buffer = GL_COLOR_ATTACHMENT0;
725 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
726 context_set_draw_buffer(context, buffer);
727 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
728 context_invalidate_state(context, STATE_FRAMEBUFFER);
730 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
731 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
732 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
733 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
734 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
736 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
737 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
739 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
740 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
741 checkGLcall("glBlitFramebuffer()");
743 if (wined3d_settings.strict_draw_ordering
744 || (dst_location == WINED3D_LOCATION_DRAWABLE
745 && dst_surface->container->swapchain->front_buffer == dst_surface->container))
746 gl_info->gl_ops.gl.p_glFlush();
748 if (restore_rt)
749 context_restore(context, restore_rt);
752 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
753 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
754 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
756 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
757 return FALSE;
759 /* Source and/or destination need to be on the GL side */
760 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
761 return FALSE;
763 switch (blit_op)
765 case WINED3D_BLIT_OP_COLOR_BLIT:
766 if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
767 || (src_usage & WINED3DUSAGE_RENDERTARGET)))
768 return FALSE;
769 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
770 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
771 return FALSE;
772 if (!(src_format->id == dst_format->id
773 || (is_identity_fixup(src_format->color_fixup)
774 && is_identity_fixup(dst_format->color_fixup))))
775 return FALSE;
776 break;
778 case WINED3D_BLIT_OP_DEPTH_BLIT:
779 if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
780 return FALSE;
781 if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
782 return FALSE;
783 /* Accept pure swizzle fixups for depth formats. In general we
784 * ignore the stencil component (if present) at the moment and the
785 * swizzle is not relevant with just the depth component. */
786 if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
787 || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
788 return FALSE;
789 break;
791 default:
792 return FALSE;
795 return TRUE;
798 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
800 const struct wined3d_format *format = surface->container->resource.format;
802 switch (format->id)
804 case WINED3DFMT_S1_UINT_D15_UNORM:
805 *float_depth = depth / (float)0x00007fff;
806 break;
808 case WINED3DFMT_D16_UNORM:
809 *float_depth = depth / (float)0x0000ffff;
810 break;
812 case WINED3DFMT_D24_UNORM_S8_UINT:
813 case WINED3DFMT_X8D24_UNORM:
814 *float_depth = depth / (float)0x00ffffff;
815 break;
817 case WINED3DFMT_D32_UNORM:
818 *float_depth = depth / (float)0xffffffff;
819 break;
821 default:
822 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
823 return FALSE;
826 return TRUE;
829 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
831 struct wined3d_resource *resource = &surface->container->resource;
832 struct wined3d_device *device = resource->device;
833 struct wined3d_rendertarget_view_desc view_desc;
834 struct wined3d_rendertarget_view *view;
835 const struct blit_shader *blitter;
836 HRESULT hr;
838 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
839 WINED3D_BLIT_OP_DEPTH_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
841 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
842 return WINED3DERR_INVALIDCALL;
845 view_desc.format_id = resource->format->id;
846 view_desc.u.texture.level_idx = surface->texture_level;
847 view_desc.u.texture.layer_idx = surface->texture_layer;
848 view_desc.u.texture.layer_count = 1;
849 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
850 resource, NULL, &wined3d_null_parent_ops, &view)))
852 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
853 return hr;
856 hr = blitter->depth_fill(device, view, rect, WINED3DCLEAR_ZBUFFER, depth, 0);
857 wined3d_rendertarget_view_decref(view);
859 return hr;
862 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
863 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
865 struct wined3d_texture *src_texture = src_surface->container;
866 struct wined3d_texture *dst_texture = dst_surface->container;
867 struct wined3d_device *device = src_texture->resource.device;
869 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
870 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
871 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
872 return WINED3DERR_INVALIDCALL;
874 surface_depth_blt_fbo(device, src_surface, src_location, src_rect, dst_surface, dst_location, dst_rect);
876 surface_modify_ds_location(dst_surface, dst_location,
877 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
879 return WINED3D_OK;
882 static ULONG surface_resource_incref(struct wined3d_resource *resource)
884 struct wined3d_surface *surface = surface_from_resource(resource);
886 TRACE("surface %p, container %p.\n", surface, surface->container);
888 return wined3d_texture_incref(surface->container);
891 static ULONG surface_resource_decref(struct wined3d_resource *resource)
893 struct wined3d_surface *surface = surface_from_resource(resource);
895 TRACE("surface %p, container %p.\n", surface, surface->container);
897 return wined3d_texture_decref(surface->container);
900 static void surface_unload(struct wined3d_resource *resource)
902 struct wined3d_surface *surface = surface_from_resource(resource);
903 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
904 struct wined3d_texture *texture = surface->container;
905 struct wined3d_renderbuffer_entry *entry, *entry2;
906 struct wined3d_device *device = resource->device;
907 const struct wined3d_gl_info *gl_info;
908 struct wined3d_context *context;
910 TRACE("surface %p.\n", surface);
912 context = context_acquire(device, NULL);
913 gl_info = context->gl_info;
915 if (resource->pool == WINED3D_POOL_DEFAULT)
917 /* Default pool resources are supposed to be destroyed before Reset is called.
918 * Implicit resources stay however. So this means we have an implicit render target
919 * or depth stencil. The content may be destroyed, but we still have to tear down
920 * opengl resources, so we cannot leave early.
922 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
923 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
924 * or the depth stencil into an FBO the texture or render buffer will be removed
925 * and all flags get lost */
926 if (resource->usage & WINED3DUSAGE_DEPTHSTENCIL)
928 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
929 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_DISCARDED);
931 else
933 surface_prepare_system_memory(surface);
934 memset(surface->resource.heap_memory, 0, surface->resource.size);
935 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
936 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_SYSMEM);
939 else
941 surface_load_location(surface, context, surface->resource.map_binding);
942 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~surface->resource.map_binding);
945 /* Destroy fbo render buffers. This is needed for implicit render targets, for
946 * all application-created targets the application has to release the surface
947 * before calling _Reset
949 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
951 context_gl_resource_released(device, entry->id, TRUE);
952 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
953 list_remove(&entry->entry);
954 HeapFree(GetProcessHeap(), 0, entry);
956 list_init(&surface->renderbuffers);
957 surface->current_renderbuffer = NULL;
959 if (surface->rb_multisample)
961 context_gl_resource_released(device, surface->rb_multisample, TRUE);
962 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
963 surface->rb_multisample = 0;
965 if (surface->rb_resolved)
967 context_gl_resource_released(device, surface->rb_resolved, TRUE);
968 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
969 surface->rb_resolved = 0;
972 context_release(context);
974 resource_unload(resource);
977 static HRESULT surface_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx,
978 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
980 ERR("Not supported on sub-resources.\n");
981 return WINED3DERR_INVALIDCALL;
984 static HRESULT surface_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
986 ERR("Not supported on sub-resources.\n");
987 return WINED3DERR_INVALIDCALL;
990 static const struct wined3d_resource_ops surface_resource_ops =
992 surface_resource_incref,
993 surface_resource_decref,
994 surface_unload,
995 surface_resource_sub_resource_map,
996 surface_resource_sub_resource_unmap,
999 /* This call just downloads data, the caller is responsible for binding the
1000 * correct texture. */
1001 /* Context activation is done by the caller. */
1002 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1003 DWORD dst_location)
1005 struct wined3d_texture *texture = surface->container;
1006 const struct wined3d_format *format = texture->resource.format;
1007 struct wined3d_bo_address data;
1009 /* Only support read back of converted P8 surfaces. */
1010 if (texture->flags & WINED3D_TEXTURE_CONVERTED && format->id != WINED3DFMT_P8_UINT)
1012 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
1013 return;
1016 surface_get_memory(surface, &data, dst_location);
1018 if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
1020 TRACE("(%p) : Calling glGetCompressedTexImage level %d, format %#x, type %#x, data %p.\n",
1021 surface, surface->texture_level, format->glFormat, format->glType, data.addr);
1023 if (data.buffer_object)
1025 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1026 checkGLcall("glBindBuffer");
1027 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target, surface->texture_level, NULL));
1028 checkGLcall("glGetCompressedTexImage");
1029 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1030 checkGLcall("glBindBuffer");
1032 else
1034 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target,
1035 surface->texture_level, data.addr));
1036 checkGLcall("glGetCompressedTexImage");
1039 else
1041 unsigned int dst_row_pitch, dst_slice_pitch;
1042 unsigned int src_row_pitch, src_slice_pitch;
1043 GLenum gl_format = format->glFormat;
1044 GLenum gl_type = format->glType;
1045 void *mem;
1047 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1049 wined3d_texture_get_pitch(texture, surface->texture_level, &dst_row_pitch, &dst_slice_pitch);
1050 wined3d_format_calculate_pitch(format, texture->resource.device->surface_alignment,
1051 surface->pow2Width, surface->pow2Height, &src_row_pitch, &src_slice_pitch);
1052 mem = HeapAlloc(GetProcessHeap(), 0, src_slice_pitch);
1054 else
1056 mem = data.addr;
1059 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1060 surface, surface->texture_level, gl_format, gl_type, mem);
1062 if (data.buffer_object)
1064 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1065 checkGLcall("glBindBuffer");
1067 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1068 gl_format, gl_type, NULL);
1069 checkGLcall("glGetTexImage");
1071 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1072 checkGLcall("glBindBuffer");
1074 else
1076 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1077 gl_format, gl_type, mem);
1078 checkGLcall("glGetTexImage");
1081 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1083 const BYTE *src_data;
1084 BYTE *dst_data;
1085 UINT y;
1087 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1088 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1089 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1091 * We're doing this...
1093 * instead of boxing the texture :
1094 * |<-texture width ->| -->pow2width| /\
1095 * |111111111111111111| | |
1096 * |222 Texture 222222| boxed empty | texture height
1097 * |3333 Data 33333333| | |
1098 * |444444444444444444| | \/
1099 * ----------------------------------- |
1100 * | boxed empty | boxed empty | pow2height
1101 * | | | \/
1102 * -----------------------------------
1105 * we're repacking the data to the expected texture width
1107 * |<-texture width ->| -->pow2width| /\
1108 * |111111111111111111222222222222222| |
1109 * |222333333333333333333444444444444| texture height
1110 * |444444 | |
1111 * | | \/
1112 * | | |
1113 * | empty | pow2height
1114 * | | \/
1115 * -----------------------------------
1117 * == is the same as
1119 * |<-texture width ->| /\
1120 * |111111111111111111|
1121 * |222222222222222222|texture height
1122 * |333333333333333333|
1123 * |444444444444444444| \/
1124 * --------------------
1126 * This also means that any references to surface memory should work with the data as if it were a
1127 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1129 * internally the texture is still stored in a boxed format so any references to textureName will
1130 * get a boxed texture with width pow2width and not a texture of width resource.width. */
1131 src_data = mem;
1132 dst_data = data.addr;
1133 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch);
1134 for (y = 0; y < surface->resource.height; ++y)
1136 memcpy(dst_data, src_data, dst_row_pitch);
1137 src_data += src_row_pitch;
1138 dst_data += dst_row_pitch;
1141 HeapFree(GetProcessHeap(), 0, mem);
1146 /* This call just uploads data, the caller is responsible for binding the
1147 * correct texture. */
1148 /* Context activation is done by the caller. */
1149 void wined3d_surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1150 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
1151 BOOL srgb, const struct wined3d_const_bo_address *data)
1153 struct wined3d_texture *texture = surface->container;
1154 UINT update_w = src_rect->right - src_rect->left;
1155 UINT update_h = src_rect->bottom - src_rect->top;
1157 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1158 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
1159 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
1161 if (surface->resource.map_count)
1163 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1164 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
1167 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
1169 update_h *= format->height_scale.numerator;
1170 update_h /= format->height_scale.denominator;
1173 if (data->buffer_object)
1175 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, data->buffer_object));
1176 checkGLcall("glBindBuffer");
1179 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1181 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1, 1);
1182 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
1183 const BYTE *addr = data->addr;
1184 GLenum internal;
1186 addr += (src_rect->top / format->block_height) * src_pitch;
1187 addr += (src_rect->left / format->block_width) * format->block_byte_count;
1189 if (srgb)
1190 internal = format->glGammaInternal;
1191 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET
1192 && wined3d_resource_is_offscreen(&texture->resource))
1193 internal = format->rtInternal;
1194 else
1195 internal = format->glInternal;
1197 TRACE("glCompressedTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, "
1198 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
1199 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
1201 if (row_length == src_pitch)
1203 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1204 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
1206 else
1208 UINT row, y;
1210 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1211 * can't use the unpack row length like for glTexSubImage2D. */
1212 for (row = 0, y = dst_point->y; row < row_count; ++row)
1214 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1215 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
1216 y += format->block_height;
1217 addr += src_pitch;
1220 checkGLcall("glCompressedTexSubImage2D");
1222 else
1224 const BYTE *addr = data->addr;
1226 addr += src_rect->top * src_pitch;
1227 addr += src_rect->left * format->byte_count;
1229 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1230 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
1231 update_w, update_h, format->glFormat, format->glType, addr);
1233 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
1234 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
1235 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
1236 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1237 checkGLcall("glTexSubImage2D");
1240 if (data->buffer_object)
1242 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1243 checkGLcall("glBindBuffer");
1246 if (wined3d_settings.strict_draw_ordering)
1247 gl_info->gl_ops.gl.p_glFlush();
1249 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1251 struct wined3d_device *device = texture->resource.device;
1252 unsigned int i;
1254 for (i = 0; i < device->context_count; ++i)
1256 context_surface_update(device->contexts[i], surface);
1261 static BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
1263 struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
1265 return wined3d_texture_check_block_align(surface->container, surface->texture_level, &box);
1268 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
1269 struct wined3d_surface *src_surface, const RECT *src_rect)
1271 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1272 struct wined3d_texture *src_texture = src_surface->container;
1273 struct wined3d_texture *dst_texture = dst_surface->container;
1274 unsigned int src_row_pitch, src_slice_pitch;
1275 const struct wined3d_format *src_format;
1276 const struct wined3d_format *dst_format;
1277 unsigned int src_fmt_flags, dst_fmt_flags;
1278 const struct wined3d_gl_info *gl_info;
1279 struct wined3d_context *context;
1280 struct wined3d_bo_address data;
1281 UINT update_w, update_h;
1282 UINT dst_w, dst_h;
1283 RECT r, dst_rect;
1284 POINT p;
1286 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1287 dst_surface, wine_dbgstr_point(dst_point),
1288 src_surface, wine_dbgstr_rect(src_rect));
1290 src_format = src_texture->resource.format;
1291 dst_format = dst_texture->resource.format;
1292 src_fmt_flags = src_texture->resource.format_flags;
1293 dst_fmt_flags = dst_texture->resource.format_flags;
1295 if (src_format->id != dst_format->id)
1297 WARN("Source and destination surfaces should have the same format.\n");
1298 return WINED3DERR_INVALIDCALL;
1301 if (!dst_point)
1303 p.x = 0;
1304 p.y = 0;
1305 dst_point = &p;
1307 else if (dst_point->x < 0 || dst_point->y < 0)
1309 WARN("Invalid destination point.\n");
1310 return WINED3DERR_INVALIDCALL;
1313 if (!src_rect)
1315 SetRect(&r, 0, 0, src_surface->resource.width, src_surface->resource.height);
1316 src_rect = &r;
1318 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
1319 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
1321 WARN("Invalid source rectangle.\n");
1322 return WINED3DERR_INVALIDCALL;
1325 dst_w = dst_surface->resource.width;
1326 dst_h = dst_surface->resource.height;
1328 update_w = src_rect->right - src_rect->left;
1329 update_h = src_rect->bottom - src_rect->top;
1331 if (update_w > dst_w || dst_point->x > dst_w - update_w
1332 || update_h > dst_h || dst_point->y > dst_h - update_h)
1334 WARN("Destination out of bounds.\n");
1335 return WINED3DERR_INVALIDCALL;
1338 if ((src_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(src_surface, src_rect))
1340 WARN("Source rectangle not block-aligned.\n");
1341 return WINED3DERR_INVALIDCALL;
1344 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
1345 if ((dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(dst_surface, &dst_rect))
1347 WARN("Destination rectangle not block-aligned.\n");
1348 return WINED3DERR_INVALIDCALL;
1351 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1352 if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_texture, FALSE))
1353 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
1355 context = context_acquire(dst_texture->resource.device, NULL);
1356 gl_info = context->gl_info;
1358 /* Only load the surface for partial updates. For newly allocated texture
1359 * the texture wouldn't be the current location, and we'd upload zeroes
1360 * just to overwrite them again. */
1361 if (update_w == dst_w && update_h == dst_h)
1362 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1363 else
1364 surface_load_location(dst_surface, context, WINED3D_LOCATION_TEXTURE_RGB);
1365 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1367 surface_get_memory(src_surface, &data, surface_get_sub_resource(src_surface)->locations);
1368 wined3d_texture_get_pitch(src_texture, src_surface->texture_level, &src_row_pitch, &src_slice_pitch);
1370 wined3d_surface_upload_data(dst_surface, gl_info, src_format, src_rect,
1371 src_row_pitch, dst_point, FALSE, wined3d_const_bo_address(&data));
1373 context_release(context);
1375 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1376 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1378 return WINED3D_OK;
1381 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1382 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1383 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1384 /* Context activation is done by the caller. */
1385 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
1387 const struct wined3d_gl_info *gl_info = &surface->container->resource.device->adapter->gl_info;
1388 struct wined3d_renderbuffer_entry *entry;
1389 GLuint renderbuffer = 0;
1390 unsigned int src_width, src_height;
1391 unsigned int width, height;
1393 if (rt && rt->container->resource.format->id != WINED3DFMT_NULL)
1395 width = rt->pow2Width;
1396 height = rt->pow2Height;
1398 else
1400 width = surface->pow2Width;
1401 height = surface->pow2Height;
1404 src_width = surface->pow2Width;
1405 src_height = surface->pow2Height;
1407 /* A depth stencil smaller than the render target is not valid */
1408 if (width > src_width || height > src_height) return;
1410 /* Remove any renderbuffer set if the sizes match */
1411 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1412 || (width == src_width && height == src_height))
1414 surface->current_renderbuffer = NULL;
1415 return;
1418 /* Look if we've already got a renderbuffer of the correct dimensions */
1419 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1421 if (entry->width == width && entry->height == height)
1423 renderbuffer = entry->id;
1424 surface->current_renderbuffer = entry;
1425 break;
1429 if (!renderbuffer)
1431 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1432 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1433 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1434 surface->container->resource.format->glInternal, width, height);
1436 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
1437 entry->width = width;
1438 entry->height = height;
1439 entry->id = renderbuffer;
1440 list_add_head(&surface->renderbuffers, &entry->entry);
1442 surface->current_renderbuffer = entry;
1445 checkGLcall("set_compatible_renderbuffer");
1448 /* Context activation is done by the caller. */
1449 void surface_load(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
1451 DWORD location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1453 TRACE("surface %p, srgb %#x.\n", surface, srgb);
1455 if (surface->container->resource.pool == WINED3D_POOL_SCRATCH)
1456 ERR("Not supported on scratch surfaces.\n");
1458 if (surface_get_sub_resource(surface)->locations & location)
1460 TRACE("surface is already in texture\n");
1461 return;
1463 TRACE("Reloading because surface is dirty.\n");
1465 surface_load_location(surface, context, location);
1466 surface_evict_sysmem(surface);
1469 /* See also float_16_to_32() in wined3d_private.h */
1470 static inline unsigned short float_32_to_16(const float *in)
1472 int exp = 0;
1473 float tmp = fabsf(*in);
1474 unsigned int mantissa;
1475 unsigned short ret;
1477 /* Deal with special numbers */
1478 if (*in == 0.0f)
1479 return 0x0000;
1480 if (isnan(*in))
1481 return 0x7c01;
1482 if (isinf(*in))
1483 return (*in < 0.0f ? 0xfc00 : 0x7c00);
1485 if (tmp < (float)(1u << 10))
1489 tmp = tmp * 2.0f;
1490 exp--;
1491 } while (tmp < (float)(1u << 10));
1493 else if (tmp >= (float)(1u << 11))
1497 tmp /= 2.0f;
1498 exp++;
1499 } while (tmp >= (float)(1u << 11));
1502 mantissa = (unsigned int)tmp;
1503 if (tmp - mantissa >= 0.5f)
1504 ++mantissa; /* Round to nearest, away from zero. */
1506 exp += 10; /* Normalize the mantissa. */
1507 exp += 15; /* Exponent is encoded with excess 15. */
1509 if (exp > 30) /* too big */
1511 ret = 0x7c00; /* INF */
1513 else if (exp <= 0)
1515 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1516 while (exp <= 0)
1518 mantissa = mantissa >> 1;
1519 ++exp;
1521 ret = mantissa & 0x3ff;
1523 else
1525 ret = (exp << 10) | (mantissa & 0x3ff);
1528 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
1529 return ret;
1532 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
1533 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1535 unsigned short *dst_s;
1536 const float *src_f;
1537 unsigned int x, y;
1539 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1541 for (y = 0; y < h; ++y)
1543 src_f = (const float *)(src + y * pitch_in);
1544 dst_s = (unsigned short *) (dst + y * pitch_out);
1545 for (x = 0; x < w; ++x)
1547 dst_s[x] = float_32_to_16(src_f + x);
1552 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
1553 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1555 static const unsigned char convert_5to8[] =
1557 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1558 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1559 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1560 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1562 static const unsigned char convert_6to8[] =
1564 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1565 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1566 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1567 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1568 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1569 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1570 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1571 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1573 unsigned int x, y;
1575 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1577 for (y = 0; y < h; ++y)
1579 const WORD *src_line = (const WORD *)(src + y * pitch_in);
1580 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1581 for (x = 0; x < w; ++x)
1583 WORD pixel = src_line[x];
1584 dst_line[x] = 0xff000000u
1585 | convert_5to8[(pixel & 0xf800u) >> 11] << 16
1586 | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
1587 | convert_5to8[(pixel & 0x001fu)];
1592 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1593 * in both cases we're just setting the X / Alpha channel to 0xff. */
1594 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
1595 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1597 unsigned int x, y;
1599 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1601 for (y = 0; y < h; ++y)
1603 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
1604 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1606 for (x = 0; x < w; ++x)
1608 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
1613 static inline BYTE cliptobyte(int x)
1615 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
1618 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
1619 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1621 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1622 unsigned int x, y;
1624 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1626 for (y = 0; y < h; ++y)
1628 const BYTE *src_line = src + y * pitch_in;
1629 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1630 for (x = 0; x < w; ++x)
1632 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1633 * C = Y - 16; D = U - 128; E = V - 128;
1634 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1635 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1636 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1637 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1638 * U and V are shared between the pixels. */
1639 if (!(x & 1)) /* For every even pixel, read new U and V. */
1641 d = (int) src_line[1] - 128;
1642 e = (int) src_line[3] - 128;
1643 r2 = 409 * e + 128;
1644 g2 = - 100 * d - 208 * e + 128;
1645 b2 = 516 * d + 128;
1647 c2 = 298 * ((int) src_line[0] - 16);
1648 dst_line[x] = 0xff000000
1649 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
1650 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
1651 | cliptobyte((c2 + b2) >> 8); /* blue */
1652 /* Scale RGB values to 0..255 range,
1653 * then clip them if still not in range (may be negative),
1654 * then shift them within DWORD if necessary. */
1655 src_line += 2;
1660 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
1661 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1663 unsigned int x, y;
1664 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1666 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
1668 for (y = 0; y < h; ++y)
1670 const BYTE *src_line = src + y * pitch_in;
1671 WORD *dst_line = (WORD *)(dst + y * pitch_out);
1672 for (x = 0; x < w; ++x)
1674 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1675 * C = Y - 16; D = U - 128; E = V - 128;
1676 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1677 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1678 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1679 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1680 * U and V are shared between the pixels. */
1681 if (!(x & 1)) /* For every even pixel, read new U and V. */
1683 d = (int) src_line[1] - 128;
1684 e = (int) src_line[3] - 128;
1685 r2 = 409 * e + 128;
1686 g2 = - 100 * d - 208 * e + 128;
1687 b2 = 516 * d + 128;
1689 c2 = 298 * ((int) src_line[0] - 16);
1690 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
1691 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
1692 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
1693 /* Scale RGB values to 0..255 range,
1694 * then clip them if still not in range (may be negative),
1695 * then shift them within DWORD if necessary. */
1696 src_line += 2;
1701 struct d3dfmt_converter_desc
1703 enum wined3d_format_id from, to;
1704 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
1707 static const struct d3dfmt_converter_desc converters[] =
1709 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
1710 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
1711 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1712 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1713 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
1714 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
1717 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
1718 enum wined3d_format_id to)
1720 unsigned int i;
1722 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
1724 if (converters[i].from == from && converters[i].to == to)
1725 return &converters[i];
1728 return NULL;
1731 static struct wined3d_texture *surface_convert_format(struct wined3d_texture *src_texture,
1732 unsigned int sub_resource_idx, enum wined3d_format_id format)
1734 struct wined3d_map_desc src_map, dst_map;
1735 const struct d3dfmt_converter_desc *conv;
1736 struct wined3d_texture *dst_texture;
1737 struct wined3d_resource_desc desc;
1739 if (!(conv = find_converter(src_texture->resource.format->id, format)))
1741 FIXME("Cannot find a conversion function from format %s to %s.\n",
1742 debug_d3dformat(src_texture->resource.format->id), debug_d3dformat(format));
1743 return NULL;
1746 /* FIXME: Multisampled conversion? */
1747 wined3d_resource_get_desc(src_texture->sub_resources[sub_resource_idx].resource, &desc);
1748 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1749 desc.format = format;
1750 desc.usage = 0;
1751 desc.pool = WINED3D_POOL_SCRATCH;
1752 if (FAILED(wined3d_texture_create(src_texture->resource.device, &desc, 1,
1753 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
1754 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
1756 ERR("Failed to create a destination texture for conversion.\n");
1757 return NULL;
1760 memset(&src_map, 0, sizeof(src_map));
1761 memset(&dst_map, 0, sizeof(dst_map));
1763 if (FAILED(wined3d_resource_map(&src_texture->resource, sub_resource_idx,
1764 &src_map, NULL, WINED3D_MAP_READONLY)))
1766 ERR("Failed to map the source texture.\n");
1767 wined3d_texture_decref(dst_texture);
1768 return NULL;
1770 if (FAILED(wined3d_resource_map(&dst_texture->resource, 0, &dst_map, NULL, 0)))
1772 ERR("Failed to map the destination texture.\n");
1773 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1774 wined3d_texture_decref(dst_texture);
1775 return NULL;
1778 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch, desc.width, desc.height);
1780 wined3d_resource_unmap(&dst_texture->resource, 0);
1781 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1783 return dst_texture;
1786 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
1787 unsigned int bpp, UINT pitch, DWORD color)
1789 BYTE *first;
1790 unsigned int x, y;
1792 /* Do first row */
1794 #define COLORFILL_ROW(type) \
1795 do { \
1796 type *d = (type *)buf; \
1797 for (x = 0; x < width; ++x) \
1798 d[x] = (type)color; \
1799 } while(0)
1801 switch (bpp)
1803 case 1:
1804 COLORFILL_ROW(BYTE);
1805 break;
1807 case 2:
1808 COLORFILL_ROW(WORD);
1809 break;
1811 case 3:
1813 BYTE *d = buf;
1814 for (x = 0; x < width; ++x, d += 3)
1816 d[0] = (color ) & 0xff;
1817 d[1] = (color >> 8) & 0xff;
1818 d[2] = (color >> 16) & 0xff;
1820 break;
1822 case 4:
1823 COLORFILL_ROW(DWORD);
1824 break;
1826 default:
1827 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
1828 return WINED3DERR_NOTAVAILABLE;
1831 #undef COLORFILL_ROW
1833 /* Now copy first row. */
1834 first = buf;
1835 for (y = 1; y < height; ++y)
1837 buf += pitch;
1838 memcpy(buf, first, width * bpp);
1841 return WINED3D_OK;
1844 static void read_from_framebuffer(struct wined3d_surface *surface,
1845 struct wined3d_context *old_ctx, DWORD dst_location)
1847 struct wined3d_texture *texture = surface->container;
1848 struct wined3d_device *device = texture->resource.device;
1849 const struct wined3d_gl_info *gl_info;
1850 struct wined3d_context *context = old_ctx;
1851 struct wined3d_surface *restore_rt = NULL;
1852 unsigned int row_pitch, slice_pitch;
1853 BYTE *mem;
1854 BYTE *row, *top, *bottom;
1855 int i;
1856 BOOL srcIsUpsideDown;
1857 struct wined3d_bo_address data;
1859 surface_get_memory(surface, &data, dst_location);
1861 restore_rt = context_get_rt_surface(old_ctx);
1862 if (restore_rt != surface)
1863 context = context_acquire(device, surface);
1864 else
1865 restore_rt = NULL;
1867 context_apply_blit_state(context, device);
1868 gl_info = context->gl_info;
1870 /* Select the correct read buffer, and give some debug output.
1871 * There is no need to keep track of the current read buffer or reset it, every part of the code
1872 * that reads sets the read buffer as desired.
1874 if (wined3d_resource_is_offscreen(&texture->resource))
1876 /* Mapping the primary render target which is not on a swapchain.
1877 * Read from the back buffer. */
1878 TRACE("Mapping offscreen render target.\n");
1879 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1880 srcIsUpsideDown = TRUE;
1882 else
1884 /* Onscreen surfaces are always part of a swapchain */
1885 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
1886 TRACE("Mapping %#x buffer.\n", buffer);
1887 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1888 checkGLcall("glReadBuffer");
1889 srcIsUpsideDown = FALSE;
1892 if (data.buffer_object)
1894 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1895 checkGLcall("glBindBuffer");
1898 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
1900 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1901 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / texture->resource.format->byte_count);
1902 checkGLcall("glPixelStorei");
1904 gl_info->gl_ops.gl.p_glReadPixels(0, 0,
1905 surface->resource.width, surface->resource.height,
1906 texture->resource.format->glFormat,
1907 texture->resource.format->glType, data.addr);
1908 checkGLcall("glReadPixels");
1910 /* Reset previous pixel store pack state */
1911 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1912 checkGLcall("glPixelStorei");
1914 if (!srcIsUpsideDown)
1916 /* glReadPixels returns the image upside down, and there is no way to
1917 * prevent this. Flip the lines in software. */
1919 if (!(row = HeapAlloc(GetProcessHeap(), 0, row_pitch)))
1920 goto error;
1922 if (data.buffer_object)
1924 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
1925 checkGLcall("glMapBuffer");
1927 else
1928 mem = data.addr;
1930 top = mem;
1931 bottom = mem + row_pitch * (surface->resource.height - 1);
1932 for (i = 0; i < surface->resource.height / 2; i++)
1934 memcpy(row, top, row_pitch);
1935 memcpy(top, bottom, row_pitch);
1936 memcpy(bottom, row, row_pitch);
1937 top += row_pitch;
1938 bottom -= row_pitch;
1940 HeapFree(GetProcessHeap(), 0, row);
1942 if (data.buffer_object)
1943 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
1946 error:
1947 if (data.buffer_object)
1949 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1950 checkGLcall("glBindBuffer");
1953 if (restore_rt)
1954 context_restore(context, restore_rt);
1957 /* Read the framebuffer contents into a texture. Note that this function
1958 * doesn't do any kind of flipping. Using this on an onscreen surface will
1959 * result in a flipped D3D texture.
1961 * Context activation is done by the caller. This function may temporarily
1962 * switch to a different context and restore the original one before return. */
1963 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct wined3d_context *old_ctx)
1965 struct wined3d_texture *texture = surface->container;
1966 struct wined3d_device *device = texture->resource.device;
1967 const struct wined3d_gl_info *gl_info;
1968 struct wined3d_context *context = old_ctx;
1969 struct wined3d_surface *restore_rt = NULL;
1971 restore_rt = context_get_rt_surface(old_ctx);
1972 if (restore_rt != surface)
1973 context = context_acquire(device, surface);
1974 else
1975 restore_rt = NULL;
1977 gl_info = context->gl_info;
1978 device_invalidate_state(device, STATE_FRAMEBUFFER);
1980 wined3d_texture_prepare_texture(texture, context, srgb);
1981 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1983 TRACE("Reading back offscreen render target %p.\n", surface);
1985 if (wined3d_resource_is_offscreen(&texture->resource))
1986 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1987 else
1988 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
1989 checkGLcall("glReadBuffer");
1991 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
1992 0, 0, 0, 0, surface->resource.width, surface->resource.height);
1993 checkGLcall("glCopyTexSubImage2D");
1995 if (restore_rt)
1996 context_restore(context, restore_rt);
1999 static void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
2001 struct wined3d_texture *texture = surface->container;
2002 const struct wined3d_format *format = texture->resource.format;
2004 if (multisample)
2006 DWORD samples;
2008 if (surface->rb_multisample)
2009 return;
2011 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
2012 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
2013 * to GL_NV_framebuffer_multisample_coverage.
2015 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
2016 * but it does not have an equivalent OpenGL extension. */
2018 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
2019 * as the count of advertised multisample types for the surface format. */
2020 if (texture->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE)
2022 unsigned int i, count = 0;
2024 for (i = 0; i < sizeof(format->multisample_types) * 8; ++i)
2026 if (format->multisample_types & 1u << i)
2028 if (texture->resource.multisample_quality == count++)
2029 break;
2032 samples = i + 1;
2034 else
2036 samples = texture->resource.multisample_type;
2039 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
2040 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
2041 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
2042 format->glInternal, surface->pow2Width, surface->pow2Height);
2043 checkGLcall("glRenderbufferStorageMultisample()");
2044 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
2046 else
2048 if (surface->rb_resolved)
2049 return;
2051 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
2052 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
2053 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format->glInternal,
2054 surface->pow2Width, surface->pow2Height);
2055 checkGLcall("glRenderbufferStorage()");
2056 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
2060 /* Does a direct frame buffer -> texture copy. Stretching is done with single
2061 * pixel copy calls. */
2062 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2063 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2065 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2066 struct wined3d_texture *src_texture = src_surface->container;
2067 struct wined3d_texture *dst_texture = dst_surface->container;
2068 struct wined3d_device *device = dst_texture->resource.device;
2069 const struct wined3d_gl_info *gl_info;
2070 float xrel, yrel;
2071 struct wined3d_context *context;
2072 BOOL upsidedown = FALSE;
2073 RECT dst_rect = *dst_rect_in;
2075 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2076 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2078 if(dst_rect.top > dst_rect.bottom) {
2079 UINT tmp = dst_rect.bottom;
2080 dst_rect.bottom = dst_rect.top;
2081 dst_rect.top = tmp;
2082 upsidedown = TRUE;
2085 context = context_acquire(device, src_surface);
2086 gl_info = context->gl_info;
2087 context_apply_blit_state(context, device);
2088 wined3d_texture_load(dst_texture, context, FALSE);
2090 /* Bind the target texture */
2091 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
2092 if (wined3d_resource_is_offscreen(&src_texture->resource))
2094 TRACE("Reading from an offscreen target\n");
2095 upsidedown = !upsidedown;
2096 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
2098 else
2100 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2102 checkGLcall("glReadBuffer");
2104 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
2105 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
2107 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2109 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2111 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2112 ERR("Texture filtering not supported in direct blit.\n");
2114 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2115 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2117 ERR("Texture filtering not supported in direct blit\n");
2120 if (upsidedown
2121 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2122 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2124 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
2125 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2126 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
2127 src_rect->left, src_surface->resource.height - src_rect->bottom,
2128 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2130 else
2132 LONG row;
2133 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
2134 /* I have to process this row by row to swap the image,
2135 * otherwise it would be upside down, so stretching in y direction
2136 * doesn't cost extra time
2138 * However, stretching in x direction can be avoided if not necessary
2140 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
2141 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2143 /* Well, that stuff works, but it's very slow.
2144 * find a better way instead
2146 LONG col;
2148 for (col = dst_rect.left; col < dst_rect.right; ++col)
2150 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2151 dst_rect.left + col /* x offset */, row /* y offset */,
2152 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
2155 else
2157 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2158 dst_rect.left /* x offset */, row /* y offset */,
2159 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
2163 checkGLcall("glCopyTexSubImage2D");
2165 context_release(context);
2167 /* The texture is now most up to date - If the surface is a render target
2168 * and has a drawable, this path is never entered. */
2169 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2170 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2173 /* Uses the hardware to stretch and flip the image */
2174 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2175 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2177 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2178 struct wined3d_texture *src_texture = src_surface->container;
2179 struct wined3d_texture *dst_texture = dst_surface->container;
2180 struct wined3d_device *device = dst_texture->resource.device;
2181 GLuint src, backup = 0;
2182 float left, right, top, bottom; /* Texture coordinates */
2183 UINT fbwidth = src_surface->resource.width;
2184 UINT fbheight = src_surface->resource.height;
2185 const struct wined3d_gl_info *gl_info;
2186 struct wined3d_context *context;
2187 GLenum drawBuffer = GL_BACK;
2188 GLenum offscreen_buffer;
2189 GLenum texture_target;
2190 BOOL noBackBufferBackup;
2191 BOOL src_offscreen;
2192 BOOL upsidedown = FALSE;
2193 RECT dst_rect = *dst_rect_in;
2195 TRACE("Using hwstretch blit\n");
2196 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2197 context = context_acquire(device, src_surface);
2198 gl_info = context->gl_info;
2199 context_apply_blit_state(context, device);
2200 wined3d_texture_load(dst_texture, context, FALSE);
2202 offscreen_buffer = context_get_offscreen_gl_buffer(context);
2204 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
2205 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
2206 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
2208 /* Get it a description */
2209 wined3d_texture_load(src_texture, context, FALSE);
2212 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2213 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2215 if (context->aux_buffers >= 2)
2217 /* Got more than one aux buffer? Use the 2nd aux buffer */
2218 drawBuffer = GL_AUX1;
2220 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
2222 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2223 drawBuffer = GL_AUX0;
2226 if (noBackBufferBackup)
2228 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
2229 checkGLcall("glGenTextures");
2230 context_bind_texture(context, GL_TEXTURE_2D, backup);
2231 texture_target = GL_TEXTURE_2D;
2233 else
2235 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2236 * we are reading from the back buffer, the backup can be used as source texture
2238 texture_target = src_surface->texture_target;
2239 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
2240 gl_info->gl_ops.gl.p_glEnable(texture_target);
2241 checkGLcall("glEnable(texture_target)");
2243 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2244 surface_get_sub_resource(src_surface)->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
2247 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2248 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2250 if(dst_rect.top > dst_rect.bottom) {
2251 UINT tmp = dst_rect.bottom;
2252 dst_rect.bottom = dst_rect.top;
2253 dst_rect.top = tmp;
2254 upsidedown = TRUE;
2257 if (src_offscreen)
2259 TRACE("Reading from an offscreen target\n");
2260 upsidedown = !upsidedown;
2261 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
2263 else
2265 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2268 /* TODO: Only back up the part that will be overwritten */
2269 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
2271 checkGLcall("glCopyTexSubImage2D");
2273 /* No issue with overriding these - the sampler is dirty due to blit usage */
2274 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
2275 checkGLcall("glTexParameteri");
2276 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2277 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
2278 checkGLcall("glTexParameteri");
2280 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
2282 src = backup ? backup : src_texture->texture_rgb.name;
2284 else
2286 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
2287 checkGLcall("glReadBuffer(GL_FRONT)");
2289 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
2290 checkGLcall("glGenTextures(1, &src)");
2291 context_bind_texture(context, GL_TEXTURE_2D, src);
2293 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
2294 * out for power of 2 sizes
2296 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
2297 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2298 checkGLcall("glTexImage2D");
2299 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
2301 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2302 checkGLcall("glTexParameteri");
2303 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2304 checkGLcall("glTexParameteri");
2306 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
2307 checkGLcall("glReadBuffer(GL_BACK)");
2309 if (texture_target != GL_TEXTURE_2D)
2311 gl_info->gl_ops.gl.p_glDisable(texture_target);
2312 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2313 texture_target = GL_TEXTURE_2D;
2316 checkGLcall("glEnd and previous");
2318 left = src_rect->left;
2319 right = src_rect->right;
2321 if (!upsidedown)
2323 top = src_surface->resource.height - src_rect->top;
2324 bottom = src_surface->resource.height - src_rect->bottom;
2326 else
2328 top = src_surface->resource.height - src_rect->bottom;
2329 bottom = src_surface->resource.height - src_rect->top;
2332 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
2334 left /= src_surface->pow2Width;
2335 right /= src_surface->pow2Width;
2336 top /= src_surface->pow2Height;
2337 bottom /= src_surface->pow2Height;
2340 /* draw the source texture stretched and upside down. The correct surface is bound already */
2341 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2342 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2344 context_set_draw_buffer(context, drawBuffer);
2345 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
2347 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2348 /* bottom left */
2349 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
2350 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2352 /* top left */
2353 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
2354 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
2356 /* top right */
2357 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
2358 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2360 /* bottom right */
2361 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
2362 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
2363 gl_info->gl_ops.gl.p_glEnd();
2364 checkGLcall("glEnd and previous");
2366 if (texture_target != dst_surface->texture_target)
2368 gl_info->gl_ops.gl.p_glDisable(texture_target);
2369 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
2370 texture_target = dst_surface->texture_target;
2373 /* Now read the stretched and upside down image into the destination texture */
2374 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
2375 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
2377 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
2378 0, 0, /* We blitted the image to the origin */
2379 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2380 checkGLcall("glCopyTexSubImage2D");
2382 if (drawBuffer == GL_BACK)
2384 /* Write the back buffer backup back. */
2385 if (backup)
2387 if (texture_target != GL_TEXTURE_2D)
2389 gl_info->gl_ops.gl.p_glDisable(texture_target);
2390 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2391 texture_target = GL_TEXTURE_2D;
2393 context_bind_texture(context, GL_TEXTURE_2D, backup);
2395 else
2397 if (texture_target != src_surface->texture_target)
2399 gl_info->gl_ops.gl.p_glDisable(texture_target);
2400 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
2401 texture_target = src_surface->texture_target;
2403 context_bind_texture(context, src_surface->texture_target, src_texture->texture_rgb.name);
2406 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2407 /* top left */
2408 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
2409 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
2411 /* bottom left */
2412 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
2413 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2415 /* bottom right */
2416 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
2417 (float)fbheight / (float)src_surface->pow2Height);
2418 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
2420 /* top right */
2421 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
2422 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
2423 gl_info->gl_ops.gl.p_glEnd();
2425 gl_info->gl_ops.gl.p_glDisable(texture_target);
2426 checkGLcall("glDisable(texture_target)");
2428 /* Cleanup */
2429 if (src != src_texture->texture_rgb.name && src != backup)
2431 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
2432 checkGLcall("glDeleteTextures(1, &src)");
2434 if (backup)
2436 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
2437 checkGLcall("glDeleteTextures(1, &backup)");
2440 if (wined3d_settings.strict_draw_ordering)
2441 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2443 context_release(context);
2445 /* The texture is now most up to date - If the surface is a render target
2446 * and has a drawable, this path is never entered. */
2447 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2448 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2451 /* Front buffer coordinates are always full screen coordinates, but our GL
2452 * drawable is limited to the window's client area. The sysmem and texture
2453 * copies do have the full screen size. Note that GL has a bottom-left
2454 * origin, while D3D has a top-left origin. */
2455 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
2457 UINT drawable_height;
2459 if (surface->container->swapchain && surface->container == surface->container->swapchain->front_buffer)
2461 POINT offset = {0, 0};
2462 RECT windowsize;
2464 ScreenToClient(window, &offset);
2465 OffsetRect(rect, offset.x, offset.y);
2467 GetClientRect(window, &windowsize);
2468 drawable_height = windowsize.bottom - windowsize.top;
2470 else
2472 drawable_height = surface->resource.height;
2475 rect->top = drawable_height - rect->top;
2476 rect->bottom = drawable_height - rect->bottom;
2479 /* Context activation is done by the caller. */
2480 static void surface_blt_to_drawable(const struct wined3d_device *device,
2481 struct wined3d_context *old_ctx,
2482 enum wined3d_texture_filter_type filter, BOOL alpha_test,
2483 struct wined3d_surface *src_surface, const RECT *src_rect_in,
2484 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
2486 struct wined3d_texture *src_texture = src_surface->container;
2487 struct wined3d_texture *dst_texture = dst_surface->container;
2488 const struct wined3d_gl_info *gl_info;
2489 struct wined3d_context *context = old_ctx;
2490 struct wined3d_surface *restore_rt = NULL;
2491 RECT src_rect, dst_rect;
2493 src_rect = *src_rect_in;
2494 dst_rect = *dst_rect_in;
2496 restore_rt = context_get_rt_surface(old_ctx);
2497 if (restore_rt != dst_surface)
2498 context = context_acquire(device, dst_surface);
2499 else
2500 restore_rt = NULL;
2502 gl_info = context->gl_info;
2504 /* Make sure the surface is up-to-date. This should probably use
2505 * surface_load_location() and worry about the destination surface too,
2506 * unless we're overwriting it completely. */
2507 wined3d_texture_load(src_texture, context, FALSE);
2509 /* Activate the destination context, set it up for blitting */
2510 context_apply_blit_state(context, device);
2512 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
2513 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
2515 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
2517 if (alpha_test)
2519 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2520 checkGLcall("glEnable(GL_ALPHA_TEST)");
2522 /* For P8 surfaces, the alpha component contains the palette index.
2523 * Which means that the colorkey is one of the palette entries. In
2524 * other cases pixels that should be masked away have alpha set to 0. */
2525 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2526 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2527 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2528 else
2529 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2530 checkGLcall("glAlphaFunc");
2532 else
2534 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2535 checkGLcall("glDisable(GL_ALPHA_TEST)");
2538 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
2540 if (alpha_test)
2542 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2543 checkGLcall("glDisable(GL_ALPHA_TEST)");
2546 /* Leave the opengl state valid for blitting */
2547 device->blitter->unset_shader(context->gl_info);
2549 if (wined3d_settings.strict_draw_ordering
2550 || (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture))
2551 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2553 if (restore_rt)
2554 context_restore(context, restore_rt);
2557 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
2559 struct wined3d_resource *resource = &s->container->resource;
2560 struct wined3d_device *device = resource->device;
2561 struct wined3d_rendertarget_view_desc view_desc;
2562 struct wined3d_rendertarget_view *view;
2563 const struct blit_shader *blitter;
2564 HRESULT hr;
2566 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
2567 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
2569 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2570 return WINED3DERR_INVALIDCALL;
2573 view_desc.format_id = resource->format->id;
2574 view_desc.u.texture.level_idx = s->texture_level;
2575 view_desc.u.texture.layer_idx = s->texture_layer;
2576 view_desc.u.texture.layer_count = 1;
2577 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
2578 resource, NULL, &wined3d_null_parent_ops, &view)))
2580 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
2581 return hr;
2584 hr = blitter->color_fill(device, view, rect, color);
2585 wined3d_rendertarget_view_decref(view);
2587 return hr;
2590 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
2591 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
2592 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2594 struct wined3d_texture *dst_texture = dst_surface->container;
2595 struct wined3d_device *device = dst_texture->resource.device;
2596 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
2597 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
2598 struct wined3d_texture *src_texture;
2600 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2601 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2602 flags, fx, debug_d3dtexturefiltertype(filter));
2604 /* Get the swapchain. One of the surfaces has to be a primary surface */
2605 if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2607 WARN("Destination is in sysmem, rejecting gl blt\n");
2608 return WINED3DERR_INVALIDCALL;
2611 dst_swapchain = dst_texture->swapchain;
2613 if (src_surface)
2615 src_texture = src_surface->container;
2616 if (src_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2618 WARN("Src is in sysmem, rejecting gl blt\n");
2619 return WINED3DERR_INVALIDCALL;
2622 src_swapchain = src_texture->swapchain;
2624 else
2626 src_texture = NULL;
2627 src_swapchain = NULL;
2630 /* Early sort out of cases where no render target is used */
2631 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
2633 TRACE("No surface is render target, not using hardware blit.\n");
2634 return WINED3DERR_INVALIDCALL;
2637 /* No destination color keying supported */
2638 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
2640 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2641 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2642 return WINED3DERR_INVALIDCALL;
2645 if (dst_swapchain && dst_swapchain == src_swapchain)
2647 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2648 return WINED3DERR_INVALIDCALL;
2651 if (dst_swapchain && src_swapchain)
2653 FIXME("Implement hardware blit between two different swapchains\n");
2654 return WINED3DERR_INVALIDCALL;
2657 if (dst_swapchain)
2659 /* Handled with regular texture -> swapchain blit */
2660 if (src_surface == rt)
2661 TRACE("Blit from active render target to a swapchain\n");
2663 else if (src_swapchain && dst_surface == rt)
2665 FIXME("Implement blit from a swapchain to the active render target\n");
2666 return WINED3DERR_INVALIDCALL;
2669 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
2671 /* Blit from render target to texture */
2672 BOOL stretchx;
2674 /* P8 read back is not implemented */
2675 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
2676 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
2678 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2679 return WINED3DERR_INVALIDCALL;
2682 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
2684 TRACE("Color keying not supported by frame buffer to texture blit\n");
2685 return WINED3DERR_INVALIDCALL;
2686 /* Destination color key is checked above */
2689 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
2690 stretchx = TRUE;
2691 else
2692 stretchx = FALSE;
2694 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2695 * flip the image nor scale it.
2697 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2698 * -> If the app wants an image width an unscaled width, copy it line per line
2699 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2700 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2701 * back buffer. This is slower than reading line per line, thus not used for flipping
2702 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2703 * pixel by pixel. */
2704 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
2705 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
2707 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2708 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
2710 else
2712 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2713 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
2716 surface_evict_sysmem(dst_surface);
2718 return WINED3D_OK;
2721 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2722 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2723 return WINED3DERR_INVALIDCALL;
2726 /* Context activation is done by the caller. */
2727 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
2728 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
2730 struct wined3d_device *device = surface->container->resource.device;
2731 const struct wined3d_gl_info *gl_info = context->gl_info;
2732 GLint compare_mode = GL_NONE;
2733 struct blt_info info;
2734 GLint old_binding = 0;
2735 RECT rect;
2737 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
2739 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2740 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2741 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2742 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2743 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2744 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
2745 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
2746 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
2747 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2748 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
2749 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
2751 SetRect(&rect, 0, h, w, 0);
2752 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
2753 context_active_texture(context, context->gl_info, 0);
2754 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
2755 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
2756 if (gl_info->supported[ARB_SHADOW])
2758 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
2759 if (compare_mode != GL_NONE)
2760 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
2763 device->shader_backend->shader_select_depth_blt(device->shader_priv,
2764 gl_info, info.tex_type, &surface->ds_current_size);
2766 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
2767 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
2768 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
2769 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
2770 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
2771 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
2772 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
2773 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
2774 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
2775 gl_info->gl_ops.gl.p_glEnd();
2777 if (compare_mode != GL_NONE)
2778 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
2779 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
2781 gl_info->gl_ops.gl.p_glPopAttrib();
2783 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
2786 void surface_modify_ds_location(struct wined3d_surface *surface,
2787 DWORD location, UINT w, UINT h)
2789 struct wined3d_texture_sub_resource *sub_resource;
2791 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
2793 sub_resource = surface_get_sub_resource(surface);
2794 if (((sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
2795 || (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
2796 && (location & WINED3D_LOCATION_TEXTURE_RGB)))
2797 wined3d_texture_set_dirty(surface->container);
2799 surface->ds_current_size.cx = w;
2800 surface->ds_current_size.cy = h;
2801 sub_resource->locations = location;
2804 /* Context activation is done by the caller. */
2805 static void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
2807 struct wined3d_texture *texture = surface->container;
2808 struct wined3d_device *device = texture->resource.device;
2809 const struct wined3d_gl_info *gl_info = context->gl_info;
2810 GLsizei w, h;
2812 TRACE("surface %p, context %p, new location %#x.\n", surface, context, location);
2814 /* TODO: Make this work for modes other than FBO */
2815 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
2817 if (!(surface_get_sub_resource(surface)->locations & location))
2819 w = surface->ds_current_size.cx;
2820 h = surface->ds_current_size.cy;
2821 surface->ds_current_size.cx = 0;
2822 surface->ds_current_size.cy = 0;
2824 else
2826 w = surface->resource.width;
2827 h = surface->resource.height;
2830 if (surface->current_renderbuffer)
2832 FIXME("Not supported with fixed up depth stencil.\n");
2833 return;
2836 wined3d_surface_prepare(surface, context, location);
2838 if (location == WINED3D_LOCATION_TEXTURE_RGB)
2840 GLint old_binding = 0;
2841 GLenum bind_target;
2843 /* The render target is allowed to be smaller than the depth/stencil
2844 * buffer, so the onscreen depth/stencil buffer is potentially smaller
2845 * than the offscreen surface. Don't overwrite the offscreen surface
2846 * with undefined data. */
2847 w = min(w, context->swapchain->desc.backbuffer_width);
2848 h = min(h, context->swapchain->desc.backbuffer_height);
2850 TRACE("Copying onscreen depth buffer to depth texture.\n");
2852 if (!device->depth_blt_texture)
2853 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
2855 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2856 * directly on the FBO texture. That's because we need to flip. */
2857 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2858 surface_from_resource(wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)),
2859 NULL, WINED3D_LOCATION_DRAWABLE);
2860 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2862 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
2863 bind_target = GL_TEXTURE_RECTANGLE_ARB;
2865 else
2867 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
2868 bind_target = GL_TEXTURE_2D;
2870 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
2871 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
2872 * internal format, because the internal format might include stencil
2873 * data. In principle we should copy stencil data as well, but unless
2874 * the driver supports stencil export it's hard to do, and doesn't
2875 * seem to be needed in practice. If the hardware doesn't support
2876 * writing stencil data, the glCopyTexImage2D() call might trigger
2877 * software fallbacks. */
2878 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
2879 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2880 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2881 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2882 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2883 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2884 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
2886 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2887 NULL, surface, WINED3D_LOCATION_TEXTURE_RGB);
2888 context_set_draw_buffer(context, GL_NONE);
2890 /* Do the actual blit */
2891 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
2892 checkGLcall("depth_blt");
2894 context_invalidate_state(context, STATE_FRAMEBUFFER);
2896 if (wined3d_settings.strict_draw_ordering)
2897 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2899 else if (location == WINED3D_LOCATION_DRAWABLE)
2901 TRACE("Copying depth texture to onscreen depth buffer.\n");
2903 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2904 surface_from_resource(wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)),
2905 NULL, WINED3D_LOCATION_DRAWABLE);
2906 surface_depth_blt(surface, context, texture->texture_rgb.name,
2907 0, surface->pow2Height - h, w, h, surface->texture_target);
2908 checkGLcall("depth_blt");
2910 context_invalidate_state(context, STATE_FRAMEBUFFER);
2912 if (wined3d_settings.strict_draw_ordering)
2913 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2915 else
2917 ERR("Invalid location (%#x) specified.\n", location);
2921 static DWORD resource_access_from_location(DWORD location)
2923 switch (location)
2925 case WINED3D_LOCATION_SYSMEM:
2926 case WINED3D_LOCATION_USER_MEMORY:
2927 case WINED3D_LOCATION_DIB:
2928 case WINED3D_LOCATION_BUFFER:
2929 return WINED3D_RESOURCE_ACCESS_CPU;
2931 case WINED3D_LOCATION_DRAWABLE:
2932 case WINED3D_LOCATION_TEXTURE_SRGB:
2933 case WINED3D_LOCATION_TEXTURE_RGB:
2934 case WINED3D_LOCATION_RB_MULTISAMPLE:
2935 case WINED3D_LOCATION_RB_RESOLVED:
2936 return WINED3D_RESOURCE_ACCESS_GPU;
2938 default:
2939 FIXME("Unhandled location %#x.\n", location);
2940 return 0;
2944 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
2946 struct wined3d_device *device = surface->container->resource.device;
2947 struct wined3d_context *context;
2948 const struct wined3d_gl_info *gl_info;
2949 struct wined3d_bo_address dst, src;
2950 UINT size = surface->resource.size;
2952 surface_get_memory(surface, &dst, location);
2953 surface_get_memory(surface, &src, surface_get_sub_resource(surface)->locations);
2955 if (dst.buffer_object)
2957 context = context_acquire(device, NULL);
2958 gl_info = context->gl_info;
2959 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
2960 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
2961 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2962 checkGLcall("Upload PBO");
2963 context_release(context);
2964 return;
2966 if (src.buffer_object)
2968 context = context_acquire(device, NULL);
2969 gl_info = context->gl_info;
2970 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
2971 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
2972 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2973 checkGLcall("Download PBO");
2974 context_release(context);
2975 return;
2977 memcpy(dst.addr, src.addr, size);
2980 /* Context activation is done by the caller. */
2981 static void surface_load_sysmem(struct wined3d_surface *surface,
2982 struct wined3d_context *context, DWORD dst_location)
2984 const struct wined3d_gl_info *gl_info = context->gl_info;
2985 struct wined3d_texture_sub_resource *sub_resource;
2987 wined3d_surface_prepare(surface, context, dst_location);
2989 sub_resource = surface_get_sub_resource(surface);
2990 if (sub_resource->locations & surface_simple_locations)
2992 surface_copy_simple_location(surface, dst_location);
2993 return;
2996 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
2997 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
2999 /* Download the surface to system memory. */
3000 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
3002 struct wined3d_texture *texture = surface->container;
3004 wined3d_texture_bind_and_dirtify(texture, context,
3005 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
3006 surface_download_data(surface, gl_info, dst_location);
3007 ++texture->download_count;
3009 return;
3012 if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3014 read_from_framebuffer(surface, context, dst_location);
3015 return;
3018 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
3019 surface, wined3d_debug_location(sub_resource->locations));
3022 /* Context activation is done by the caller. */
3023 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
3024 struct wined3d_context *context)
3026 struct wined3d_texture *texture = surface->container;
3027 RECT r;
3029 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3030 && wined3d_resource_is_offscreen(&texture->resource))
3032 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
3033 return WINED3DERR_INVALIDCALL;
3036 surface_get_rect(surface, NULL, &r);
3037 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
3038 surface_blt_to_drawable(texture->resource.device, context,
3039 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
3041 return WINED3D_OK;
3044 static HRESULT surface_load_texture(struct wined3d_surface *surface,
3045 struct wined3d_context *context, BOOL srgb)
3047 unsigned int width, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
3048 const RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
3049 const struct wined3d_gl_info *gl_info = context->gl_info;
3050 struct wined3d_texture *texture = surface->container;
3051 struct wined3d_device *device = texture->resource.device;
3052 const struct wined3d_color_key_conversion *conversion;
3053 struct wined3d_texture_sub_resource *sub_resource;
3054 struct wined3d_bo_address data;
3055 struct wined3d_format format;
3056 POINT dst_point = {0, 0};
3057 BYTE *mem = NULL;
3059 sub_resource = surface_get_sub_resource(surface);
3060 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
3061 && wined3d_resource_is_offscreen(&texture->resource)
3062 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
3064 surface_load_fb_texture(surface, srgb, context);
3066 return WINED3D_OK;
3069 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
3070 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
3071 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3072 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3073 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3075 if (srgb)
3076 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
3077 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
3078 else
3079 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
3080 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
3082 return WINED3D_OK;
3085 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
3086 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
3087 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3088 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3089 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3091 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
3092 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
3093 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
3094 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
3096 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
3097 &rect, surface, dst_location, &rect);
3099 return WINED3D_OK;
3102 /* Upload from system memory */
3104 if (srgb)
3106 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
3107 == WINED3D_LOCATION_TEXTURE_RGB)
3109 /* Performance warning... */
3110 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
3111 surface_load_location(surface, context, surface->resource.map_binding);
3114 else
3116 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
3117 == WINED3D_LOCATION_TEXTURE_SRGB)
3119 /* Performance warning... */
3120 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
3121 surface_load_location(surface, context, surface->resource.map_binding);
3125 if (!(sub_resource->locations & surface_simple_locations))
3127 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
3128 /* Lets hope we get it from somewhere... */
3129 surface_load_location(surface, context, WINED3D_LOCATION_SYSMEM);
3132 wined3d_texture_prepare_texture(texture, context, srgb);
3133 wined3d_texture_bind_and_dirtify(texture, context, srgb);
3134 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
3136 width = surface->resource.width;
3138 format = *texture->resource.format;
3139 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
3140 format = *wined3d_get_format(gl_info, conversion->dst_format);
3142 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
3143 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
3144 * getting called. */
3145 if ((format.convert || conversion)
3146 && texture->sub_resources[surface_get_sub_resource_idx(surface)].buffer_object)
3148 TRACE("Removing the pbo attached to surface %p.\n", surface);
3150 if (surface->flags & SFLAG_DIBSECTION)
3151 surface->resource.map_binding = WINED3D_LOCATION_DIB;
3152 else
3153 surface->resource.map_binding = WINED3D_LOCATION_SYSMEM;
3155 surface_load_location(surface, context, surface->resource.map_binding);
3156 wined3d_texture_remove_buffer_object(texture, surface_get_sub_resource_idx(surface), gl_info);
3159 surface_get_memory(surface, &data, sub_resource->locations);
3160 if (format.convert)
3162 /* This code is entered for texture formats which need a fixup. */
3163 UINT height = surface->resource.height;
3165 format.byte_count = format.conv_byte_count;
3166 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
3168 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3170 ERR("Out of memory (%u).\n", dst_slice_pitch);
3171 context_release(context);
3172 return E_OUTOFMEMORY;
3174 format.convert(data.addr, mem, src_row_pitch, src_slice_pitch,
3175 dst_row_pitch, dst_slice_pitch, width, height, 1);
3176 src_row_pitch = dst_row_pitch;
3177 data.addr = mem;
3179 else if (conversion)
3181 /* This code is only entered for color keying fixups */
3182 struct wined3d_palette *palette = NULL;
3183 UINT height = surface->resource.height;
3185 wined3d_format_calculate_pitch(&format, device->surface_alignment,
3186 width, height, &dst_row_pitch, &dst_slice_pitch);
3188 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3190 ERR("Out of memory (%u).\n", dst_slice_pitch);
3191 context_release(context);
3192 return E_OUTOFMEMORY;
3194 if (texture->swapchain && texture->swapchain->palette)
3195 palette = texture->swapchain->palette;
3196 conversion->convert(data.addr, src_row_pitch, mem, dst_row_pitch,
3197 width, height, palette, &texture->async.gl_color_key);
3198 src_row_pitch = dst_row_pitch;
3199 data.addr = mem;
3202 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
3203 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
3205 HeapFree(GetProcessHeap(), 0, mem);
3207 return WINED3D_OK;
3210 /* Context activation is done by the caller. */
3211 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
3212 DWORD dst_location)
3214 const RECT rect = {0, 0, surface->resource.width, surface->resource.height};
3215 DWORD locations = surface_get_sub_resource(surface)->locations;
3216 DWORD src_location;
3218 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
3219 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
3220 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
3221 src_location = WINED3D_LOCATION_RB_RESOLVED;
3222 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
3223 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
3224 else /* surface_blt_fbo will load the source location if necessary. */
3225 src_location = WINED3D_LOCATION_TEXTURE_RGB;
3227 surface_blt_fbo(surface->container->resource.device, context, WINED3D_TEXF_POINT,
3228 surface, src_location, &rect, surface, dst_location, &rect);
3231 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
3232 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
3234 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3235 struct wined3d_texture *texture = surface->container;
3236 struct wined3d_texture_sub_resource *sub_resource;
3237 HRESULT hr;
3239 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
3241 sub_resource = &texture->sub_resources[sub_resource_idx];
3242 if (sub_resource->locations & location && (!(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3243 || (surface->ds_current_size.cx == surface->resource.width
3244 && surface->ds_current_size.cy == surface->resource.height)))
3246 TRACE("Location (%#x) is already up to date.\n", location);
3247 return WINED3D_OK;
3250 if (WARN_ON(d3d))
3252 DWORD required_access = resource_access_from_location(location);
3253 if ((texture->resource.access_flags & required_access) != required_access)
3254 WARN("Operation requires %#x access, but surface only has %#x.\n",
3255 required_access, texture->resource.access_flags);
3258 if (sub_resource->locations & WINED3D_LOCATION_DISCARDED)
3260 TRACE("Surface previously discarded, nothing to do.\n");
3261 wined3d_surface_prepare(surface, context, location);
3262 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3263 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3264 goto done;
3267 if (!sub_resource->locations)
3269 ERR("Surface %p does not have any up to date location.\n", surface);
3270 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3271 return surface_load_location(surface, context, location);
3274 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3276 if ((location == WINED3D_LOCATION_TEXTURE_RGB && sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3277 || (location == WINED3D_LOCATION_DRAWABLE && sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB))
3279 surface_load_ds_location(surface, context, location);
3280 goto done;
3283 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
3284 wined3d_debug_location(sub_resource->locations), wined3d_debug_location(location));
3285 return WINED3DERR_INVALIDCALL;
3288 switch (location)
3290 case WINED3D_LOCATION_DIB:
3291 case WINED3D_LOCATION_USER_MEMORY:
3292 case WINED3D_LOCATION_SYSMEM:
3293 case WINED3D_LOCATION_BUFFER:
3294 surface_load_sysmem(surface, context, location);
3295 break;
3297 case WINED3D_LOCATION_DRAWABLE:
3298 if (FAILED(hr = surface_load_drawable(surface, context)))
3299 return hr;
3300 break;
3302 case WINED3D_LOCATION_RB_RESOLVED:
3303 case WINED3D_LOCATION_RB_MULTISAMPLE:
3304 surface_load_renderbuffer(surface, context, location);
3305 break;
3307 case WINED3D_LOCATION_TEXTURE_RGB:
3308 case WINED3D_LOCATION_TEXTURE_SRGB:
3309 if (FAILED(hr = surface_load_texture(surface, context,
3310 location == WINED3D_LOCATION_TEXTURE_SRGB)))
3311 return hr;
3312 break;
3314 default:
3315 ERR("Don't know how to handle location %#x.\n", location);
3316 break;
3319 done:
3320 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3322 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3324 surface->ds_current_size.cx = surface->resource.width;
3325 surface->ds_current_size.cy = surface->resource.height;
3328 if (location != WINED3D_LOCATION_SYSMEM && (sub_resource->locations & WINED3D_LOCATION_SYSMEM))
3329 surface_evict_sysmem(surface);
3331 return WINED3D_OK;
3334 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
3335 /* Context activation is done by the caller. */
3336 static void ffp_blit_free(struct wined3d_device *device) { }
3338 /* Context activation is done by the caller. */
3339 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3340 const struct wined3d_color_key *color_key)
3342 const struct wined3d_gl_info *gl_info = context->gl_info;
3344 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
3345 checkGLcall("glEnable(target)");
3347 return WINED3D_OK;
3350 /* Context activation is done by the caller. */
3351 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
3353 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
3354 checkGLcall("glDisable(GL_TEXTURE_2D)");
3355 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
3357 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
3358 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3360 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
3362 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
3363 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
3367 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
3368 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3369 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3370 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3372 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
3374 TRACE("Source or destination is in system memory.\n");
3375 return FALSE;
3378 switch (blit_op)
3380 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3381 if (d3d_info->shader_color_key)
3383 TRACE("Color keying requires converted textures.\n");
3384 return FALSE;
3386 case WINED3D_BLIT_OP_COLOR_BLIT:
3387 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3388 if (TRACE_ON(d3d))
3390 TRACE("Checking support for fixup:\n");
3391 dump_color_fixup_desc(src_format->color_fixup);
3394 /* We only support identity conversions. */
3395 if (!is_identity_fixup(src_format->color_fixup)
3396 || !is_identity_fixup(dst_format->color_fixup))
3398 TRACE("Fixups are not supported.\n");
3399 return FALSE;
3402 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3404 TRACE("Can only blit to render targets.\n");
3405 return FALSE;
3407 return TRUE;
3409 case WINED3D_BLIT_OP_COLOR_FILL:
3410 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3412 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
3413 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
3414 return FALSE;
3416 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3418 TRACE("Color fill not supported\n");
3419 return FALSE;
3422 /* FIXME: We should reject color fills on formats with fixups,
3423 * but this would break P8 color fills for example. */
3425 return TRUE;
3427 case WINED3D_BLIT_OP_DEPTH_FILL:
3428 return TRUE;
3430 default:
3431 TRACE("Unsupported blit_op=%d\n", blit_op);
3432 return FALSE;
3436 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
3437 const RECT *rect, const struct wined3d_color *color)
3439 const RECT draw_rect = {0, 0, view->width, view->height};
3440 struct wined3d_fb_state fb = {&view, NULL};
3442 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
3444 return WINED3D_OK;
3447 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
3448 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3449 float depth, DWORD stencil)
3451 const RECT draw_rect = {0, 0, view->width, view->height};
3452 struct wined3d_fb_state fb = {NULL, view};
3454 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, clear_flags, NULL, depth, stencil);
3456 return WINED3D_OK;
3459 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3460 struct wined3d_surface *src_surface, const RECT *src_rect,
3461 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3462 const struct wined3d_color_key *color_key)
3464 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3465 struct wined3d_texture *dst_texture = dst_surface->container;
3466 struct wined3d_texture *src_texture = src_surface->container;
3467 struct wined3d_context *context;
3469 /* Blit from offscreen surface to render target */
3470 struct wined3d_color_key old_blt_key = src_texture->async.src_blt_color_key;
3471 DWORD old_color_key_flags = src_texture->async.color_key_flags;
3473 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3475 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
3477 context = context_acquire(device, dst_surface);
3479 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3480 glEnable(GL_ALPHA_TEST);
3482 surface_blt_to_drawable(device, context, filter,
3483 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
3485 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3486 glDisable(GL_ALPHA_TEST);
3488 context_release(context);
3490 /* Restore the color key parameters */
3491 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
3492 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
3494 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_texture->resource.draw_binding);
3495 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_texture->resource.draw_binding);
3498 const struct blit_shader ffp_blit = {
3499 ffp_blit_alloc,
3500 ffp_blit_free,
3501 ffp_blit_set,
3502 ffp_blit_unset,
3503 ffp_blit_supported,
3504 ffp_blit_color_fill,
3505 ffp_blit_depth_fill,
3506 ffp_blit_blit_surface,
3509 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
3511 return WINED3D_OK;
3514 /* Context activation is done by the caller. */
3515 static void cpu_blit_free(struct wined3d_device *device)
3519 /* Context activation is done by the caller. */
3520 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3521 const struct wined3d_color_key *color_key)
3523 return WINED3D_OK;
3526 /* Context activation is done by the caller. */
3527 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
3531 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
3532 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3533 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3534 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3536 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
3538 return TRUE;
3541 return FALSE;
3544 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
3545 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
3546 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
3548 UINT row_block_count;
3549 const BYTE *src_row;
3550 BYTE *dst_row;
3551 UINT x, y;
3553 src_row = src_data;
3554 dst_row = dst_data;
3556 row_block_count = (update_w + format->block_width - 1) / format->block_width;
3558 if (!flags)
3560 for (y = 0; y < update_h; y += format->block_height)
3562 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
3563 src_row += src_pitch;
3564 dst_row += dst_pitch;
3567 return WINED3D_OK;
3570 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
3572 src_row += (((update_h / format->block_height) - 1) * src_pitch);
3574 switch (format->id)
3576 case WINED3DFMT_DXT1:
3577 for (y = 0; y < update_h; y += format->block_height)
3579 struct block
3581 WORD color[2];
3582 BYTE control_row[4];
3585 const struct block *s = (const struct block *)src_row;
3586 struct block *d = (struct block *)dst_row;
3588 for (x = 0; x < row_block_count; ++x)
3590 d[x].color[0] = s[x].color[0];
3591 d[x].color[1] = s[x].color[1];
3592 d[x].control_row[0] = s[x].control_row[3];
3593 d[x].control_row[1] = s[x].control_row[2];
3594 d[x].control_row[2] = s[x].control_row[1];
3595 d[x].control_row[3] = s[x].control_row[0];
3597 src_row -= src_pitch;
3598 dst_row += dst_pitch;
3600 return WINED3D_OK;
3602 case WINED3DFMT_DXT2:
3603 case WINED3DFMT_DXT3:
3604 for (y = 0; y < update_h; y += format->block_height)
3606 struct block
3608 WORD alpha_row[4];
3609 WORD color[2];
3610 BYTE control_row[4];
3613 const struct block *s = (const struct block *)src_row;
3614 struct block *d = (struct block *)dst_row;
3616 for (x = 0; x < row_block_count; ++x)
3618 d[x].alpha_row[0] = s[x].alpha_row[3];
3619 d[x].alpha_row[1] = s[x].alpha_row[2];
3620 d[x].alpha_row[2] = s[x].alpha_row[1];
3621 d[x].alpha_row[3] = s[x].alpha_row[0];
3622 d[x].color[0] = s[x].color[0];
3623 d[x].color[1] = s[x].color[1];
3624 d[x].control_row[0] = s[x].control_row[3];
3625 d[x].control_row[1] = s[x].control_row[2];
3626 d[x].control_row[2] = s[x].control_row[1];
3627 d[x].control_row[3] = s[x].control_row[0];
3629 src_row -= src_pitch;
3630 dst_row += dst_pitch;
3632 return WINED3D_OK;
3634 default:
3635 FIXME("Compressed flip not implemented for format %s.\n",
3636 debug_d3dformat(format->id));
3637 return E_NOTIMPL;
3641 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3642 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
3644 return E_NOTIMPL;
3647 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3648 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3649 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3650 enum wined3d_texture_filter_type filter)
3652 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
3653 const struct wined3d_format *src_format, *dst_format;
3654 struct wined3d_texture *converted_texture = NULL;
3655 unsigned int src_fmt_flags, dst_fmt_flags;
3656 struct wined3d_map_desc dst_map, src_map;
3657 const BYTE *sbase = NULL;
3658 HRESULT hr = WINED3D_OK;
3659 BOOL same_sub_resource;
3660 const BYTE *sbuf;
3661 BYTE *dbuf;
3662 int x, y;
3664 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3665 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3666 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
3667 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3669 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
3671 same_sub_resource = TRUE;
3672 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, NULL, 0);
3673 src_map = dst_map;
3674 src_format = dst_texture->resource.format;
3675 dst_format = src_format;
3676 dst_fmt_flags = dst_texture->resource.format_flags;
3677 src_fmt_flags = dst_fmt_flags;
3679 else
3681 same_sub_resource = FALSE;
3682 dst_format = dst_texture->resource.format;
3683 dst_fmt_flags = dst_texture->resource.format_flags;
3684 if (src_texture)
3686 if (dst_texture->resource.format->id != src_texture->resource.format->id)
3688 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format->id)))
3690 /* The conv function writes a FIXME */
3691 WARN("Cannot convert source surface format to dest format.\n");
3692 goto release;
3694 src_texture = converted_texture;
3695 src_sub_resource_idx = 0;
3697 wined3d_resource_map(&src_texture->resource, src_sub_resource_idx, &src_map, NULL, WINED3D_MAP_READONLY);
3698 src_format = src_texture->resource.format;
3699 src_fmt_flags = src_texture->resource.format_flags;
3701 else
3703 src_format = dst_format;
3704 src_fmt_flags = dst_fmt_flags;
3707 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, dst_box, 0);
3710 bpp = dst_format->byte_count;
3711 src_height = src_box->bottom - src_box->top;
3712 src_width = src_box->right - src_box->left;
3713 dst_height = dst_box->bottom - dst_box->top;
3714 dst_width = dst_box->right - dst_box->left;
3715 row_byte_count = dst_width * bpp;
3717 if (src_texture)
3718 sbase = (BYTE *)src_map.data
3719 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
3720 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
3721 if (same_sub_resource)
3722 dbuf = (BYTE *)dst_map.data
3723 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
3724 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
3725 else
3726 dbuf = dst_map.data;
3728 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
3730 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
3732 if (same_sub_resource)
3734 FIXME("Only plain blits supported on compressed surfaces.\n");
3735 hr = E_NOTIMPL;
3736 goto release;
3739 if (src_height != dst_height || src_width != dst_width)
3741 WARN("Stretching not supported on compressed surfaces.\n");
3742 hr = WINED3DERR_INVALIDCALL;
3743 goto release;
3746 if (!wined3d_texture_check_block_align(src_texture,
3747 src_sub_resource_idx % src_texture->level_count, src_box))
3749 WARN("Source rectangle not block-aligned.\n");
3750 hr = WINED3DERR_INVALIDCALL;
3751 goto release;
3754 if (!wined3d_texture_check_block_align(dst_texture,
3755 dst_sub_resource_idx % dst_texture->level_count, dst_box))
3757 WARN("Destination rectangle not block-aligned.\n");
3758 hr = WINED3DERR_INVALIDCALL;
3759 goto release;
3762 hr = surface_cpu_blt_compressed(sbase, dbuf,
3763 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
3764 src_format, flags, fx);
3765 goto release;
3768 /* First, all the 'source-less' blits */
3769 if (flags & WINED3D_BLT_COLOR_FILL)
3771 hr = _Blt_ColorFill(dbuf, dst_width, dst_height, bpp, dst_map.row_pitch, fx->fill_color);
3772 flags &= ~WINED3D_BLT_COLOR_FILL;
3775 if (flags & WINED3D_BLT_DEPTH_FILL)
3776 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3778 /* Now the 'with source' blits. */
3779 if (src_texture)
3781 int sx, xinc, sy, yinc;
3783 if (!dst_width || !dst_height) /* Hmm... stupid program? */
3784 goto release;
3786 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3787 && (src_width != dst_width || src_height != dst_height))
3789 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3790 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
3793 xinc = (src_width << 16) / dst_width;
3794 yinc = (src_height << 16) / dst_height;
3796 if (!flags)
3798 /* No effects, we can cheat here. */
3799 if (dst_width == src_width)
3801 if (dst_height == src_height)
3803 /* No stretching in either direction. This needs to be as
3804 * fast as possible. */
3805 sbuf = sbase;
3807 /* Check for overlapping surfaces. */
3808 if (!same_sub_resource || dst_box->top < src_box->top
3809 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
3811 /* No overlap, or dst above src, so copy from top downwards. */
3812 for (y = 0; y < dst_height; ++y)
3814 memcpy(dbuf, sbuf, row_byte_count);
3815 sbuf += src_map.row_pitch;
3816 dbuf += dst_map.row_pitch;
3819 else if (dst_box->top > src_box->top)
3821 /* Copy from bottom upwards. */
3822 sbuf += src_map.row_pitch * dst_height;
3823 dbuf += dst_map.row_pitch * dst_height;
3824 for (y = 0; y < dst_height; ++y)
3826 sbuf -= src_map.row_pitch;
3827 dbuf -= dst_map.row_pitch;
3828 memcpy(dbuf, sbuf, row_byte_count);
3831 else
3833 /* Src and dst overlapping on the same line, use memmove. */
3834 for (y = 0; y < dst_height; ++y)
3836 memmove(dbuf, sbuf, row_byte_count);
3837 sbuf += src_map.row_pitch;
3838 dbuf += dst_map.row_pitch;
3842 else
3844 /* Stretching in y direction only. */
3845 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3847 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3848 memcpy(dbuf, sbuf, row_byte_count);
3849 dbuf += dst_map.row_pitch;
3853 else
3855 /* Stretching in X direction. */
3856 int last_sy = -1;
3857 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3859 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3861 if ((sy >> 16) == (last_sy >> 16))
3863 /* This source row is the same as last source row -
3864 * Copy the already stretched row. */
3865 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
3867 else
3869 #define STRETCH_ROW(type) \
3870 do { \
3871 const type *s = (const type *)sbuf; \
3872 type *d = (type *)dbuf; \
3873 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3874 d[x] = s[sx >> 16]; \
3875 } while(0)
3877 switch(bpp)
3879 case 1:
3880 STRETCH_ROW(BYTE);
3881 break;
3882 case 2:
3883 STRETCH_ROW(WORD);
3884 break;
3885 case 4:
3886 STRETCH_ROW(DWORD);
3887 break;
3888 case 3:
3890 const BYTE *s;
3891 BYTE *d = dbuf;
3892 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3894 DWORD pixel;
3896 s = sbuf + 3 * (sx >> 16);
3897 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3898 d[0] = (pixel ) & 0xff;
3899 d[1] = (pixel >> 8) & 0xff;
3900 d[2] = (pixel >> 16) & 0xff;
3901 d += 3;
3903 break;
3905 default:
3906 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
3907 hr = WINED3DERR_NOTAVAILABLE;
3908 goto error;
3910 #undef STRETCH_ROW
3912 dbuf += dst_map.row_pitch;
3913 last_sy = sy;
3917 else
3919 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3920 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3921 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3922 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3923 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3925 /* The color keying flags are checked for correctness in ddraw */
3926 if (flags & WINED3D_BLT_SRC_CKEY)
3928 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
3929 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3931 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3933 keylow = fx->src_color_key.color_space_low_value;
3934 keyhigh = fx->src_color_key.color_space_high_value;
3937 if (flags & WINED3D_BLT_DST_CKEY)
3939 /* Destination color keys are taken from the source surface! */
3940 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3941 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3943 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3945 destkeylow = fx->dst_color_key.color_space_low_value;
3946 destkeyhigh = fx->dst_color_key.color_space_high_value;
3949 if (bpp == 1)
3951 keymask = 0xff;
3953 else
3955 DWORD masks[3];
3956 get_color_masks(src_format, masks);
3957 keymask = masks[0]
3958 | masks[1]
3959 | masks[2];
3961 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3962 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3965 if (flags & WINED3D_BLT_FX)
3967 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3968 LONG tmpxy;
3969 dTopLeft = dbuf;
3970 dTopRight = dbuf + ((dst_width - 1) * bpp);
3971 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3972 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3974 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3976 /* I don't think we need to do anything about this flag */
3977 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3979 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3981 tmp = dTopRight;
3982 dTopRight = dTopLeft;
3983 dTopLeft = tmp;
3984 tmp = dBottomRight;
3985 dBottomRight = dBottomLeft;
3986 dBottomLeft = tmp;
3987 dstxinc = dstxinc * -1;
3989 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
3991 tmp = dTopLeft;
3992 dTopLeft = dBottomLeft;
3993 dBottomLeft = tmp;
3994 tmp = dTopRight;
3995 dTopRight = dBottomRight;
3996 dBottomRight = tmp;
3997 dstyinc = dstyinc * -1;
3999 if (fx->fx & WINEDDBLTFX_NOTEARING)
4001 /* I don't think we need to do anything about this flag */
4002 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
4004 if (fx->fx & WINEDDBLTFX_ROTATE180)
4006 tmp = dBottomRight;
4007 dBottomRight = dTopLeft;
4008 dTopLeft = tmp;
4009 tmp = dBottomLeft;
4010 dBottomLeft = dTopRight;
4011 dTopRight = tmp;
4012 dstxinc = dstxinc * -1;
4013 dstyinc = dstyinc * -1;
4015 if (fx->fx & WINEDDBLTFX_ROTATE270)
4017 tmp = dTopLeft;
4018 dTopLeft = dBottomLeft;
4019 dBottomLeft = dBottomRight;
4020 dBottomRight = dTopRight;
4021 dTopRight = tmp;
4022 tmpxy = dstxinc;
4023 dstxinc = dstyinc;
4024 dstyinc = tmpxy;
4025 dstxinc = dstxinc * -1;
4027 if (fx->fx & WINEDDBLTFX_ROTATE90)
4029 tmp = dTopLeft;
4030 dTopLeft = dTopRight;
4031 dTopRight = dBottomRight;
4032 dBottomRight = dBottomLeft;
4033 dBottomLeft = tmp;
4034 tmpxy = dstxinc;
4035 dstxinc = dstyinc;
4036 dstyinc = tmpxy;
4037 dstyinc = dstyinc * -1;
4039 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
4041 /* I don't think we need to do anything about this flag */
4042 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
4044 dbuf = dTopLeft;
4045 flags &= ~(WINED3D_BLT_FX);
4048 #define COPY_COLORKEY_FX(type) \
4049 do { \
4050 const type *s; \
4051 type *d = (type *)dbuf, *dx, tmp; \
4052 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
4054 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
4055 dx = d; \
4056 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
4058 tmp = s[sx >> 16]; \
4059 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
4060 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
4062 dx[0] = tmp; \
4064 dx = (type *)(((BYTE *)dx) + dstxinc); \
4066 d = (type *)(((BYTE *)d) + dstyinc); \
4068 } while(0)
4070 switch (bpp)
4072 case 1:
4073 COPY_COLORKEY_FX(BYTE);
4074 break;
4075 case 2:
4076 COPY_COLORKEY_FX(WORD);
4077 break;
4078 case 4:
4079 COPY_COLORKEY_FX(DWORD);
4080 break;
4081 case 3:
4083 const BYTE *s;
4084 BYTE *d = dbuf, *dx;
4085 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
4087 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
4088 dx = d;
4089 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
4091 DWORD pixel, dpixel = 0;
4092 s = sbuf + 3 * (sx>>16);
4093 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
4094 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
4095 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
4096 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
4098 dx[0] = (pixel ) & 0xff;
4099 dx[1] = (pixel >> 8) & 0xff;
4100 dx[2] = (pixel >> 16) & 0xff;
4102 dx += dstxinc;
4104 d += dstyinc;
4106 break;
4108 default:
4109 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
4110 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
4111 hr = WINED3DERR_NOTAVAILABLE;
4112 goto error;
4113 #undef COPY_COLORKEY_FX
4118 error:
4119 if (flags)
4120 FIXME(" Unsupported flags %#x.\n", flags);
4122 release:
4123 wined3d_resource_unmap(&dst_texture->resource, dst_sub_resource_idx);
4124 if (src_texture && !same_sub_resource)
4125 wined3d_resource_unmap(&src_texture->resource, src_sub_resource_idx);
4126 if (converted_texture)
4127 wined3d_texture_decref(converted_texture);
4129 return hr;
4132 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
4133 const RECT *rect, const struct wined3d_color *color)
4135 const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
4136 static const struct wined3d_box src_box;
4137 struct wined3d_blt_fx fx;
4139 fx.fill_color = wined3d_format_convert_from_float(view->format, color);
4140 return surface_cpu_blt(wined3d_texture_from_resource(view->resource), view->sub_resource_idx,
4141 &box, NULL, 0, &src_box, WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
4144 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
4145 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
4146 float depth, DWORD stencil)
4148 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
4149 return WINED3DERR_INVALIDCALL;
4152 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
4153 struct wined3d_surface *src_surface, const RECT *src_rect,
4154 struct wined3d_surface *dst_surface, const RECT *dst_rect,
4155 const struct wined3d_color_key *color_key)
4157 /* FIXME: Remove error returns from surface_blt_cpu. */
4158 ERR("Blit method not implemented by cpu_blit.\n");
4161 const struct blit_shader cpu_blit = {
4162 cpu_blit_alloc,
4163 cpu_blit_free,
4164 cpu_blit_set,
4165 cpu_blit_unset,
4166 cpu_blit_supported,
4167 cpu_blit_color_fill,
4168 cpu_blit_depth_fill,
4169 cpu_blit_blit_surface,
4172 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
4173 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
4174 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
4176 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
4177 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
4178 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
4179 struct wined3d_texture *dst_texture = dst_surface->container;
4180 struct wined3d_device *device = dst_texture->resource.device;
4181 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
4182 struct wined3d_texture *src_texture = NULL;
4183 DWORD src_ds_flags, dst_ds_flags;
4184 BOOL scale, convert;
4186 static const DWORD simple_blit = WINED3D_BLT_ASYNC
4187 | WINED3D_BLT_COLOR_FILL
4188 | WINED3D_BLT_SRC_CKEY
4189 | WINED3D_BLT_SRC_CKEY_OVERRIDE
4190 | WINED3D_BLT_WAIT
4191 | WINED3D_BLT_DEPTH_FILL
4192 | WINED3D_BLT_DO_NOT_WAIT
4193 | WINED3D_BLT_ALPHA_TEST;
4195 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4196 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
4197 flags, fx, debug_d3dtexturefiltertype(filter));
4198 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
4200 if (fx)
4202 TRACE("fx %#x.\n", fx->fx);
4203 TRACE("fill_color 0x%08x.\n", fx->fill_color);
4204 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
4205 fx->dst_color_key.color_space_low_value,
4206 fx->dst_color_key.color_space_high_value);
4207 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
4208 fx->src_color_key.color_space_low_value,
4209 fx->src_color_key.color_space_high_value);
4212 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
4214 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
4215 return WINEDDERR_SURFACEBUSY;
4218 if (dst_rect->left >= dst_rect->right || dst_rect->top >= dst_rect->bottom
4219 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
4220 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
4221 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
4222 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0)
4224 WARN("The application gave us a bad destination rectangle.\n");
4225 return WINEDDERR_INVALIDRECT;
4228 if (src_surface)
4230 if (src_rect->left >= src_rect->right || src_rect->top >= src_rect->bottom
4231 || src_rect->left > src_surface->resource.width || src_rect->left < 0
4232 || src_rect->top > src_surface->resource.height || src_rect->top < 0
4233 || src_rect->right > src_surface->resource.width || src_rect->right < 0
4234 || src_rect->bottom > src_surface->resource.height || src_rect->bottom < 0)
4236 WARN("The application gave us a bad source rectangle.\n");
4237 return WINEDDERR_INVALIDRECT;
4239 src_texture = src_surface->container;
4242 if (!fx || !(fx->fx))
4243 flags &= ~WINED3D_BLT_FX;
4245 if (flags & WINED3D_BLT_WAIT)
4246 flags &= ~WINED3D_BLT_WAIT;
4248 if (flags & WINED3D_BLT_ASYNC)
4250 static unsigned int once;
4252 if (!once++)
4253 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
4254 flags &= ~WINED3D_BLT_ASYNC;
4257 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
4258 if (flags & WINED3D_BLT_DO_NOT_WAIT)
4260 static unsigned int once;
4262 if (!once++)
4263 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
4264 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
4267 if (!device->d3d_initialized)
4269 WARN("D3D not initialized, using fallback.\n");
4270 goto cpu;
4273 /* We want to avoid invalidating the sysmem location for converted
4274 * surfaces, since otherwise we'd have to convert the data back when
4275 * locking them. */
4276 if (dst_texture->flags & WINED3D_TEXTURE_CONVERTED || dst_texture->resource.format->convert
4277 || wined3d_format_get_color_key_conversion(dst_texture, TRUE))
4279 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
4280 goto cpu;
4283 if (flags & ~simple_blit)
4285 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
4286 goto fallback;
4289 if (src_surface)
4290 src_swapchain = src_texture->swapchain;
4291 else
4292 src_swapchain = NULL;
4294 dst_swapchain = dst_texture->swapchain;
4296 /* This isn't strictly needed. FBO blits for example could deal with
4297 * cross-swapchain blits by first downloading the source to a texture
4298 * before switching to the destination context. We just have this here to
4299 * not have to deal with the issue, since cross-swapchain blits should be
4300 * rare. */
4301 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
4303 FIXME("Using fallback for cross-swapchain blit.\n");
4304 goto fallback;
4307 scale = src_surface
4308 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
4309 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
4310 convert = src_surface && src_texture->resource.format->id != dst_texture->resource.format->id;
4312 dst_ds_flags = dst_texture->resource.format_flags
4313 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4314 if (src_surface)
4315 src_ds_flags = src_texture->resource.format_flags
4316 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4317 else
4318 src_ds_flags = 0;
4320 if (src_ds_flags || dst_ds_flags)
4322 if (flags & WINED3D_BLT_DEPTH_FILL)
4324 float depth;
4326 TRACE("Depth fill.\n");
4328 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
4329 return WINED3DERR_INVALIDCALL;
4331 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
4332 return WINED3D_OK;
4334 else
4336 if (src_ds_flags != dst_ds_flags)
4338 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
4339 return WINED3DERR_INVALIDCALL;
4342 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_texture->resource.draw_binding,
4343 src_rect, dst_surface, dst_texture->resource.draw_binding, dst_rect)))
4344 return WINED3D_OK;
4347 else
4349 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
4350 const struct blit_shader *blitter;
4352 dst_sub_resource = surface_get_sub_resource(dst_surface);
4353 src_sub_resource = src_surface ? surface_get_sub_resource(src_surface) : NULL;
4355 /* In principle this would apply to depth blits as well, but we don't
4356 * implement those in the CPU blitter at the moment. */
4357 if ((dst_sub_resource->locations & dst_surface->resource.map_binding)
4358 && (!src_surface || (src_sub_resource->locations & src_surface->resource.map_binding)))
4360 if (scale)
4361 TRACE("Not doing sysmem blit because of scaling.\n");
4362 else if (convert)
4363 TRACE("Not doing sysmem blit because of format conversion.\n");
4364 else
4365 goto cpu;
4368 if (flags & WINED3D_BLT_COLOR_FILL)
4370 struct wined3d_color color;
4371 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
4373 TRACE("Color fill.\n");
4375 if (!wined3d_format_convert_color_to_float(dst_texture->resource.format,
4376 palette, fx->fill_color, &color))
4377 goto fallback;
4379 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
4380 return WINED3D_OK;
4382 else
4384 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
4385 const struct wined3d_color_key *color_key = NULL;
4387 TRACE("Color blit.\n");
4388 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
4390 color_key = &fx->src_color_key;
4391 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4393 else if (flags & WINED3D_BLT_SRC_CKEY)
4395 color_key = &src_texture->async.src_blt_color_key;
4396 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4398 else if (flags & WINED3D_BLT_ALPHA_TEST)
4400 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
4402 else if ((src_sub_resource->locations & WINED3D_LOCATION_SYSMEM)
4403 && !(dst_sub_resource->locations & WINED3D_LOCATION_SYSMEM))
4405 /* Upload */
4406 if (scale)
4407 TRACE("Not doing upload because of scaling.\n");
4408 else if (convert)
4409 TRACE("Not doing upload because of format conversion.\n");
4410 else
4412 POINT dst_point = {dst_rect->left, dst_rect->top};
4414 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
4416 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
4418 struct wined3d_context *context = context_acquire(device, dst_surface);
4419 surface_load_location(dst_surface, context, dst_texture->resource.draw_binding);
4420 context_release(context);
4422 return WINED3D_OK;
4426 else if (dst_swapchain && dst_swapchain->back_buffers
4427 && dst_texture == dst_swapchain->front_buffer
4428 && src_texture == dst_swapchain->back_buffers[0])
4430 /* Use present for back -> front blits. The idea behind this is
4431 * that present is potentially faster than a blit, in particular
4432 * when FBO blits aren't available. Some ddraw applications like
4433 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4434 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4435 * applications can't blit directly to the frontbuffer. */
4436 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
4438 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4440 /* Set the swap effect to COPY, we don't want the backbuffer
4441 * to become undefined. */
4442 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
4443 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, 0);
4444 dst_swapchain->desc.swap_effect = swap_effect;
4446 return WINED3D_OK;
4449 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
4450 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4451 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
4453 struct wined3d_context *context;
4454 TRACE("Using FBO blit.\n");
4456 context = context_acquire(device, NULL);
4457 surface_blt_fbo(device, context, filter,
4458 src_surface, src_texture->resource.draw_binding, src_rect,
4459 dst_surface, dst_texture->resource.draw_binding, dst_rect);
4460 context_release(context);
4462 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx,
4463 dst_texture->resource.draw_binding);
4464 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx,
4465 ~dst_texture->resource.draw_binding);
4467 return WINED3D_OK;
4470 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
4471 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4472 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format);
4473 if (blitter)
4475 blitter->blit_surface(device, blit_op, filter, src_surface,
4476 src_rect, dst_surface, dst_rect, color_key);
4477 return WINED3D_OK;
4482 fallback:
4483 /* Special cases for render targets. */
4484 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
4485 return WINED3D_OK;
4487 cpu:
4488 return surface_cpu_blt(dst_texture, surface_get_sub_resource_idx(dst_surface), &dst_box,
4489 src_texture, src_texture ? surface_get_sub_resource_idx(src_surface) : 0, &src_box, flags, fx, filter);
4492 HRESULT wined3d_surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
4493 const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags)
4495 unsigned int sub_resource_idx = layer * container->level_count + level;
4496 struct wined3d_device *device = container->resource.device;
4497 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4498 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format);
4499 BOOL lockable = flags & WINED3D_TEXTURE_CREATE_MAPPABLE;
4500 UINT multisample_quality = desc->multisample_quality;
4501 unsigned int resource_size;
4502 HRESULT hr;
4504 if (container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
4506 unsigned int pow2_width = 1, pow2_height = 1;
4508 /* Find the nearest pow2 match. */
4509 while (pow2_width < desc->width)
4510 pow2_width <<= 1;
4511 while (pow2_height < desc->height)
4512 pow2_height <<= 1;
4514 surface->pow2Width = pow2_width;
4515 surface->pow2Height = pow2_height;
4517 else
4519 surface->pow2Width = desc->width;
4520 surface->pow2Height = desc->height;
4523 /* Quick lockable sanity check.
4524 * TODO: remove this after surfaces, usage and lockability have been debugged properly
4525 * this function is too deep to need to care about things like this.
4526 * Levels need to be checked too, since they all affect what can be done. */
4527 switch (desc->pool)
4529 case WINED3D_POOL_MANAGED:
4530 if (desc->usage & WINED3DUSAGE_DYNAMIC)
4531 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
4532 break;
4534 case WINED3D_POOL_DEFAULT:
4535 if (lockable && !(desc->usage & (WINED3DUSAGE_DYNAMIC
4536 | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4537 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
4538 break;
4540 case WINED3D_POOL_SCRATCH:
4541 case WINED3D_POOL_SYSTEM_MEM:
4542 break;
4544 default:
4545 FIXME("Unknown pool %#x.\n", desc->pool);
4546 break;
4549 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->pool != WINED3D_POOL_DEFAULT)
4550 FIXME("Trying to create a render target that isn't in the default pool.\n");
4552 /* FIXME: Check that the format is supported by the device. */
4554 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, 1);
4555 if (!resource_size)
4556 return WINED3DERR_INVALIDCALL;
4558 if (FAILED(hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE,
4559 format, desc->multisample_type, multisample_quality, desc->usage, desc->pool, desc->width, desc->height,
4560 1, resource_size, NULL, &wined3d_null_parent_ops, &surface_resource_ops)))
4562 WARN("Failed to initialize resource, returning %#x.\n", hr);
4563 return hr;
4566 surface->container = container;
4567 surface->texture_target = target;
4568 surface->texture_level = level;
4569 surface->texture_layer = layer;
4571 list_init(&surface->renderbuffers);
4572 list_init(&surface->overlays);
4574 /* Flags */
4575 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
4576 surface->flags |= SFLAG_DISCARD;
4577 if (lockable || desc->format == WINED3DFMT_D16_LOCKABLE)
4578 surface->resource.access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
4580 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4581 if (container->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4582 container->sub_resources[sub_resource_idx].locations = WINED3D_LOCATION_DISCARDED;
4584 if (wined3d_texture_use_pbo(container, gl_info))
4585 surface->resource.map_binding = WINED3D_LOCATION_BUFFER;
4587 /* Similar to lockable rendertargets above, creating the DIB section
4588 * during surface initialization prevents the sysmem pointer from changing
4589 * after a wined3d_texture_get_dc() call. */
4590 if ((desc->usage & WINED3DUSAGE_OWNDC) || (device->wined3d->flags & WINED3D_NO3D))
4592 if (FAILED(hr = surface_create_dib_section(surface)))
4594 wined3d_surface_cleanup(surface);
4595 return hr;
4597 surface->resource.map_binding = WINED3D_LOCATION_DIB;
4600 if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
4602 wined3d_resource_free_sysmem(&surface->resource);
4603 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_DIB);
4604 wined3d_texture_invalidate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4607 return hr;
4610 /* Context activation is done by the caller. Context may be NULL in
4611 * WINED3D_NO3D mode. */
4612 void wined3d_surface_prepare(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4614 struct wined3d_texture *texture = surface->container;
4616 switch (location)
4618 case WINED3D_LOCATION_SYSMEM:
4619 surface_prepare_system_memory(surface);
4620 break;
4622 case WINED3D_LOCATION_USER_MEMORY:
4623 if (!texture->user_memory)
4624 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
4625 break;
4627 case WINED3D_LOCATION_DIB:
4628 if (!surface->dib.bitmap_data)
4629 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
4630 break;
4632 case WINED3D_LOCATION_BUFFER:
4633 wined3d_texture_prepare_buffer_object(texture,
4634 surface_get_sub_resource_idx(surface), context->gl_info);
4635 break;
4637 case WINED3D_LOCATION_TEXTURE_RGB:
4638 wined3d_texture_prepare_texture(texture, context, FALSE);
4639 break;
4641 case WINED3D_LOCATION_TEXTURE_SRGB:
4642 wined3d_texture_prepare_texture(texture, context, TRUE);
4643 break;
4645 case WINED3D_LOCATION_RB_MULTISAMPLE:
4646 surface_prepare_rb(surface, context->gl_info, TRUE);
4647 break;
4649 case WINED3D_LOCATION_RB_RESOLVED:
4650 surface_prepare_rb(surface, context->gl_info, FALSE);
4651 break;