wined3d: Use the texture dimension helpers in surface_load_texture().
[wine.git] / dlls / wined3d / surface.c
blob5427ee98414103e7f7aa4beee1a22a6bf36b2fa6
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 const struct wined3d_texture *texture = surface->container;
282 rect_out->left = 0;
283 rect_out->top = 0;
284 rect_out->right = wined3d_texture_get_level_width(texture, surface->texture_level);
285 rect_out->bottom = wined3d_texture_get_level_height(texture, surface->texture_level);
289 /* Context activation is done by the caller. */
290 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
291 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
293 const struct wined3d_gl_info *gl_info = context->gl_info;
294 struct wined3d_texture *texture = src_surface->container;
295 struct blt_info info;
297 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
299 gl_info->gl_ops.gl.p_glEnable(info.bind_target);
300 checkGLcall("glEnable(bind_target)");
302 context_bind_texture(context, info.bind_target, texture->texture_rgb.name);
304 /* Filtering for StretchRect */
305 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
306 checkGLcall("glTexParameteri");
307 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
308 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
309 checkGLcall("glTexParameteri");
310 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
311 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
312 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
313 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
314 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
315 checkGLcall("glTexEnvi");
317 /* Draw a quad */
318 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
319 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
320 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->top);
322 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
323 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->top);
325 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
326 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->bottom);
328 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
329 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->bottom);
330 gl_info->gl_ops.gl.p_glEnd();
332 /* Unbind the texture */
333 context_bind_texture(context, info.bind_target, 0);
335 /* We changed the filtering settings on the texture. Inform the
336 * container about this to get the filters reset properly next draw. */
337 texture->texture_rgb.sampler_desc.mag_filter = WINED3D_TEXF_POINT;
338 texture->texture_rgb.sampler_desc.min_filter = WINED3D_TEXF_POINT;
339 texture->texture_rgb.sampler_desc.mip_filter = WINED3D_TEXF_NONE;
340 texture->texture_rgb.sampler_desc.srgb_decode = FALSE;
343 /* Works correctly only for <= 4 bpp formats. */
344 static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
346 masks[0] = ((1u << format->red_size) - 1) << format->red_offset;
347 masks[1] = ((1u << format->green_size) - 1) << format->green_offset;
348 masks[2] = ((1u << format->blue_size) - 1) << format->blue_offset;
351 HRESULT surface_create_dib_section(struct wined3d_surface *surface)
353 struct wined3d_texture *texture = surface->container;
354 const struct wined3d_format *format = texture->resource.format;
355 unsigned int format_flags = texture->resource.format_flags;
356 unsigned int row_pitch, slice_pitch;
357 BITMAPINFO *b_info;
358 DWORD *masks;
360 TRACE("surface %p.\n", surface);
362 if (!(format_flags & WINED3DFMT_FLAG_GETDC))
364 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
365 return WINED3DERR_INVALIDCALL;
368 switch (format->byte_count)
370 case 2:
371 case 4:
372 /* Allocate extra space to store the RGB bit masks. */
373 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO, bmiColors[3]));
374 break;
376 case 3:
377 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(BITMAPINFO, bmiColors[0]));
378 break;
380 default:
381 /* Allocate extra space for a palette. */
382 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
383 FIELD_OFFSET(BITMAPINFO, bmiColors[1u << (format->byte_count * 8)]));
384 break;
387 if (!b_info)
388 return E_OUTOFMEMORY;
390 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
391 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
392 b_info->bmiHeader.biWidth = row_pitch / format->byte_count;
393 b_info->bmiHeader.biHeight = 0 - wined3d_texture_get_level_height(texture, surface->texture_level);
394 b_info->bmiHeader.biSizeImage = slice_pitch;
395 b_info->bmiHeader.biPlanes = 1;
396 b_info->bmiHeader.biBitCount = format->byte_count * 8;
398 b_info->bmiHeader.biXPelsPerMeter = 0;
399 b_info->bmiHeader.biYPelsPerMeter = 0;
400 b_info->bmiHeader.biClrUsed = 0;
401 b_info->bmiHeader.biClrImportant = 0;
403 /* Get the bit masks */
404 masks = (DWORD *)b_info->bmiColors;
405 switch (format->id)
407 case WINED3DFMT_B8G8R8_UNORM:
408 b_info->bmiHeader.biCompression = BI_RGB;
409 break;
411 case WINED3DFMT_B5G5R5X1_UNORM:
412 case WINED3DFMT_B5G5R5A1_UNORM:
413 case WINED3DFMT_B4G4R4A4_UNORM:
414 case WINED3DFMT_B4G4R4X4_UNORM:
415 case WINED3DFMT_B2G3R3_UNORM:
416 case WINED3DFMT_B2G3R3A8_UNORM:
417 case WINED3DFMT_R10G10B10A2_UNORM:
418 case WINED3DFMT_R8G8B8A8_UNORM:
419 case WINED3DFMT_R8G8B8X8_UNORM:
420 case WINED3DFMT_B10G10R10A2_UNORM:
421 case WINED3DFMT_B5G6R5_UNORM:
422 case WINED3DFMT_R16G16B16A16_UNORM:
423 b_info->bmiHeader.biCompression = BI_BITFIELDS;
424 get_color_masks(format, masks);
425 break;
427 default:
428 /* Don't know palette */
429 b_info->bmiHeader.biCompression = BI_RGB;
430 break;
433 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
434 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
435 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
436 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
438 if (!surface->dib.DIBsection)
440 ERR("Failed to create DIB section.\n");
441 HeapFree(GetProcessHeap(), 0, b_info);
442 return HRESULT_FROM_WIN32(GetLastError());
445 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
446 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
448 HeapFree(GetProcessHeap(), 0, b_info);
450 /* Now allocate a DC. */
451 surface->hDC = CreateCompatibleDC(0);
452 SelectObject(surface->hDC, surface->dib.DIBsection);
454 surface->flags |= SFLAG_DIBSECTION;
456 return WINED3D_OK;
459 static void surface_prepare_system_memory(struct wined3d_surface *surface)
461 TRACE("surface %p.\n", surface);
463 if (surface->resource.heap_memory)
464 return;
466 /* Whatever surface we have, make sure that there is memory allocated
467 * for the downloaded copy, or a PBO to map. */
468 if (!wined3d_resource_allocate_sysmem(&surface->resource))
469 ERR("Failed to allocate system memory.\n");
471 if (surface_get_sub_resource(surface)->locations & WINED3D_LOCATION_SYSMEM)
472 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
475 static void surface_evict_sysmem(struct wined3d_surface *surface)
477 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
478 struct wined3d_texture *texture = surface->container;
480 if (surface->resource.map_count || texture->download_count > MAXLOCKCOUNT
481 || texture->flags & (WINED3D_TEXTURE_CONVERTED | WINED3D_TEXTURE_PIN_SYSMEM))
482 return;
484 wined3d_resource_free_sysmem(&surface->resource);
485 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
488 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
490 unsigned int t;
492 t = wined3d_texture_get_level_width(surface->container, surface->texture_level);
493 if ((r->left && r->right) || abs(r->right - r->left) != t)
494 return FALSE;
495 t = wined3d_texture_get_level_height(surface->container, surface->texture_level);
496 if ((r->top && r->bottom) || abs(r->bottom - r->top) != t)
497 return FALSE;
498 return TRUE;
501 static void surface_depth_blt_fbo(const struct wined3d_device *device,
502 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
503 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
505 const struct wined3d_gl_info *gl_info;
506 struct wined3d_context *context;
507 DWORD src_mask, dst_mask;
508 GLbitfield gl_mask;
510 TRACE("device %p\n", device);
511 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
512 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect));
513 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
514 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
516 src_mask = src_surface->container->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
517 dst_mask = dst_surface->container->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
519 if (src_mask != dst_mask)
521 ERR("Incompatible formats %s and %s.\n",
522 debug_d3dformat(src_surface->container->resource.format->id),
523 debug_d3dformat(dst_surface->container->resource.format->id));
524 return;
527 if (!src_mask)
529 ERR("Not a depth / stencil format: %s.\n",
530 debug_d3dformat(src_surface->container->resource.format->id));
531 return;
534 gl_mask = 0;
535 if (src_mask & WINED3DFMT_FLAG_DEPTH)
536 gl_mask |= GL_DEPTH_BUFFER_BIT;
537 if (src_mask & WINED3DFMT_FLAG_STENCIL)
538 gl_mask |= GL_STENCIL_BUFFER_BIT;
540 context = context_acquire(device, NULL);
541 if (!context->valid)
543 context_release(context);
544 WARN("Invalid context, skipping blit.\n");
545 return;
548 /* Make sure the locations are up-to-date. Loading the destination
549 * surface isn't required if the entire surface is overwritten. */
550 surface_load_location(src_surface, context, src_location);
551 if (!surface_is_full_rect(dst_surface, dst_rect))
552 surface_load_location(dst_surface, context, dst_location);
553 else
554 wined3d_surface_prepare(dst_surface, context, dst_location);
556 gl_info = context->gl_info;
558 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, src_location);
559 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
561 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, dst_location);
562 context_set_draw_buffer(context, GL_NONE);
563 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
564 context_invalidate_state(context, STATE_FRAMEBUFFER);
566 if (gl_mask & GL_DEPTH_BUFFER_BIT)
568 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
569 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
571 if (gl_mask & GL_STENCIL_BUFFER_BIT)
573 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
575 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
576 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
578 gl_info->gl_ops.gl.p_glStencilMask(~0U);
579 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
582 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
583 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
585 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
586 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
587 checkGLcall("glBlitFramebuffer()");
589 if (wined3d_settings.strict_draw_ordering)
590 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
592 context_release(context);
595 /* Blit between surface locations. Onscreen on different swapchains is not supported.
596 * Depth / stencil is not supported. Context activation is done by the caller. */
597 static void surface_blt_fbo(const struct wined3d_device *device,
598 struct wined3d_context *old_ctx, enum wined3d_texture_filter_type filter,
599 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
600 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
602 const struct wined3d_gl_info *gl_info;
603 struct wined3d_context *context = old_ctx;
604 struct wined3d_surface *required_rt, *restore_rt = NULL;
605 RECT src_rect, dst_rect;
606 GLenum gl_filter;
607 GLenum buffer;
609 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
610 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
611 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect_in));
612 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
613 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect_in));
615 src_rect = *src_rect_in;
616 dst_rect = *dst_rect_in;
618 switch (filter)
620 case WINED3D_TEXF_LINEAR:
621 gl_filter = GL_LINEAR;
622 break;
624 default:
625 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
626 case WINED3D_TEXF_NONE:
627 case WINED3D_TEXF_POINT:
628 gl_filter = GL_NEAREST;
629 break;
632 /* Resolve the source surface first if needed. */
633 if (src_location == WINED3D_LOCATION_RB_MULTISAMPLE
634 && (src_surface->container->resource.format->id != dst_surface->container->resource.format->id
635 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
636 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
637 src_location = WINED3D_LOCATION_RB_RESOLVED;
639 /* Make sure the locations are up-to-date. Loading the destination
640 * surface isn't required if the entire surface is overwritten. (And is
641 * in fact harmful if we're being called by surface_load_location() with
642 * the purpose of loading the destination surface.) */
643 surface_load_location(src_surface, old_ctx, src_location);
644 if (!surface_is_full_rect(dst_surface, &dst_rect))
645 surface_load_location(dst_surface, old_ctx, dst_location);
646 else
647 wined3d_surface_prepare(dst_surface, old_ctx, dst_location);
650 if (src_location == WINED3D_LOCATION_DRAWABLE) required_rt = src_surface;
651 else if (dst_location == WINED3D_LOCATION_DRAWABLE) required_rt = dst_surface;
652 else required_rt = NULL;
654 restore_rt = context_get_rt_surface(old_ctx);
655 if (restore_rt != required_rt)
656 context = context_acquire(device, required_rt);
657 else
658 restore_rt = NULL;
660 if (!context->valid)
662 context_release(context);
663 WARN("Invalid context, skipping blit.\n");
664 return;
667 gl_info = context->gl_info;
669 if (src_location == WINED3D_LOCATION_DRAWABLE)
671 TRACE("Source surface %p is onscreen.\n", src_surface);
672 buffer = wined3d_texture_get_gl_buffer(src_surface->container);
673 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
675 else
677 TRACE("Source surface %p is offscreen.\n", src_surface);
678 buffer = GL_COLOR_ATTACHMENT0;
681 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
682 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
683 checkGLcall("glReadBuffer()");
684 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
686 if (dst_location == WINED3D_LOCATION_DRAWABLE)
688 TRACE("Destination surface %p is onscreen.\n", dst_surface);
689 buffer = wined3d_texture_get_gl_buffer(dst_surface->container);
690 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
692 else
694 TRACE("Destination surface %p is offscreen.\n", dst_surface);
695 buffer = GL_COLOR_ATTACHMENT0;
698 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
699 context_set_draw_buffer(context, buffer);
700 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
701 context_invalidate_state(context, STATE_FRAMEBUFFER);
703 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
704 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
705 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
706 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
707 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
709 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
710 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
712 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
713 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
714 checkGLcall("glBlitFramebuffer()");
716 if (wined3d_settings.strict_draw_ordering
717 || (dst_location == WINED3D_LOCATION_DRAWABLE
718 && dst_surface->container->swapchain->front_buffer == dst_surface->container))
719 gl_info->gl_ops.gl.p_glFlush();
721 if (restore_rt)
722 context_restore(context, restore_rt);
725 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
726 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
727 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
729 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
730 return FALSE;
732 /* Source and/or destination need to be on the GL side */
733 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
734 return FALSE;
736 switch (blit_op)
738 case WINED3D_BLIT_OP_COLOR_BLIT:
739 if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
740 || (src_usage & WINED3DUSAGE_RENDERTARGET)))
741 return FALSE;
742 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
743 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
744 return FALSE;
745 if (!(src_format->id == dst_format->id
746 || (is_identity_fixup(src_format->color_fixup)
747 && is_identity_fixup(dst_format->color_fixup))))
748 return FALSE;
749 break;
751 case WINED3D_BLIT_OP_DEPTH_BLIT:
752 if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
753 return FALSE;
754 if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
755 return FALSE;
756 /* Accept pure swizzle fixups for depth formats. In general we
757 * ignore the stencil component (if present) at the moment and the
758 * swizzle is not relevant with just the depth component. */
759 if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
760 || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
761 return FALSE;
762 break;
764 default:
765 return FALSE;
768 return TRUE;
771 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
773 const struct wined3d_format *format = surface->container->resource.format;
775 switch (format->id)
777 case WINED3DFMT_S1_UINT_D15_UNORM:
778 *float_depth = depth / (float)0x00007fff;
779 break;
781 case WINED3DFMT_D16_UNORM:
782 *float_depth = depth / (float)0x0000ffff;
783 break;
785 case WINED3DFMT_D24_UNORM_S8_UINT:
786 case WINED3DFMT_X8D24_UNORM:
787 *float_depth = depth / (float)0x00ffffff;
788 break;
790 case WINED3DFMT_D32_UNORM:
791 *float_depth = depth / (float)0xffffffff;
792 break;
794 default:
795 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
796 return FALSE;
799 return TRUE;
802 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
804 struct wined3d_resource *resource = &surface->container->resource;
805 struct wined3d_device *device = resource->device;
806 struct wined3d_rendertarget_view_desc view_desc;
807 struct wined3d_rendertarget_view *view;
808 const struct blit_shader *blitter;
809 HRESULT hr;
811 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
812 WINED3D_BLIT_OP_DEPTH_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
814 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
815 return WINED3DERR_INVALIDCALL;
818 view_desc.format_id = resource->format->id;
819 view_desc.u.texture.level_idx = surface->texture_level;
820 view_desc.u.texture.layer_idx = surface->texture_layer;
821 view_desc.u.texture.layer_count = 1;
822 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
823 resource, NULL, &wined3d_null_parent_ops, &view)))
825 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
826 return hr;
829 hr = blitter->depth_fill(device, view, rect, WINED3DCLEAR_ZBUFFER, depth, 0);
830 wined3d_rendertarget_view_decref(view);
832 return hr;
835 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
836 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
838 struct wined3d_texture *src_texture = src_surface->container;
839 struct wined3d_texture *dst_texture = dst_surface->container;
840 struct wined3d_device *device = src_texture->resource.device;
842 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
843 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
844 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
845 return WINED3DERR_INVALIDCALL;
847 surface_depth_blt_fbo(device, src_surface, src_location, src_rect, dst_surface, dst_location, dst_rect);
849 surface_modify_ds_location(dst_surface, dst_location,
850 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
852 return WINED3D_OK;
855 static ULONG surface_resource_incref(struct wined3d_resource *resource)
857 struct wined3d_surface *surface = surface_from_resource(resource);
859 TRACE("surface %p, container %p.\n", surface, surface->container);
861 return wined3d_texture_incref(surface->container);
864 static ULONG surface_resource_decref(struct wined3d_resource *resource)
866 struct wined3d_surface *surface = surface_from_resource(resource);
868 TRACE("surface %p, container %p.\n", surface, surface->container);
870 return wined3d_texture_decref(surface->container);
873 static void surface_unload(struct wined3d_resource *resource)
875 struct wined3d_surface *surface = surface_from_resource(resource);
876 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
877 struct wined3d_texture *texture = surface->container;
878 struct wined3d_renderbuffer_entry *entry, *entry2;
879 struct wined3d_device *device = resource->device;
880 const struct wined3d_gl_info *gl_info;
881 struct wined3d_context *context;
883 TRACE("surface %p.\n", surface);
885 context = context_acquire(device, NULL);
886 gl_info = context->gl_info;
888 if (resource->pool == WINED3D_POOL_DEFAULT)
890 /* Default pool resources are supposed to be destroyed before Reset is called.
891 * Implicit resources stay however. So this means we have an implicit render target
892 * or depth stencil. The content may be destroyed, but we still have to tear down
893 * opengl resources, so we cannot leave early.
895 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
896 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
897 * or the depth stencil into an FBO the texture or render buffer will be removed
898 * and all flags get lost */
899 if (resource->usage & WINED3DUSAGE_DEPTHSTENCIL)
901 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
902 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_DISCARDED);
904 else
906 surface_prepare_system_memory(surface);
907 memset(surface->resource.heap_memory, 0, surface->resource.size);
908 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
909 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_SYSMEM);
912 else
914 surface_load_location(surface, context, surface->resource.map_binding);
915 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~surface->resource.map_binding);
918 /* Destroy fbo render buffers. This is needed for implicit render targets, for
919 * all application-created targets the application has to release the surface
920 * before calling _Reset
922 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
924 context_gl_resource_released(device, entry->id, TRUE);
925 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
926 list_remove(&entry->entry);
927 HeapFree(GetProcessHeap(), 0, entry);
929 list_init(&surface->renderbuffers);
930 surface->current_renderbuffer = NULL;
932 if (surface->rb_multisample)
934 context_gl_resource_released(device, surface->rb_multisample, TRUE);
935 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
936 surface->rb_multisample = 0;
938 if (surface->rb_resolved)
940 context_gl_resource_released(device, surface->rb_resolved, TRUE);
941 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
942 surface->rb_resolved = 0;
945 context_release(context);
947 resource_unload(resource);
950 static HRESULT surface_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx,
951 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
953 ERR("Not supported on sub-resources.\n");
954 return WINED3DERR_INVALIDCALL;
957 static HRESULT surface_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
959 ERR("Not supported on sub-resources.\n");
960 return WINED3DERR_INVALIDCALL;
963 static const struct wined3d_resource_ops surface_resource_ops =
965 surface_resource_incref,
966 surface_resource_decref,
967 surface_unload,
968 surface_resource_sub_resource_map,
969 surface_resource_sub_resource_unmap,
972 /* This call just downloads data, the caller is responsible for binding the
973 * correct texture. */
974 /* Context activation is done by the caller. */
975 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
976 DWORD dst_location)
978 struct wined3d_texture *texture = surface->container;
979 const struct wined3d_format *format = texture->resource.format;
980 struct wined3d_bo_address data;
982 /* Only support read back of converted P8 surfaces. */
983 if (texture->flags & WINED3D_TEXTURE_CONVERTED && format->id != WINED3DFMT_P8_UINT)
985 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
986 return;
989 wined3d_texture_get_memory(texture, surface_get_sub_resource_idx(surface), &data, dst_location);
991 if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
993 TRACE("(%p) : Calling glGetCompressedTexImage level %d, format %#x, type %#x, data %p.\n",
994 surface, surface->texture_level, format->glFormat, format->glType, data.addr);
996 if (data.buffer_object)
998 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
999 checkGLcall("glBindBuffer");
1000 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target, surface->texture_level, NULL));
1001 checkGLcall("glGetCompressedTexImage");
1002 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1003 checkGLcall("glBindBuffer");
1005 else
1007 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target,
1008 surface->texture_level, data.addr));
1009 checkGLcall("glGetCompressedTexImage");
1012 else
1014 unsigned int dst_row_pitch, dst_slice_pitch;
1015 unsigned int src_row_pitch, src_slice_pitch;
1016 GLenum gl_format = format->glFormat;
1017 GLenum gl_type = format->glType;
1018 void *mem;
1020 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1022 wined3d_texture_get_pitch(texture, surface->texture_level, &dst_row_pitch, &dst_slice_pitch);
1023 wined3d_format_calculate_pitch(format, texture->resource.device->surface_alignment,
1024 surface->pow2Width, surface->pow2Height, &src_row_pitch, &src_slice_pitch);
1025 mem = HeapAlloc(GetProcessHeap(), 0, src_slice_pitch);
1027 else
1029 mem = data.addr;
1032 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1033 surface, surface->texture_level, gl_format, gl_type, mem);
1035 if (data.buffer_object)
1037 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1038 checkGLcall("glBindBuffer");
1040 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1041 gl_format, gl_type, NULL);
1042 checkGLcall("glGetTexImage");
1044 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1045 checkGLcall("glBindBuffer");
1047 else
1049 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1050 gl_format, gl_type, mem);
1051 checkGLcall("glGetTexImage");
1054 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1056 const BYTE *src_data;
1057 unsigned int h, y;
1058 BYTE *dst_data;
1060 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1061 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1062 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1064 * We're doing this...
1066 * instead of boxing the texture :
1067 * |<-texture width ->| -->pow2width| /\
1068 * |111111111111111111| | |
1069 * |222 Texture 222222| boxed empty | texture height
1070 * |3333 Data 33333333| | |
1071 * |444444444444444444| | \/
1072 * ----------------------------------- |
1073 * | boxed empty | boxed empty | pow2height
1074 * | | | \/
1075 * -----------------------------------
1078 * we're repacking the data to the expected texture width
1080 * |<-texture width ->| -->pow2width| /\
1081 * |111111111111111111222222222222222| |
1082 * |222333333333333333333444444444444| texture height
1083 * |444444 | |
1084 * | | \/
1085 * | | |
1086 * | empty | pow2height
1087 * | | \/
1088 * -----------------------------------
1090 * == is the same as
1092 * |<-texture width ->| /\
1093 * |111111111111111111|
1094 * |222222222222222222|texture height
1095 * |333333333333333333|
1096 * |444444444444444444| \/
1097 * --------------------
1099 * This also means that any references to surface memory should work with the data as if it were a
1100 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1102 * internally the texture is still stored in a boxed format so any references to textureName will
1103 * get a boxed texture with width pow2width and not a texture of width resource.width. */
1104 src_data = mem;
1105 dst_data = data.addr;
1106 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch);
1107 h = wined3d_texture_get_level_height(texture, surface->texture_level);
1108 for (y = 0; y < h; ++y)
1110 memcpy(dst_data, src_data, dst_row_pitch);
1111 src_data += src_row_pitch;
1112 dst_data += dst_row_pitch;
1115 HeapFree(GetProcessHeap(), 0, mem);
1120 /* This call just uploads data, the caller is responsible for binding the
1121 * correct texture. */
1122 /* Context activation is done by the caller. */
1123 void wined3d_surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1124 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
1125 BOOL srgb, const struct wined3d_const_bo_address *data)
1127 struct wined3d_texture *texture = surface->container;
1128 UINT update_w = src_rect->right - src_rect->left;
1129 UINT update_h = src_rect->bottom - src_rect->top;
1131 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1132 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
1133 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
1135 if (surface->resource.map_count)
1137 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1138 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
1141 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
1143 update_h *= format->height_scale.numerator;
1144 update_h /= format->height_scale.denominator;
1147 if (data->buffer_object)
1149 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, data->buffer_object));
1150 checkGLcall("glBindBuffer");
1153 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1155 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1, 1);
1156 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
1157 const BYTE *addr = data->addr;
1158 GLenum internal;
1160 addr += (src_rect->top / format->block_height) * src_pitch;
1161 addr += (src_rect->left / format->block_width) * format->block_byte_count;
1163 if (srgb)
1164 internal = format->glGammaInternal;
1165 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET
1166 && wined3d_resource_is_offscreen(&texture->resource))
1167 internal = format->rtInternal;
1168 else
1169 internal = format->glInternal;
1171 TRACE("glCompressedTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, "
1172 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
1173 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
1175 if (row_length == src_pitch)
1177 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1178 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
1180 else
1182 UINT row, y;
1184 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1185 * can't use the unpack row length like for glTexSubImage2D. */
1186 for (row = 0, y = dst_point->y; row < row_count; ++row)
1188 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1189 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
1190 y += format->block_height;
1191 addr += src_pitch;
1194 checkGLcall("glCompressedTexSubImage2D");
1196 else
1198 const BYTE *addr = data->addr;
1200 addr += src_rect->top * src_pitch;
1201 addr += src_rect->left * format->byte_count;
1203 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1204 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
1205 update_w, update_h, format->glFormat, format->glType, addr);
1207 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
1208 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
1209 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
1210 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1211 checkGLcall("glTexSubImage2D");
1214 if (data->buffer_object)
1216 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1217 checkGLcall("glBindBuffer");
1220 if (wined3d_settings.strict_draw_ordering)
1221 gl_info->gl_ops.gl.p_glFlush();
1223 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1225 struct wined3d_device *device = texture->resource.device;
1226 unsigned int i;
1228 for (i = 0; i < device->context_count; ++i)
1230 context_surface_update(device->contexts[i], surface);
1235 static BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
1237 struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
1239 return wined3d_texture_check_block_align(surface->container, surface->texture_level, &box);
1242 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
1243 struct wined3d_surface *src_surface, const RECT *src_rect)
1245 unsigned int src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
1246 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1247 struct wined3d_texture *src_texture = src_surface->container;
1248 struct wined3d_texture *dst_texture = dst_surface->container;
1249 unsigned int src_row_pitch, src_slice_pitch;
1250 const struct wined3d_format *src_format;
1251 const struct wined3d_format *dst_format;
1252 unsigned int src_fmt_flags, dst_fmt_flags;
1253 const struct wined3d_gl_info *gl_info;
1254 struct wined3d_context *context;
1255 struct wined3d_bo_address data;
1256 UINT update_w, update_h;
1257 UINT dst_w, dst_h;
1258 RECT r, dst_rect;
1259 POINT p;
1261 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1262 dst_surface, wine_dbgstr_point(dst_point),
1263 src_surface, wine_dbgstr_rect(src_rect));
1265 src_format = src_texture->resource.format;
1266 dst_format = dst_texture->resource.format;
1267 src_fmt_flags = src_texture->resource.format_flags;
1268 dst_fmt_flags = dst_texture->resource.format_flags;
1270 if (src_format->id != dst_format->id)
1272 WARN("Source and destination surfaces should have the same format.\n");
1273 return WINED3DERR_INVALIDCALL;
1276 if (!dst_point)
1278 p.x = 0;
1279 p.y = 0;
1280 dst_point = &p;
1282 else if (dst_point->x < 0 || dst_point->y < 0)
1284 WARN("Invalid destination point.\n");
1285 return WINED3DERR_INVALIDCALL;
1288 if (!src_rect)
1290 SetRect(&r, 0, 0, wined3d_texture_get_level_width(src_texture, src_surface->texture_level),
1291 wined3d_texture_get_level_height(src_texture, src_surface->texture_level));
1292 src_rect = &r;
1294 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
1295 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
1297 WARN("Invalid source rectangle.\n");
1298 return WINED3DERR_INVALIDCALL;
1301 dst_w = wined3d_texture_get_level_width(dst_texture, dst_surface->texture_level);
1302 dst_h = wined3d_texture_get_level_height(dst_texture, dst_surface->texture_level);
1304 update_w = src_rect->right - src_rect->left;
1305 update_h = src_rect->bottom - src_rect->top;
1307 if (update_w > dst_w || dst_point->x > dst_w - update_w
1308 || update_h > dst_h || dst_point->y > dst_h - update_h)
1310 WARN("Destination out of bounds.\n");
1311 return WINED3DERR_INVALIDCALL;
1314 if ((src_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(src_surface, src_rect))
1316 WARN("Source rectangle not block-aligned.\n");
1317 return WINED3DERR_INVALIDCALL;
1320 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
1321 if ((dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(dst_surface, &dst_rect))
1323 WARN("Destination rectangle not block-aligned.\n");
1324 return WINED3DERR_INVALIDCALL;
1327 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1328 if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_texture, FALSE))
1329 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
1331 context = context_acquire(dst_texture->resource.device, NULL);
1332 gl_info = context->gl_info;
1334 /* Only load the surface for partial updates. For newly allocated texture
1335 * the texture wouldn't be the current location, and we'd upload zeroes
1336 * just to overwrite them again. */
1337 if (update_w == dst_w && update_h == dst_h)
1338 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1339 else
1340 surface_load_location(dst_surface, context, WINED3D_LOCATION_TEXTURE_RGB);
1341 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1343 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data,
1344 src_texture->sub_resources[src_sub_resource_idx].locations);
1345 wined3d_texture_get_pitch(src_texture, src_surface->texture_level, &src_row_pitch, &src_slice_pitch);
1347 wined3d_surface_upload_data(dst_surface, gl_info, src_format, src_rect,
1348 src_row_pitch, dst_point, FALSE, wined3d_const_bo_address(&data));
1350 context_release(context);
1352 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1353 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1355 return WINED3D_OK;
1358 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1359 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1360 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1361 /* Context activation is done by the caller. */
1362 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
1364 const struct wined3d_gl_info *gl_info = &surface->container->resource.device->adapter->gl_info;
1365 struct wined3d_renderbuffer_entry *entry;
1366 GLuint renderbuffer = 0;
1367 unsigned int src_width, src_height;
1368 unsigned int width, height;
1370 if (rt && rt->container->resource.format->id != WINED3DFMT_NULL)
1372 width = rt->pow2Width;
1373 height = rt->pow2Height;
1375 else
1377 width = surface->pow2Width;
1378 height = surface->pow2Height;
1381 src_width = surface->pow2Width;
1382 src_height = surface->pow2Height;
1384 /* A depth stencil smaller than the render target is not valid */
1385 if (width > src_width || height > src_height) return;
1387 /* Remove any renderbuffer set if the sizes match */
1388 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1389 || (width == src_width && height == src_height))
1391 surface->current_renderbuffer = NULL;
1392 return;
1395 /* Look if we've already got a renderbuffer of the correct dimensions */
1396 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1398 if (entry->width == width && entry->height == height)
1400 renderbuffer = entry->id;
1401 surface->current_renderbuffer = entry;
1402 break;
1406 if (!renderbuffer)
1408 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1409 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1410 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1411 surface->container->resource.format->glInternal, width, height);
1413 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
1414 entry->width = width;
1415 entry->height = height;
1416 entry->id = renderbuffer;
1417 list_add_head(&surface->renderbuffers, &entry->entry);
1419 surface->current_renderbuffer = entry;
1422 checkGLcall("set_compatible_renderbuffer");
1425 /* See also float_16_to_32() in wined3d_private.h */
1426 static inline unsigned short float_32_to_16(const float *in)
1428 int exp = 0;
1429 float tmp = fabsf(*in);
1430 unsigned int mantissa;
1431 unsigned short ret;
1433 /* Deal with special numbers */
1434 if (*in == 0.0f)
1435 return 0x0000;
1436 if (isnan(*in))
1437 return 0x7c01;
1438 if (isinf(*in))
1439 return (*in < 0.0f ? 0xfc00 : 0x7c00);
1441 if (tmp < (float)(1u << 10))
1445 tmp = tmp * 2.0f;
1446 exp--;
1447 } while (tmp < (float)(1u << 10));
1449 else if (tmp >= (float)(1u << 11))
1453 tmp /= 2.0f;
1454 exp++;
1455 } while (tmp >= (float)(1u << 11));
1458 mantissa = (unsigned int)tmp;
1459 if (tmp - mantissa >= 0.5f)
1460 ++mantissa; /* Round to nearest, away from zero. */
1462 exp += 10; /* Normalize the mantissa. */
1463 exp += 15; /* Exponent is encoded with excess 15. */
1465 if (exp > 30) /* too big */
1467 ret = 0x7c00; /* INF */
1469 else if (exp <= 0)
1471 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1472 while (exp <= 0)
1474 mantissa = mantissa >> 1;
1475 ++exp;
1477 ret = mantissa & 0x3ff;
1479 else
1481 ret = (exp << 10) | (mantissa & 0x3ff);
1484 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
1485 return ret;
1488 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
1489 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1491 unsigned short *dst_s;
1492 const float *src_f;
1493 unsigned int x, y;
1495 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1497 for (y = 0; y < h; ++y)
1499 src_f = (const float *)(src + y * pitch_in);
1500 dst_s = (unsigned short *) (dst + y * pitch_out);
1501 for (x = 0; x < w; ++x)
1503 dst_s[x] = float_32_to_16(src_f + x);
1508 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
1509 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1511 static const unsigned char convert_5to8[] =
1513 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1514 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1515 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1516 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1518 static const unsigned char convert_6to8[] =
1520 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1521 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1522 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1523 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1524 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1525 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1526 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1527 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1529 unsigned int x, y;
1531 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1533 for (y = 0; y < h; ++y)
1535 const WORD *src_line = (const WORD *)(src + y * pitch_in);
1536 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1537 for (x = 0; x < w; ++x)
1539 WORD pixel = src_line[x];
1540 dst_line[x] = 0xff000000u
1541 | convert_5to8[(pixel & 0xf800u) >> 11] << 16
1542 | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
1543 | convert_5to8[(pixel & 0x001fu)];
1548 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1549 * in both cases we're just setting the X / Alpha channel to 0xff. */
1550 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
1551 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1553 unsigned int x, y;
1555 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1557 for (y = 0; y < h; ++y)
1559 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
1560 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1562 for (x = 0; x < w; ++x)
1564 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
1569 static inline BYTE cliptobyte(int x)
1571 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
1574 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
1575 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1577 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1578 unsigned int x, y;
1580 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1582 for (y = 0; y < h; ++y)
1584 const BYTE *src_line = src + y * pitch_in;
1585 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1586 for (x = 0; x < w; ++x)
1588 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1589 * C = Y - 16; D = U - 128; E = V - 128;
1590 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1591 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1592 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1593 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1594 * U and V are shared between the pixels. */
1595 if (!(x & 1)) /* For every even pixel, read new U and V. */
1597 d = (int) src_line[1] - 128;
1598 e = (int) src_line[3] - 128;
1599 r2 = 409 * e + 128;
1600 g2 = - 100 * d - 208 * e + 128;
1601 b2 = 516 * d + 128;
1603 c2 = 298 * ((int) src_line[0] - 16);
1604 dst_line[x] = 0xff000000
1605 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
1606 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
1607 | cliptobyte((c2 + b2) >> 8); /* blue */
1608 /* Scale RGB values to 0..255 range,
1609 * then clip them if still not in range (may be negative),
1610 * then shift them within DWORD if necessary. */
1611 src_line += 2;
1616 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
1617 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1619 unsigned int x, y;
1620 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1622 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
1624 for (y = 0; y < h; ++y)
1626 const BYTE *src_line = src + y * pitch_in;
1627 WORD *dst_line = (WORD *)(dst + y * pitch_out);
1628 for (x = 0; x < w; ++x)
1630 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1631 * C = Y - 16; D = U - 128; E = V - 128;
1632 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1633 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1634 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1635 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1636 * U and V are shared between the pixels. */
1637 if (!(x & 1)) /* For every even pixel, read new U and V. */
1639 d = (int) src_line[1] - 128;
1640 e = (int) src_line[3] - 128;
1641 r2 = 409 * e + 128;
1642 g2 = - 100 * d - 208 * e + 128;
1643 b2 = 516 * d + 128;
1645 c2 = 298 * ((int) src_line[0] - 16);
1646 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
1647 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
1648 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
1649 /* Scale RGB values to 0..255 range,
1650 * then clip them if still not in range (may be negative),
1651 * then shift them within DWORD if necessary. */
1652 src_line += 2;
1657 struct d3dfmt_converter_desc
1659 enum wined3d_format_id from, to;
1660 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
1663 static const struct d3dfmt_converter_desc converters[] =
1665 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
1666 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
1667 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1668 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1669 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
1670 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
1673 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
1674 enum wined3d_format_id to)
1676 unsigned int i;
1678 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
1680 if (converters[i].from == from && converters[i].to == to)
1681 return &converters[i];
1684 return NULL;
1687 static struct wined3d_texture *surface_convert_format(struct wined3d_texture *src_texture,
1688 unsigned int sub_resource_idx, const struct wined3d_format *dst_format)
1690 const struct wined3d_format *src_format = src_texture->resource.format;
1691 struct wined3d_device *device = src_texture->resource.device;
1692 const struct d3dfmt_converter_desc *conv = NULL;
1693 struct wined3d_texture *dst_texture;
1694 struct wined3d_resource_desc desc;
1695 struct wined3d_map_desc src_map;
1697 if (!(conv = find_converter(src_format->id, dst_format->id)) && (!device->d3d_initialized
1698 || !is_identity_fixup(src_format->color_fixup) || src_format->convert
1699 || !is_identity_fixup(dst_format->color_fixup) || dst_format->convert))
1701 FIXME("Cannot find a conversion function from format %s to %s.\n",
1702 debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
1703 return NULL;
1706 /* FIXME: Multisampled conversion? */
1707 wined3d_resource_get_desc(src_texture->sub_resources[sub_resource_idx].resource, &desc);
1708 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1709 desc.format = dst_format->id;
1710 desc.usage = 0;
1711 desc.pool = WINED3D_POOL_SCRATCH;
1712 if (FAILED(wined3d_texture_create(device, &desc, 1,
1713 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
1714 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
1716 ERR("Failed to create a destination texture for conversion.\n");
1717 return NULL;
1720 memset(&src_map, 0, sizeof(src_map));
1721 if (FAILED(wined3d_resource_map(&src_texture->resource, sub_resource_idx,
1722 &src_map, NULL, WINED3D_MAP_READONLY)))
1724 ERR("Failed to map the source texture.\n");
1725 wined3d_texture_decref(dst_texture);
1726 return NULL;
1728 if (conv)
1730 struct wined3d_map_desc dst_map;
1732 memset(&dst_map, 0, sizeof(dst_map));
1733 if (FAILED(wined3d_resource_map(&dst_texture->resource, 0, &dst_map, NULL, 0)))
1735 ERR("Failed to map the destination texture.\n");
1736 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1737 wined3d_texture_decref(dst_texture);
1738 return NULL;
1741 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch, desc.width, desc.height);
1743 wined3d_resource_unmap(&dst_texture->resource, 0);
1745 else
1747 struct wined3d_bo_address data = {0, src_map.data};
1748 RECT src_rect = {0, 0, desc.width, desc.height};
1749 const struct wined3d_gl_info *gl_info;
1750 struct wined3d_context *context;
1751 POINT dst_point = {0, 0};
1753 TRACE("Using upload conversion.\n");
1754 context = context_acquire(device, NULL);
1755 gl_info = context->gl_info;
1757 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1758 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1759 wined3d_surface_upload_data(dst_texture->sub_resources[0].u.surface, gl_info, src_format,
1760 &src_rect, src_map.row_pitch, &dst_point, FALSE, wined3d_const_bo_address(&data));
1762 context_release(context);
1764 wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
1765 wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
1767 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1769 return dst_texture;
1772 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
1773 unsigned int bpp, UINT pitch, DWORD color)
1775 BYTE *first;
1776 unsigned int x, y;
1778 /* Do first row */
1780 #define COLORFILL_ROW(type) \
1781 do { \
1782 type *d = (type *)buf; \
1783 for (x = 0; x < width; ++x) \
1784 d[x] = (type)color; \
1785 } while(0)
1787 switch (bpp)
1789 case 1:
1790 COLORFILL_ROW(BYTE);
1791 break;
1793 case 2:
1794 COLORFILL_ROW(WORD);
1795 break;
1797 case 3:
1799 BYTE *d = buf;
1800 for (x = 0; x < width; ++x, d += 3)
1802 d[0] = (color ) & 0xff;
1803 d[1] = (color >> 8) & 0xff;
1804 d[2] = (color >> 16) & 0xff;
1806 break;
1808 case 4:
1809 COLORFILL_ROW(DWORD);
1810 break;
1812 default:
1813 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
1814 return WINED3DERR_NOTAVAILABLE;
1817 #undef COLORFILL_ROW
1819 /* Now copy first row. */
1820 first = buf;
1821 for (y = 1; y < height; ++y)
1823 buf += pitch;
1824 memcpy(buf, first, width * bpp);
1827 return WINED3D_OK;
1830 static void read_from_framebuffer(struct wined3d_surface *surface,
1831 struct wined3d_context *old_ctx, DWORD dst_location)
1833 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
1834 struct wined3d_texture *texture = surface->container;
1835 struct wined3d_device *device = texture->resource.device;
1836 const struct wined3d_gl_info *gl_info;
1837 struct wined3d_context *context = old_ctx;
1838 struct wined3d_surface *restore_rt = NULL;
1839 unsigned int row_pitch, slice_pitch;
1840 unsigned int width, height;
1841 BYTE *mem;
1842 BYTE *row, *top, *bottom;
1843 int i;
1844 BOOL srcIsUpsideDown;
1845 struct wined3d_bo_address data;
1847 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1849 restore_rt = context_get_rt_surface(old_ctx);
1850 if (restore_rt != surface)
1851 context = context_acquire(device, surface);
1852 else
1853 restore_rt = NULL;
1855 context_apply_blit_state(context, device);
1856 gl_info = context->gl_info;
1858 /* Select the correct read buffer, and give some debug output.
1859 * There is no need to keep track of the current read buffer or reset it, every part of the code
1860 * that reads sets the read buffer as desired.
1862 if (wined3d_resource_is_offscreen(&texture->resource))
1864 /* Mapping the primary render target which is not on a swapchain.
1865 * Read from the back buffer. */
1866 TRACE("Mapping offscreen render target.\n");
1867 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1868 srcIsUpsideDown = TRUE;
1870 else
1872 /* Onscreen surfaces are always part of a swapchain */
1873 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
1874 TRACE("Mapping %#x buffer.\n", buffer);
1875 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1876 checkGLcall("glReadBuffer");
1877 srcIsUpsideDown = FALSE;
1880 if (data.buffer_object)
1882 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1883 checkGLcall("glBindBuffer");
1886 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
1888 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1889 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / texture->resource.format->byte_count);
1890 checkGLcall("glPixelStorei");
1892 width = wined3d_texture_get_level_width(texture, surface->texture_level);
1893 height = wined3d_texture_get_level_height(texture, surface->texture_level);
1894 gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
1895 texture->resource.format->glFormat,
1896 texture->resource.format->glType, data.addr);
1897 checkGLcall("glReadPixels");
1899 /* Reset previous pixel store pack state */
1900 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1901 checkGLcall("glPixelStorei");
1903 if (!srcIsUpsideDown)
1905 /* glReadPixels returns the image upside down, and there is no way to
1906 * prevent this. Flip the lines in software. */
1908 if (!(row = HeapAlloc(GetProcessHeap(), 0, row_pitch)))
1909 goto error;
1911 if (data.buffer_object)
1913 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
1914 checkGLcall("glMapBuffer");
1916 else
1917 mem = data.addr;
1919 top = mem;
1920 bottom = mem + row_pitch * (height - 1);
1921 for (i = 0; i < height / 2; i++)
1923 memcpy(row, top, row_pitch);
1924 memcpy(top, bottom, row_pitch);
1925 memcpy(bottom, row, row_pitch);
1926 top += row_pitch;
1927 bottom -= row_pitch;
1929 HeapFree(GetProcessHeap(), 0, row);
1931 if (data.buffer_object)
1932 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
1935 error:
1936 if (data.buffer_object)
1938 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1939 checkGLcall("glBindBuffer");
1942 if (restore_rt)
1943 context_restore(context, restore_rt);
1946 /* Read the framebuffer contents into a texture. Note that this function
1947 * doesn't do any kind of flipping. Using this on an onscreen surface will
1948 * result in a flipped D3D texture.
1950 * Context activation is done by the caller. This function may temporarily
1951 * switch to a different context and restore the original one before return. */
1952 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct wined3d_context *old_ctx)
1954 struct wined3d_texture *texture = surface->container;
1955 struct wined3d_device *device = texture->resource.device;
1956 const struct wined3d_gl_info *gl_info;
1957 struct wined3d_context *context = old_ctx;
1958 struct wined3d_surface *restore_rt = NULL;
1960 restore_rt = context_get_rt_surface(old_ctx);
1961 if (restore_rt != surface)
1962 context = context_acquire(device, surface);
1963 else
1964 restore_rt = NULL;
1966 gl_info = context->gl_info;
1967 device_invalidate_state(device, STATE_FRAMEBUFFER);
1969 wined3d_texture_prepare_texture(texture, context, srgb);
1970 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1972 TRACE("Reading back offscreen render target %p.\n", surface);
1974 if (wined3d_resource_is_offscreen(&texture->resource))
1975 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1976 else
1977 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
1978 checkGLcall("glReadBuffer");
1980 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
1981 0, 0, 0, 0, wined3d_texture_get_level_width(texture, surface->texture_level),
1982 wined3d_texture_get_level_height(texture, surface->texture_level));
1983 checkGLcall("glCopyTexSubImage2D");
1985 if (restore_rt)
1986 context_restore(context, restore_rt);
1989 static void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
1991 struct wined3d_texture *texture = surface->container;
1992 const struct wined3d_format *format = texture->resource.format;
1994 if (multisample)
1996 DWORD samples;
1998 if (surface->rb_multisample)
1999 return;
2001 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
2002 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
2003 * to GL_NV_framebuffer_multisample_coverage.
2005 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
2006 * but it does not have an equivalent OpenGL extension. */
2008 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
2009 * as the count of advertised multisample types for the surface format. */
2010 if (texture->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE)
2012 unsigned int i, count = 0;
2014 for (i = 0; i < sizeof(format->multisample_types) * 8; ++i)
2016 if (format->multisample_types & 1u << i)
2018 if (texture->resource.multisample_quality == count++)
2019 break;
2022 samples = i + 1;
2024 else
2026 samples = texture->resource.multisample_type;
2029 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
2030 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
2031 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
2032 format->glInternal, surface->pow2Width, surface->pow2Height);
2033 checkGLcall("glRenderbufferStorageMultisample()");
2034 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
2036 else
2038 if (surface->rb_resolved)
2039 return;
2041 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
2042 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
2043 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format->glInternal,
2044 surface->pow2Width, surface->pow2Height);
2045 checkGLcall("glRenderbufferStorage()");
2046 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
2050 /* Does a direct frame buffer -> texture copy. Stretching is done with single
2051 * pixel copy calls. */
2052 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2053 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2055 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2056 struct wined3d_texture *src_texture = src_surface->container;
2057 struct wined3d_texture *dst_texture = dst_surface->container;
2058 struct wined3d_device *device = dst_texture->resource.device;
2059 const struct wined3d_gl_info *gl_info;
2060 float xrel, yrel;
2061 struct wined3d_context *context;
2062 BOOL upsidedown = FALSE;
2063 RECT dst_rect = *dst_rect_in;
2064 unsigned int src_height;
2066 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2067 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2069 if(dst_rect.top > dst_rect.bottom) {
2070 UINT tmp = dst_rect.bottom;
2071 dst_rect.bottom = dst_rect.top;
2072 dst_rect.top = tmp;
2073 upsidedown = TRUE;
2076 context = context_acquire(device, src_surface);
2077 gl_info = context->gl_info;
2078 context_apply_blit_state(context, device);
2079 wined3d_texture_load(dst_texture, context, FALSE);
2081 /* Bind the target texture */
2082 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
2083 if (wined3d_resource_is_offscreen(&src_texture->resource))
2085 TRACE("Reading from an offscreen target\n");
2086 upsidedown = !upsidedown;
2087 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
2089 else
2091 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2093 checkGLcall("glReadBuffer");
2095 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
2096 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
2098 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2100 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2102 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2103 ERR("Texture filtering not supported in direct blit.\n");
2105 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2106 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2108 ERR("Texture filtering not supported in direct blit\n");
2111 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2112 if (upsidedown
2113 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2114 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2116 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
2117 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2118 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
2119 src_rect->left, src_height - src_rect->bottom,
2120 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2122 else
2124 LONG row;
2125 UINT yoffset = src_height - src_rect->top + dst_rect.top - 1;
2126 /* I have to process this row by row to swap the image,
2127 * otherwise it would be upside down, so stretching in y direction
2128 * doesn't cost extra time
2130 * However, stretching in x direction can be avoided if not necessary
2132 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
2133 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2135 /* Well, that stuff works, but it's very slow.
2136 * find a better way instead
2138 LONG col;
2140 for (col = dst_rect.left; col < dst_rect.right; ++col)
2142 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2143 dst_rect.left + col /* x offset */, row /* y offset */,
2144 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
2147 else
2149 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2150 dst_rect.left /* x offset */, row /* y offset */,
2151 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
2155 checkGLcall("glCopyTexSubImage2D");
2157 context_release(context);
2159 /* The texture is now most up to date - If the surface is a render target
2160 * and has a drawable, this path is never entered. */
2161 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2162 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2165 /* Uses the hardware to stretch and flip the image */
2166 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2167 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2169 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2170 struct wined3d_texture *src_texture = src_surface->container;
2171 struct wined3d_texture *dst_texture = dst_surface->container;
2172 struct wined3d_device *device = dst_texture->resource.device;
2173 GLuint src, backup = 0;
2174 float left, right, top, bottom; /* Texture coordinates */
2175 const struct wined3d_gl_info *gl_info;
2176 unsigned int src_width, src_height;
2177 struct wined3d_context *context;
2178 GLenum drawBuffer = GL_BACK;
2179 GLenum offscreen_buffer;
2180 GLenum texture_target;
2181 BOOL noBackBufferBackup;
2182 BOOL src_offscreen;
2183 BOOL upsidedown = FALSE;
2184 RECT dst_rect = *dst_rect_in;
2186 TRACE("Using hwstretch blit\n");
2187 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2188 context = context_acquire(device, src_surface);
2189 gl_info = context->gl_info;
2190 context_apply_blit_state(context, device);
2191 wined3d_texture_load(dst_texture, context, FALSE);
2193 offscreen_buffer = context_get_offscreen_gl_buffer(context);
2194 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
2195 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2197 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
2198 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
2199 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
2201 /* Get it a description */
2202 wined3d_texture_load(src_texture, context, FALSE);
2205 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2206 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2208 if (context->aux_buffers >= 2)
2210 /* Got more than one aux buffer? Use the 2nd aux buffer */
2211 drawBuffer = GL_AUX1;
2213 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
2215 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2216 drawBuffer = GL_AUX0;
2219 if (noBackBufferBackup)
2221 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
2222 checkGLcall("glGenTextures");
2223 context_bind_texture(context, GL_TEXTURE_2D, backup);
2224 texture_target = GL_TEXTURE_2D;
2226 else
2228 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2229 * we are reading from the back buffer, the backup can be used as source texture
2231 texture_target = src_surface->texture_target;
2232 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
2233 gl_info->gl_ops.gl.p_glEnable(texture_target);
2234 checkGLcall("glEnable(texture_target)");
2236 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2237 surface_get_sub_resource(src_surface)->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
2240 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2241 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2243 if(dst_rect.top > dst_rect.bottom) {
2244 UINT tmp = dst_rect.bottom;
2245 dst_rect.bottom = dst_rect.top;
2246 dst_rect.top = tmp;
2247 upsidedown = TRUE;
2250 if (src_offscreen)
2252 TRACE("Reading from an offscreen target\n");
2253 upsidedown = !upsidedown;
2254 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
2256 else
2258 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2261 /* TODO: Only back up the part that will be overwritten */
2262 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, src_width, src_height);
2264 checkGLcall("glCopyTexSubImage2D");
2266 /* No issue with overriding these - the sampler is dirty due to blit usage */
2267 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
2268 checkGLcall("glTexParameteri");
2269 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2270 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
2271 checkGLcall("glTexParameteri");
2273 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
2275 src = backup ? backup : src_texture->texture_rgb.name;
2277 else
2279 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
2280 checkGLcall("glReadBuffer(GL_FRONT)");
2282 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
2283 checkGLcall("glGenTextures(1, &src)");
2284 context_bind_texture(context, GL_TEXTURE_2D, src);
2286 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
2287 * out for power of 2 sizes
2289 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
2290 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2291 checkGLcall("glTexImage2D");
2292 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_width, src_height);
2294 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2295 checkGLcall("glTexParameteri");
2296 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2297 checkGLcall("glTexParameteri");
2299 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
2300 checkGLcall("glReadBuffer(GL_BACK)");
2302 if (texture_target != GL_TEXTURE_2D)
2304 gl_info->gl_ops.gl.p_glDisable(texture_target);
2305 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2306 texture_target = GL_TEXTURE_2D;
2309 checkGLcall("glEnd and previous");
2311 left = src_rect->left;
2312 right = src_rect->right;
2314 if (!upsidedown)
2316 top = src_height - src_rect->top;
2317 bottom = src_height - src_rect->bottom;
2319 else
2321 top = src_height - src_rect->bottom;
2322 bottom = src_height - src_rect->top;
2325 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
2327 left /= src_surface->pow2Width;
2328 right /= src_surface->pow2Width;
2329 top /= src_surface->pow2Height;
2330 bottom /= src_surface->pow2Height;
2333 /* draw the source texture stretched and upside down. The correct surface is bound already */
2334 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2335 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2337 context_set_draw_buffer(context, drawBuffer);
2338 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
2340 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2341 /* bottom left */
2342 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
2343 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2345 /* top left */
2346 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
2347 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
2349 /* top right */
2350 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
2351 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2353 /* bottom right */
2354 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
2355 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
2356 gl_info->gl_ops.gl.p_glEnd();
2357 checkGLcall("glEnd and previous");
2359 if (texture_target != dst_surface->texture_target)
2361 gl_info->gl_ops.gl.p_glDisable(texture_target);
2362 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
2363 texture_target = dst_surface->texture_target;
2366 /* Now read the stretched and upside down image into the destination texture */
2367 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
2368 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
2370 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
2371 0, 0, /* We blitted the image to the origin */
2372 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2373 checkGLcall("glCopyTexSubImage2D");
2375 if (drawBuffer == GL_BACK)
2377 /* Write the back buffer backup back. */
2378 if (backup)
2380 if (texture_target != GL_TEXTURE_2D)
2382 gl_info->gl_ops.gl.p_glDisable(texture_target);
2383 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2384 texture_target = GL_TEXTURE_2D;
2386 context_bind_texture(context, GL_TEXTURE_2D, backup);
2388 else
2390 if (texture_target != src_surface->texture_target)
2392 gl_info->gl_ops.gl.p_glDisable(texture_target);
2393 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
2394 texture_target = src_surface->texture_target;
2396 context_bind_texture(context, src_surface->texture_target, src_texture->texture_rgb.name);
2399 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2400 /* top left */
2401 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
2402 gl_info->gl_ops.gl.p_glVertex2i(0, src_height);
2404 /* bottom left */
2405 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)src_height / (float)src_surface->pow2Height);
2406 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2408 /* bottom right */
2409 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_surface->pow2Width,
2410 (float)src_height / (float)src_surface->pow2Height);
2411 gl_info->gl_ops.gl.p_glVertex2i(src_width, 0);
2413 /* top right */
2414 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_surface->pow2Width, 0.0f);
2415 gl_info->gl_ops.gl.p_glVertex2i(src_width, src_height);
2416 gl_info->gl_ops.gl.p_glEnd();
2418 gl_info->gl_ops.gl.p_glDisable(texture_target);
2419 checkGLcall("glDisable(texture_target)");
2421 /* Cleanup */
2422 if (src != src_texture->texture_rgb.name && src != backup)
2424 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
2425 checkGLcall("glDeleteTextures(1, &src)");
2427 if (backup)
2429 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
2430 checkGLcall("glDeleteTextures(1, &backup)");
2433 if (wined3d_settings.strict_draw_ordering)
2434 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2436 context_release(context);
2438 /* The texture is now most up to date - If the surface is a render target
2439 * and has a drawable, this path is never entered. */
2440 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2441 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2444 /* Front buffer coordinates are always full screen coordinates, but our GL
2445 * drawable is limited to the window's client area. The sysmem and texture
2446 * copies do have the full screen size. Note that GL has a bottom-left
2447 * origin, while D3D has a top-left origin. */
2448 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
2450 struct wined3d_texture *texture = surface->container;
2451 UINT drawable_height;
2453 if (texture->swapchain && texture == texture->swapchain->front_buffer)
2455 POINT offset = {0, 0};
2456 RECT windowsize;
2458 ScreenToClient(window, &offset);
2459 OffsetRect(rect, offset.x, offset.y);
2461 GetClientRect(window, &windowsize);
2462 drawable_height = windowsize.bottom - windowsize.top;
2464 else
2466 drawable_height = wined3d_texture_get_level_height(texture, surface->texture_level);
2469 rect->top = drawable_height - rect->top;
2470 rect->bottom = drawable_height - rect->bottom;
2473 /* Context activation is done by the caller. */
2474 static void surface_blt_to_drawable(const struct wined3d_device *device,
2475 struct wined3d_context *old_ctx,
2476 enum wined3d_texture_filter_type filter, BOOL alpha_test,
2477 struct wined3d_surface *src_surface, const RECT *src_rect_in,
2478 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
2480 struct wined3d_texture *src_texture = src_surface->container;
2481 struct wined3d_texture *dst_texture = dst_surface->container;
2482 const struct wined3d_gl_info *gl_info;
2483 struct wined3d_context *context = old_ctx;
2484 struct wined3d_surface *restore_rt = NULL;
2485 RECT src_rect, dst_rect;
2487 src_rect = *src_rect_in;
2488 dst_rect = *dst_rect_in;
2490 restore_rt = context_get_rt_surface(old_ctx);
2491 if (restore_rt != dst_surface)
2492 context = context_acquire(device, dst_surface);
2493 else
2494 restore_rt = NULL;
2496 gl_info = context->gl_info;
2498 /* Make sure the surface is up-to-date. This should probably use
2499 * surface_load_location() and worry about the destination surface too,
2500 * unless we're overwriting it completely. */
2501 wined3d_texture_load(src_texture, context, FALSE);
2503 /* Activate the destination context, set it up for blitting */
2504 context_apply_blit_state(context, device);
2506 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
2507 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
2509 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
2511 if (alpha_test)
2513 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2514 checkGLcall("glEnable(GL_ALPHA_TEST)");
2516 /* For P8 surfaces, the alpha component contains the palette index.
2517 * Which means that the colorkey is one of the palette entries. In
2518 * other cases pixels that should be masked away have alpha set to 0. */
2519 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2520 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2521 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2522 else
2523 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2524 checkGLcall("glAlphaFunc");
2526 else
2528 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2529 checkGLcall("glDisable(GL_ALPHA_TEST)");
2532 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
2534 if (alpha_test)
2536 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2537 checkGLcall("glDisable(GL_ALPHA_TEST)");
2540 /* Leave the opengl state valid for blitting */
2541 device->blitter->unset_shader(context->gl_info);
2543 if (wined3d_settings.strict_draw_ordering
2544 || (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture))
2545 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2547 if (restore_rt)
2548 context_restore(context, restore_rt);
2551 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
2553 struct wined3d_resource *resource = &s->container->resource;
2554 struct wined3d_device *device = resource->device;
2555 struct wined3d_rendertarget_view_desc view_desc;
2556 struct wined3d_rendertarget_view *view;
2557 const struct blit_shader *blitter;
2558 HRESULT hr;
2560 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
2561 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
2563 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2564 return WINED3DERR_INVALIDCALL;
2567 view_desc.format_id = resource->format->id;
2568 view_desc.u.texture.level_idx = s->texture_level;
2569 view_desc.u.texture.layer_idx = s->texture_layer;
2570 view_desc.u.texture.layer_count = 1;
2571 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
2572 resource, NULL, &wined3d_null_parent_ops, &view)))
2574 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
2575 return hr;
2578 hr = blitter->color_fill(device, view, rect, color);
2579 wined3d_rendertarget_view_decref(view);
2581 return hr;
2584 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
2585 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
2586 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2588 struct wined3d_texture *dst_texture = dst_surface->container;
2589 struct wined3d_device *device = dst_texture->resource.device;
2590 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
2591 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
2592 struct wined3d_texture *src_texture;
2594 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2595 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2596 flags, fx, debug_d3dtexturefiltertype(filter));
2598 /* Get the swapchain. One of the surfaces has to be a primary surface */
2599 if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2601 WARN("Destination is in sysmem, rejecting gl blt\n");
2602 return WINED3DERR_INVALIDCALL;
2605 dst_swapchain = dst_texture->swapchain;
2607 if (src_surface)
2609 src_texture = src_surface->container;
2610 if (src_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2612 WARN("Src is in sysmem, rejecting gl blt\n");
2613 return WINED3DERR_INVALIDCALL;
2616 src_swapchain = src_texture->swapchain;
2618 else
2620 src_texture = NULL;
2621 src_swapchain = NULL;
2624 /* Early sort out of cases where no render target is used */
2625 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
2627 TRACE("No surface is render target, not using hardware blit.\n");
2628 return WINED3DERR_INVALIDCALL;
2631 /* No destination color keying supported */
2632 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
2634 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2635 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2636 return WINED3DERR_INVALIDCALL;
2639 if (dst_swapchain && dst_swapchain == src_swapchain)
2641 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2642 return WINED3DERR_INVALIDCALL;
2645 if (dst_swapchain && src_swapchain)
2647 FIXME("Implement hardware blit between two different swapchains\n");
2648 return WINED3DERR_INVALIDCALL;
2651 if (dst_swapchain)
2653 /* Handled with regular texture -> swapchain blit */
2654 if (src_surface == rt)
2655 TRACE("Blit from active render target to a swapchain\n");
2657 else if (src_swapchain && dst_surface == rt)
2659 FIXME("Implement blit from a swapchain to the active render target\n");
2660 return WINED3DERR_INVALIDCALL;
2663 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
2665 unsigned int src_width, src_height;
2666 /* Blit from render target to texture */
2667 BOOL stretchx;
2669 /* P8 read back is not implemented */
2670 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
2671 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
2673 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2674 return WINED3DERR_INVALIDCALL;
2677 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
2679 TRACE("Color keying not supported by frame buffer to texture blit\n");
2680 return WINED3DERR_INVALIDCALL;
2681 /* Destination color key is checked above */
2684 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
2685 stretchx = TRUE;
2686 else
2687 stretchx = FALSE;
2689 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2690 * flip the image nor scale it.
2692 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2693 * -> If the app wants an image width an unscaled width, copy it line per line
2694 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2695 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2696 * back buffer. This is slower than reading line per line, thus not used for flipping
2697 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2698 * pixel by pixel. */
2699 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
2700 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2701 if (!stretchx || dst_rect->right - dst_rect->left > src_width
2702 || dst_rect->bottom - dst_rect->top > src_height)
2704 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2705 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
2707 else
2709 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2710 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
2713 surface_evict_sysmem(dst_surface);
2715 return WINED3D_OK;
2718 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2719 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2720 return WINED3DERR_INVALIDCALL;
2723 /* Context activation is done by the caller. */
2724 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
2725 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
2727 struct wined3d_device *device = surface->container->resource.device;
2728 const struct wined3d_gl_info *gl_info = context->gl_info;
2729 GLint compare_mode = GL_NONE;
2730 struct blt_info info;
2731 GLint old_binding = 0;
2732 RECT rect;
2734 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
2736 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2737 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2738 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2739 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2740 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2741 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
2742 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
2743 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
2744 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2745 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
2746 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
2748 SetRect(&rect, 0, h, w, 0);
2749 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
2750 context_active_texture(context, context->gl_info, 0);
2751 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
2752 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
2753 if (gl_info->supported[ARB_SHADOW])
2755 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
2756 if (compare_mode != GL_NONE)
2757 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
2760 device->shader_backend->shader_select_depth_blt(device->shader_priv,
2761 gl_info, info.tex_type, &surface->ds_current_size);
2763 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
2764 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
2765 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
2766 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
2767 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
2768 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
2769 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
2770 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
2771 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
2772 gl_info->gl_ops.gl.p_glEnd();
2774 if (compare_mode != GL_NONE)
2775 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
2776 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
2778 gl_info->gl_ops.gl.p_glPopAttrib();
2780 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
2783 void surface_modify_ds_location(struct wined3d_surface *surface,
2784 DWORD location, UINT w, UINT h)
2786 struct wined3d_texture_sub_resource *sub_resource;
2788 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
2790 sub_resource = surface_get_sub_resource(surface);
2791 if (((sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
2792 || (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
2793 && (location & WINED3D_LOCATION_TEXTURE_RGB)))
2794 wined3d_texture_set_dirty(surface->container);
2796 surface->ds_current_size.cx = w;
2797 surface->ds_current_size.cy = h;
2798 sub_resource->locations = location;
2801 /* Context activation is done by the caller. */
2802 static void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
2804 struct wined3d_texture *texture = surface->container;
2805 struct wined3d_device *device = texture->resource.device;
2806 const struct wined3d_gl_info *gl_info = context->gl_info;
2807 GLsizei w, h;
2809 TRACE("surface %p, context %p, new location %#x.\n", surface, context, location);
2811 /* TODO: Make this work for modes other than FBO */
2812 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
2814 if (!(surface_get_sub_resource(surface)->locations & location))
2816 w = surface->ds_current_size.cx;
2817 h = surface->ds_current_size.cy;
2818 surface->ds_current_size.cx = 0;
2819 surface->ds_current_size.cy = 0;
2821 else
2823 w = wined3d_texture_get_level_width(surface->container, surface->texture_level);
2824 h = wined3d_texture_get_level_height(surface->container, surface->texture_level);
2827 if (surface->current_renderbuffer)
2829 FIXME("Not supported with fixed up depth stencil.\n");
2830 return;
2833 wined3d_surface_prepare(surface, context, location);
2835 if (location == WINED3D_LOCATION_TEXTURE_RGB)
2837 GLint old_binding = 0;
2838 GLenum bind_target;
2840 /* The render target is allowed to be smaller than the depth/stencil
2841 * buffer, so the onscreen depth/stencil buffer is potentially smaller
2842 * than the offscreen surface. Don't overwrite the offscreen surface
2843 * with undefined data. */
2844 w = min(w, context->swapchain->desc.backbuffer_width);
2845 h = min(h, context->swapchain->desc.backbuffer_height);
2847 TRACE("Copying onscreen depth buffer to depth texture.\n");
2849 if (!device->depth_blt_texture)
2850 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
2852 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2853 * directly on the FBO texture. That's because we need to flip. */
2854 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2855 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2856 NULL, WINED3D_LOCATION_DRAWABLE);
2857 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2859 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
2860 bind_target = GL_TEXTURE_RECTANGLE_ARB;
2862 else
2864 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
2865 bind_target = GL_TEXTURE_2D;
2867 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
2868 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
2869 * internal format, because the internal format might include stencil
2870 * data. In principle we should copy stencil data as well, but unless
2871 * the driver supports stencil export it's hard to do, and doesn't
2872 * seem to be needed in practice. If the hardware doesn't support
2873 * writing stencil data, the glCopyTexImage2D() call might trigger
2874 * software fallbacks. */
2875 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
2876 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2877 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2878 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2879 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2880 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2881 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
2883 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2884 NULL, surface, WINED3D_LOCATION_TEXTURE_RGB);
2885 context_set_draw_buffer(context, GL_NONE);
2887 /* Do the actual blit */
2888 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
2889 checkGLcall("depth_blt");
2891 context_invalidate_state(context, STATE_FRAMEBUFFER);
2893 if (wined3d_settings.strict_draw_ordering)
2894 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2896 else if (location == WINED3D_LOCATION_DRAWABLE)
2898 TRACE("Copying depth texture to onscreen depth buffer.\n");
2900 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2901 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2902 NULL, WINED3D_LOCATION_DRAWABLE);
2903 surface_depth_blt(surface, context, texture->texture_rgb.name,
2904 0, surface->pow2Height - h, w, h, surface->texture_target);
2905 checkGLcall("depth_blt");
2907 context_invalidate_state(context, STATE_FRAMEBUFFER);
2909 if (wined3d_settings.strict_draw_ordering)
2910 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2912 else
2914 ERR("Invalid location (%#x) specified.\n", location);
2918 static DWORD resource_access_from_location(DWORD location)
2920 switch (location)
2922 case WINED3D_LOCATION_SYSMEM:
2923 case WINED3D_LOCATION_USER_MEMORY:
2924 case WINED3D_LOCATION_DIB:
2925 case WINED3D_LOCATION_BUFFER:
2926 return WINED3D_RESOURCE_ACCESS_CPU;
2928 case WINED3D_LOCATION_DRAWABLE:
2929 case WINED3D_LOCATION_TEXTURE_SRGB:
2930 case WINED3D_LOCATION_TEXTURE_RGB:
2931 case WINED3D_LOCATION_RB_MULTISAMPLE:
2932 case WINED3D_LOCATION_RB_RESOLVED:
2933 return WINED3D_RESOURCE_ACCESS_GPU;
2935 default:
2936 FIXME("Unhandled location %#x.\n", location);
2937 return 0;
2941 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
2943 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2944 struct wined3d_texture *texture = surface->container;
2945 struct wined3d_device *device = texture->resource.device;
2946 struct wined3d_context *context;
2947 const struct wined3d_gl_info *gl_info;
2948 struct wined3d_bo_address dst, src;
2949 UINT size = surface->resource.size;
2951 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
2952 wined3d_texture_get_memory(texture, sub_resource_idx, &src,
2953 texture->sub_resources[sub_resource_idx].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, height, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
3048 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
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;
3058 RECT src_rect;
3060 sub_resource = surface_get_sub_resource(surface);
3061 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
3062 && wined3d_resource_is_offscreen(&texture->resource)
3063 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
3065 surface_load_fb_texture(surface, srgb, context);
3067 return WINED3D_OK;
3070 width = wined3d_texture_get_level_width(texture, surface->texture_level);
3071 height = wined3d_texture_get_level_height(texture, surface->texture_level);
3072 SetRect(&src_rect, 0, 0, width, height);
3074 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
3075 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
3076 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3077 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3078 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3080 if (srgb)
3081 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
3082 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
3083 else
3084 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
3085 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
3087 return WINED3D_OK;
3090 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
3091 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
3092 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3093 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3094 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3096 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
3097 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
3098 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
3100 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
3101 &src_rect, surface, dst_location, &src_rect);
3103 return WINED3D_OK;
3106 /* Upload from system memory */
3108 if (srgb)
3110 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
3111 == WINED3D_LOCATION_TEXTURE_RGB)
3113 /* Performance warning... */
3114 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
3115 surface_load_location(surface, context, surface->resource.map_binding);
3118 else
3120 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
3121 == WINED3D_LOCATION_TEXTURE_SRGB)
3123 /* Performance warning... */
3124 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
3125 surface_load_location(surface, context, surface->resource.map_binding);
3129 if (!(sub_resource->locations & surface_simple_locations))
3131 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
3132 /* Lets hope we get it from somewhere... */
3133 surface_load_location(surface, context, WINED3D_LOCATION_SYSMEM);
3136 wined3d_texture_prepare_texture(texture, context, srgb);
3137 wined3d_texture_bind_and_dirtify(texture, context, srgb);
3138 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
3140 format = *texture->resource.format;
3141 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
3142 format = *wined3d_get_format(gl_info, conversion->dst_format);
3144 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
3145 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
3146 * getting called. */
3147 if ((format.convert || conversion) && texture->sub_resources[sub_resource_idx].buffer_object)
3149 TRACE("Removing the pbo attached to surface %p.\n", surface);
3151 if (surface->flags & SFLAG_DIBSECTION)
3152 surface->resource.map_binding = WINED3D_LOCATION_DIB;
3153 else
3154 surface->resource.map_binding = WINED3D_LOCATION_SYSMEM;
3156 surface_load_location(surface, context, surface->resource.map_binding);
3157 wined3d_texture_remove_buffer_object(texture, sub_resource_idx, gl_info);
3160 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
3161 if (format.convert)
3163 /* This code is entered for texture formats which need a fixup. */
3164 format.byte_count = format.conv_byte_count;
3165 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
3167 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3169 ERR("Out of memory (%u).\n", dst_slice_pitch);
3170 context_release(context);
3171 return E_OUTOFMEMORY;
3173 format.convert(data.addr, mem, src_row_pitch, src_slice_pitch,
3174 dst_row_pitch, dst_slice_pitch, width, height, 1);
3175 src_row_pitch = dst_row_pitch;
3176 data.addr = mem;
3178 else if (conversion)
3180 /* This code is only entered for color keying fixups */
3181 struct wined3d_palette *palette = NULL;
3183 wined3d_format_calculate_pitch(&format, device->surface_alignment,
3184 width, height, &dst_row_pitch, &dst_slice_pitch);
3186 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3188 ERR("Out of memory (%u).\n", dst_slice_pitch);
3189 context_release(context);
3190 return E_OUTOFMEMORY;
3192 if (texture->swapchain && texture->swapchain->palette)
3193 palette = texture->swapchain->palette;
3194 conversion->convert(data.addr, src_row_pitch, mem, dst_row_pitch,
3195 width, height, palette, &texture->async.gl_color_key);
3196 src_row_pitch = dst_row_pitch;
3197 data.addr = mem;
3200 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
3201 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
3203 HeapFree(GetProcessHeap(), 0, mem);
3205 return WINED3D_OK;
3208 /* Context activation is done by the caller. */
3209 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
3210 DWORD dst_location)
3212 const RECT rect = {0, 0, surface->resource.width, surface->resource.height};
3213 DWORD locations = surface_get_sub_resource(surface)->locations;
3214 DWORD src_location;
3216 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
3217 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
3218 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
3219 src_location = WINED3D_LOCATION_RB_RESOLVED;
3220 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
3221 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
3222 else /* surface_blt_fbo will load the source location if necessary. */
3223 src_location = WINED3D_LOCATION_TEXTURE_RGB;
3225 surface_blt_fbo(surface->container->resource.device, context, WINED3D_TEXF_POINT,
3226 surface, src_location, &rect, surface, dst_location, &rect);
3229 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
3230 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
3232 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3233 struct wined3d_texture *texture = surface->container;
3234 struct wined3d_texture_sub_resource *sub_resource;
3235 HRESULT hr;
3237 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
3239 sub_resource = &texture->sub_resources[sub_resource_idx];
3240 if (sub_resource->locations & location && (!(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3241 || (surface->ds_current_size.cx == surface->resource.width
3242 && surface->ds_current_size.cy == surface->resource.height)))
3244 TRACE("Location (%#x) is already up to date.\n", location);
3245 return WINED3D_OK;
3248 if (WARN_ON(d3d))
3250 DWORD required_access = resource_access_from_location(location);
3251 if ((texture->resource.access_flags & required_access) != required_access)
3252 WARN("Operation requires %#x access, but surface only has %#x.\n",
3253 required_access, texture->resource.access_flags);
3256 if (sub_resource->locations & WINED3D_LOCATION_DISCARDED)
3258 TRACE("Surface previously discarded, nothing to do.\n");
3259 wined3d_surface_prepare(surface, context, location);
3260 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3261 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3262 goto done;
3265 if (!sub_resource->locations)
3267 ERR("Surface %p does not have any up to date location.\n", surface);
3268 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3269 return surface_load_location(surface, context, location);
3272 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3274 if ((location == WINED3D_LOCATION_TEXTURE_RGB && sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3275 || (location == WINED3D_LOCATION_DRAWABLE && sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB))
3277 surface_load_ds_location(surface, context, location);
3278 goto done;
3281 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
3282 wined3d_debug_location(sub_resource->locations), wined3d_debug_location(location));
3283 return WINED3DERR_INVALIDCALL;
3286 switch (location)
3288 case WINED3D_LOCATION_DIB:
3289 case WINED3D_LOCATION_USER_MEMORY:
3290 case WINED3D_LOCATION_SYSMEM:
3291 case WINED3D_LOCATION_BUFFER:
3292 surface_load_sysmem(surface, context, location);
3293 break;
3295 case WINED3D_LOCATION_DRAWABLE:
3296 if (FAILED(hr = surface_load_drawable(surface, context)))
3297 return hr;
3298 break;
3300 case WINED3D_LOCATION_RB_RESOLVED:
3301 case WINED3D_LOCATION_RB_MULTISAMPLE:
3302 surface_load_renderbuffer(surface, context, location);
3303 break;
3305 case WINED3D_LOCATION_TEXTURE_RGB:
3306 case WINED3D_LOCATION_TEXTURE_SRGB:
3307 if (FAILED(hr = surface_load_texture(surface, context,
3308 location == WINED3D_LOCATION_TEXTURE_SRGB)))
3309 return hr;
3310 break;
3312 default:
3313 ERR("Don't know how to handle location %#x.\n", location);
3314 break;
3317 done:
3318 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3320 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3322 surface->ds_current_size.cx = surface->resource.width;
3323 surface->ds_current_size.cy = surface->resource.height;
3326 if (location != WINED3D_LOCATION_SYSMEM && (sub_resource->locations & WINED3D_LOCATION_SYSMEM))
3327 surface_evict_sysmem(surface);
3329 return WINED3D_OK;
3332 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
3333 /* Context activation is done by the caller. */
3334 static void ffp_blit_free(struct wined3d_device *device) { }
3336 /* Context activation is done by the caller. */
3337 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3338 const struct wined3d_color_key *color_key)
3340 const struct wined3d_gl_info *gl_info = context->gl_info;
3342 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
3343 checkGLcall("glEnable(target)");
3345 return WINED3D_OK;
3348 /* Context activation is done by the caller. */
3349 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
3351 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
3352 checkGLcall("glDisable(GL_TEXTURE_2D)");
3353 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
3355 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
3356 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3358 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
3360 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
3361 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
3365 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
3366 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3367 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3368 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3370 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
3372 TRACE("Source or destination is in system memory.\n");
3373 return FALSE;
3376 switch (blit_op)
3378 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3379 if (d3d_info->shader_color_key)
3381 TRACE("Color keying requires converted textures.\n");
3382 return FALSE;
3384 case WINED3D_BLIT_OP_COLOR_BLIT:
3385 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3386 if (TRACE_ON(d3d))
3388 TRACE("Checking support for fixup:\n");
3389 dump_color_fixup_desc(src_format->color_fixup);
3392 /* We only support identity conversions. */
3393 if (!is_identity_fixup(src_format->color_fixup)
3394 || !is_identity_fixup(dst_format->color_fixup))
3396 TRACE("Fixups are not supported.\n");
3397 return FALSE;
3400 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3402 TRACE("Can only blit to render targets.\n");
3403 return FALSE;
3405 return TRUE;
3407 case WINED3D_BLIT_OP_COLOR_FILL:
3408 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3410 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
3411 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
3412 return FALSE;
3414 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3416 TRACE("Color fill not supported\n");
3417 return FALSE;
3420 /* FIXME: We should reject color fills on formats with fixups,
3421 * but this would break P8 color fills for example. */
3423 return TRUE;
3425 case WINED3D_BLIT_OP_DEPTH_FILL:
3426 return TRUE;
3428 default:
3429 TRACE("Unsupported blit_op=%d\n", blit_op);
3430 return FALSE;
3434 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
3435 const RECT *rect, const struct wined3d_color *color)
3437 const RECT draw_rect = {0, 0, view->width, view->height};
3438 struct wined3d_fb_state fb = {&view, NULL};
3440 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
3442 return WINED3D_OK;
3445 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
3446 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3447 float depth, DWORD stencil)
3449 const RECT draw_rect = {0, 0, view->width, view->height};
3450 struct wined3d_fb_state fb = {NULL, view};
3452 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, clear_flags, NULL, depth, stencil);
3454 return WINED3D_OK;
3457 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3458 struct wined3d_surface *src_surface, const RECT *src_rect,
3459 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3460 const struct wined3d_color_key *color_key)
3462 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3463 struct wined3d_texture *dst_texture = dst_surface->container;
3464 struct wined3d_texture *src_texture = src_surface->container;
3465 struct wined3d_context *context;
3467 /* Blit from offscreen surface to render target */
3468 struct wined3d_color_key old_blt_key = src_texture->async.src_blt_color_key;
3469 DWORD old_color_key_flags = src_texture->async.color_key_flags;
3471 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3473 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
3475 context = context_acquire(device, dst_surface);
3477 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3478 glEnable(GL_ALPHA_TEST);
3480 surface_blt_to_drawable(device, context, filter,
3481 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
3483 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3484 glDisable(GL_ALPHA_TEST);
3486 context_release(context);
3488 /* Restore the color key parameters */
3489 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
3490 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
3492 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_texture->resource.draw_binding);
3493 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_texture->resource.draw_binding);
3496 const struct blit_shader ffp_blit = {
3497 ffp_blit_alloc,
3498 ffp_blit_free,
3499 ffp_blit_set,
3500 ffp_blit_unset,
3501 ffp_blit_supported,
3502 ffp_blit_color_fill,
3503 ffp_blit_depth_fill,
3504 ffp_blit_blit_surface,
3507 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
3509 return WINED3D_OK;
3512 /* Context activation is done by the caller. */
3513 static void cpu_blit_free(struct wined3d_device *device)
3517 /* Context activation is done by the caller. */
3518 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3519 const struct wined3d_color_key *color_key)
3521 return WINED3D_OK;
3524 /* Context activation is done by the caller. */
3525 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
3529 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
3530 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3531 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3532 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3534 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
3536 return TRUE;
3539 return FALSE;
3542 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
3543 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
3544 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
3546 UINT row_block_count;
3547 const BYTE *src_row;
3548 BYTE *dst_row;
3549 UINT x, y;
3551 src_row = src_data;
3552 dst_row = dst_data;
3554 row_block_count = (update_w + format->block_width - 1) / format->block_width;
3556 if (!flags)
3558 for (y = 0; y < update_h; y += format->block_height)
3560 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
3561 src_row += src_pitch;
3562 dst_row += dst_pitch;
3565 return WINED3D_OK;
3568 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
3570 src_row += (((update_h / format->block_height) - 1) * src_pitch);
3572 switch (format->id)
3574 case WINED3DFMT_DXT1:
3575 for (y = 0; y < update_h; y += format->block_height)
3577 struct block
3579 WORD color[2];
3580 BYTE control_row[4];
3583 const struct block *s = (const struct block *)src_row;
3584 struct block *d = (struct block *)dst_row;
3586 for (x = 0; x < row_block_count; ++x)
3588 d[x].color[0] = s[x].color[0];
3589 d[x].color[1] = s[x].color[1];
3590 d[x].control_row[0] = s[x].control_row[3];
3591 d[x].control_row[1] = s[x].control_row[2];
3592 d[x].control_row[2] = s[x].control_row[1];
3593 d[x].control_row[3] = s[x].control_row[0];
3595 src_row -= src_pitch;
3596 dst_row += dst_pitch;
3598 return WINED3D_OK;
3600 case WINED3DFMT_DXT2:
3601 case WINED3DFMT_DXT3:
3602 for (y = 0; y < update_h; y += format->block_height)
3604 struct block
3606 WORD alpha_row[4];
3607 WORD color[2];
3608 BYTE control_row[4];
3611 const struct block *s = (const struct block *)src_row;
3612 struct block *d = (struct block *)dst_row;
3614 for (x = 0; x < row_block_count; ++x)
3616 d[x].alpha_row[0] = s[x].alpha_row[3];
3617 d[x].alpha_row[1] = s[x].alpha_row[2];
3618 d[x].alpha_row[2] = s[x].alpha_row[1];
3619 d[x].alpha_row[3] = s[x].alpha_row[0];
3620 d[x].color[0] = s[x].color[0];
3621 d[x].color[1] = s[x].color[1];
3622 d[x].control_row[0] = s[x].control_row[3];
3623 d[x].control_row[1] = s[x].control_row[2];
3624 d[x].control_row[2] = s[x].control_row[1];
3625 d[x].control_row[3] = s[x].control_row[0];
3627 src_row -= src_pitch;
3628 dst_row += dst_pitch;
3630 return WINED3D_OK;
3632 default:
3633 FIXME("Compressed flip not implemented for format %s.\n",
3634 debug_d3dformat(format->id));
3635 return E_NOTIMPL;
3639 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3640 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
3642 return E_NOTIMPL;
3645 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3646 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3647 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3648 enum wined3d_texture_filter_type filter)
3650 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
3651 const struct wined3d_format *src_format, *dst_format;
3652 struct wined3d_texture *converted_texture = NULL;
3653 unsigned int src_fmt_flags, dst_fmt_flags;
3654 struct wined3d_map_desc dst_map, src_map;
3655 const BYTE *sbase = NULL;
3656 HRESULT hr = WINED3D_OK;
3657 BOOL same_sub_resource;
3658 const BYTE *sbuf;
3659 BYTE *dbuf;
3660 int x, y;
3662 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3663 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3664 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
3665 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3667 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
3669 same_sub_resource = TRUE;
3670 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, NULL, 0);
3671 src_map = dst_map;
3672 src_format = dst_texture->resource.format;
3673 dst_format = src_format;
3674 dst_fmt_flags = dst_texture->resource.format_flags;
3675 src_fmt_flags = dst_fmt_flags;
3677 else
3679 same_sub_resource = FALSE;
3680 dst_format = dst_texture->resource.format;
3681 dst_fmt_flags = dst_texture->resource.format_flags;
3682 if (src_texture)
3684 if (dst_texture->resource.format->id != src_texture->resource.format->id)
3686 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
3688 /* The conv function writes a FIXME */
3689 WARN("Cannot convert source surface format to dest format.\n");
3690 goto release;
3692 src_texture = converted_texture;
3693 src_sub_resource_idx = 0;
3695 wined3d_resource_map(&src_texture->resource, src_sub_resource_idx, &src_map, NULL, WINED3D_MAP_READONLY);
3696 src_format = src_texture->resource.format;
3697 src_fmt_flags = src_texture->resource.format_flags;
3699 else
3701 src_format = dst_format;
3702 src_fmt_flags = dst_fmt_flags;
3705 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, dst_box, 0);
3708 bpp = dst_format->byte_count;
3709 src_height = src_box->bottom - src_box->top;
3710 src_width = src_box->right - src_box->left;
3711 dst_height = dst_box->bottom - dst_box->top;
3712 dst_width = dst_box->right - dst_box->left;
3713 row_byte_count = dst_width * bpp;
3715 if (src_texture)
3716 sbase = (BYTE *)src_map.data
3717 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
3718 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
3719 if (same_sub_resource)
3720 dbuf = (BYTE *)dst_map.data
3721 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
3722 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
3723 else
3724 dbuf = dst_map.data;
3726 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
3728 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
3730 if (same_sub_resource)
3732 FIXME("Only plain blits supported on compressed surfaces.\n");
3733 hr = E_NOTIMPL;
3734 goto release;
3737 if (src_height != dst_height || src_width != dst_width)
3739 WARN("Stretching not supported on compressed surfaces.\n");
3740 hr = WINED3DERR_INVALIDCALL;
3741 goto release;
3744 if (!wined3d_texture_check_block_align(src_texture,
3745 src_sub_resource_idx % src_texture->level_count, src_box))
3747 WARN("Source rectangle not block-aligned.\n");
3748 hr = WINED3DERR_INVALIDCALL;
3749 goto release;
3752 if (!wined3d_texture_check_block_align(dst_texture,
3753 dst_sub_resource_idx % dst_texture->level_count, dst_box))
3755 WARN("Destination rectangle not block-aligned.\n");
3756 hr = WINED3DERR_INVALIDCALL;
3757 goto release;
3760 hr = surface_cpu_blt_compressed(sbase, dbuf,
3761 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
3762 src_format, flags, fx);
3763 goto release;
3766 /* First, all the 'source-less' blits */
3767 if (flags & WINED3D_BLT_COLOR_FILL)
3769 hr = _Blt_ColorFill(dbuf, dst_width, dst_height, bpp, dst_map.row_pitch, fx->fill_color);
3770 flags &= ~WINED3D_BLT_COLOR_FILL;
3773 if (flags & WINED3D_BLT_DEPTH_FILL)
3774 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3776 /* Now the 'with source' blits. */
3777 if (src_texture)
3779 int sx, xinc, sy, yinc;
3781 if (!dst_width || !dst_height) /* Hmm... stupid program? */
3782 goto release;
3784 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3785 && (src_width != dst_width || src_height != dst_height))
3787 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3788 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
3791 xinc = (src_width << 16) / dst_width;
3792 yinc = (src_height << 16) / dst_height;
3794 if (!flags)
3796 /* No effects, we can cheat here. */
3797 if (dst_width == src_width)
3799 if (dst_height == src_height)
3801 /* No stretching in either direction. This needs to be as
3802 * fast as possible. */
3803 sbuf = sbase;
3805 /* Check for overlapping surfaces. */
3806 if (!same_sub_resource || dst_box->top < src_box->top
3807 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
3809 /* No overlap, or dst above src, so copy from top downwards. */
3810 for (y = 0; y < dst_height; ++y)
3812 memcpy(dbuf, sbuf, row_byte_count);
3813 sbuf += src_map.row_pitch;
3814 dbuf += dst_map.row_pitch;
3817 else if (dst_box->top > src_box->top)
3819 /* Copy from bottom upwards. */
3820 sbuf += src_map.row_pitch * dst_height;
3821 dbuf += dst_map.row_pitch * dst_height;
3822 for (y = 0; y < dst_height; ++y)
3824 sbuf -= src_map.row_pitch;
3825 dbuf -= dst_map.row_pitch;
3826 memcpy(dbuf, sbuf, row_byte_count);
3829 else
3831 /* Src and dst overlapping on the same line, use memmove. */
3832 for (y = 0; y < dst_height; ++y)
3834 memmove(dbuf, sbuf, row_byte_count);
3835 sbuf += src_map.row_pitch;
3836 dbuf += dst_map.row_pitch;
3840 else
3842 /* Stretching in y direction only. */
3843 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3845 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3846 memcpy(dbuf, sbuf, row_byte_count);
3847 dbuf += dst_map.row_pitch;
3851 else
3853 /* Stretching in X direction. */
3854 int last_sy = -1;
3855 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3857 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3859 if ((sy >> 16) == (last_sy >> 16))
3861 /* This source row is the same as last source row -
3862 * Copy the already stretched row. */
3863 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
3865 else
3867 #define STRETCH_ROW(type) \
3868 do { \
3869 const type *s = (const type *)sbuf; \
3870 type *d = (type *)dbuf; \
3871 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3872 d[x] = s[sx >> 16]; \
3873 } while(0)
3875 switch(bpp)
3877 case 1:
3878 STRETCH_ROW(BYTE);
3879 break;
3880 case 2:
3881 STRETCH_ROW(WORD);
3882 break;
3883 case 4:
3884 STRETCH_ROW(DWORD);
3885 break;
3886 case 3:
3888 const BYTE *s;
3889 BYTE *d = dbuf;
3890 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3892 DWORD pixel;
3894 s = sbuf + 3 * (sx >> 16);
3895 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3896 d[0] = (pixel ) & 0xff;
3897 d[1] = (pixel >> 8) & 0xff;
3898 d[2] = (pixel >> 16) & 0xff;
3899 d += 3;
3901 break;
3903 default:
3904 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
3905 hr = WINED3DERR_NOTAVAILABLE;
3906 goto error;
3908 #undef STRETCH_ROW
3910 dbuf += dst_map.row_pitch;
3911 last_sy = sy;
3915 else
3917 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3918 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3919 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3920 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3921 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3923 /* The color keying flags are checked for correctness in ddraw */
3924 if (flags & WINED3D_BLT_SRC_CKEY)
3926 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
3927 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3929 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3931 keylow = fx->src_color_key.color_space_low_value;
3932 keyhigh = fx->src_color_key.color_space_high_value;
3935 if (flags & WINED3D_BLT_DST_CKEY)
3937 /* Destination color keys are taken from the source surface! */
3938 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3939 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3941 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3943 destkeylow = fx->dst_color_key.color_space_low_value;
3944 destkeyhigh = fx->dst_color_key.color_space_high_value;
3947 if (bpp == 1)
3949 keymask = 0xff;
3951 else
3953 DWORD masks[3];
3954 get_color_masks(src_format, masks);
3955 keymask = masks[0]
3956 | masks[1]
3957 | masks[2];
3959 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3960 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3963 if (flags & WINED3D_BLT_FX)
3965 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3966 LONG tmpxy;
3967 dTopLeft = dbuf;
3968 dTopRight = dbuf + ((dst_width - 1) * bpp);
3969 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3970 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3972 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3974 /* I don't think we need to do anything about this flag */
3975 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3977 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3979 tmp = dTopRight;
3980 dTopRight = dTopLeft;
3981 dTopLeft = tmp;
3982 tmp = dBottomRight;
3983 dBottomRight = dBottomLeft;
3984 dBottomLeft = tmp;
3985 dstxinc = dstxinc * -1;
3987 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
3989 tmp = dTopLeft;
3990 dTopLeft = dBottomLeft;
3991 dBottomLeft = tmp;
3992 tmp = dTopRight;
3993 dTopRight = dBottomRight;
3994 dBottomRight = tmp;
3995 dstyinc = dstyinc * -1;
3997 if (fx->fx & WINEDDBLTFX_NOTEARING)
3999 /* I don't think we need to do anything about this flag */
4000 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
4002 if (fx->fx & WINEDDBLTFX_ROTATE180)
4004 tmp = dBottomRight;
4005 dBottomRight = dTopLeft;
4006 dTopLeft = tmp;
4007 tmp = dBottomLeft;
4008 dBottomLeft = dTopRight;
4009 dTopRight = tmp;
4010 dstxinc = dstxinc * -1;
4011 dstyinc = dstyinc * -1;
4013 if (fx->fx & WINEDDBLTFX_ROTATE270)
4015 tmp = dTopLeft;
4016 dTopLeft = dBottomLeft;
4017 dBottomLeft = dBottomRight;
4018 dBottomRight = dTopRight;
4019 dTopRight = tmp;
4020 tmpxy = dstxinc;
4021 dstxinc = dstyinc;
4022 dstyinc = tmpxy;
4023 dstxinc = dstxinc * -1;
4025 if (fx->fx & WINEDDBLTFX_ROTATE90)
4027 tmp = dTopLeft;
4028 dTopLeft = dTopRight;
4029 dTopRight = dBottomRight;
4030 dBottomRight = dBottomLeft;
4031 dBottomLeft = tmp;
4032 tmpxy = dstxinc;
4033 dstxinc = dstyinc;
4034 dstyinc = tmpxy;
4035 dstyinc = dstyinc * -1;
4037 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
4039 /* I don't think we need to do anything about this flag */
4040 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
4042 dbuf = dTopLeft;
4043 flags &= ~(WINED3D_BLT_FX);
4046 #define COPY_COLORKEY_FX(type) \
4047 do { \
4048 const type *s; \
4049 type *d = (type *)dbuf, *dx, tmp; \
4050 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
4052 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
4053 dx = d; \
4054 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
4056 tmp = s[sx >> 16]; \
4057 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
4058 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
4060 dx[0] = tmp; \
4062 dx = (type *)(((BYTE *)dx) + dstxinc); \
4064 d = (type *)(((BYTE *)d) + dstyinc); \
4066 } while(0)
4068 switch (bpp)
4070 case 1:
4071 COPY_COLORKEY_FX(BYTE);
4072 break;
4073 case 2:
4074 COPY_COLORKEY_FX(WORD);
4075 break;
4076 case 4:
4077 COPY_COLORKEY_FX(DWORD);
4078 break;
4079 case 3:
4081 const BYTE *s;
4082 BYTE *d = dbuf, *dx;
4083 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
4085 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
4086 dx = d;
4087 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
4089 DWORD pixel, dpixel = 0;
4090 s = sbuf + 3 * (sx>>16);
4091 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
4092 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
4093 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
4094 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
4096 dx[0] = (pixel ) & 0xff;
4097 dx[1] = (pixel >> 8) & 0xff;
4098 dx[2] = (pixel >> 16) & 0xff;
4100 dx += dstxinc;
4102 d += dstyinc;
4104 break;
4106 default:
4107 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
4108 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
4109 hr = WINED3DERR_NOTAVAILABLE;
4110 goto error;
4111 #undef COPY_COLORKEY_FX
4116 error:
4117 if (flags)
4118 FIXME(" Unsupported flags %#x.\n", flags);
4120 release:
4121 wined3d_resource_unmap(&dst_texture->resource, dst_sub_resource_idx);
4122 if (src_texture && !same_sub_resource)
4123 wined3d_resource_unmap(&src_texture->resource, src_sub_resource_idx);
4124 if (converted_texture)
4125 wined3d_texture_decref(converted_texture);
4127 return hr;
4130 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
4131 const RECT *rect, const struct wined3d_color *color)
4133 const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
4134 static const struct wined3d_box src_box;
4135 struct wined3d_blt_fx fx;
4137 fx.fill_color = wined3d_format_convert_from_float(view->format, color);
4138 return surface_cpu_blt(wined3d_texture_from_resource(view->resource), view->sub_resource_idx,
4139 &box, NULL, 0, &src_box, WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
4142 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
4143 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
4144 float depth, DWORD stencil)
4146 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
4147 return WINED3DERR_INVALIDCALL;
4150 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
4151 struct wined3d_surface *src_surface, const RECT *src_rect,
4152 struct wined3d_surface *dst_surface, const RECT *dst_rect,
4153 const struct wined3d_color_key *color_key)
4155 /* FIXME: Remove error returns from surface_blt_cpu. */
4156 ERR("Blit method not implemented by cpu_blit.\n");
4159 const struct blit_shader cpu_blit = {
4160 cpu_blit_alloc,
4161 cpu_blit_free,
4162 cpu_blit_set,
4163 cpu_blit_unset,
4164 cpu_blit_supported,
4165 cpu_blit_color_fill,
4166 cpu_blit_depth_fill,
4167 cpu_blit_blit_surface,
4170 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
4171 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
4172 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
4174 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
4175 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
4176 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
4177 struct wined3d_texture *dst_texture = dst_surface->container;
4178 struct wined3d_device *device = dst_texture->resource.device;
4179 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
4180 struct wined3d_texture *src_texture = NULL;
4181 DWORD src_ds_flags, dst_ds_flags;
4182 BOOL scale, convert;
4184 static const DWORD simple_blit = WINED3D_BLT_ASYNC
4185 | WINED3D_BLT_COLOR_FILL
4186 | WINED3D_BLT_SRC_CKEY
4187 | WINED3D_BLT_SRC_CKEY_OVERRIDE
4188 | WINED3D_BLT_WAIT
4189 | WINED3D_BLT_DEPTH_FILL
4190 | WINED3D_BLT_DO_NOT_WAIT
4191 | WINED3D_BLT_ALPHA_TEST;
4193 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4194 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
4195 flags, fx, debug_d3dtexturefiltertype(filter));
4196 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
4198 if (fx)
4200 TRACE("fx %#x.\n", fx->fx);
4201 TRACE("fill_color 0x%08x.\n", fx->fill_color);
4202 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
4203 fx->dst_color_key.color_space_low_value,
4204 fx->dst_color_key.color_space_high_value);
4205 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
4206 fx->src_color_key.color_space_low_value,
4207 fx->src_color_key.color_space_high_value);
4210 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
4212 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
4213 return WINEDDERR_SURFACEBUSY;
4216 if (dst_rect->left >= dst_rect->right || dst_rect->top >= dst_rect->bottom
4217 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
4218 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
4219 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
4220 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0)
4222 WARN("The application gave us a bad destination rectangle.\n");
4223 return WINEDDERR_INVALIDRECT;
4226 if (src_surface)
4228 if (src_rect->left >= src_rect->right || src_rect->top >= src_rect->bottom
4229 || src_rect->left > src_surface->resource.width || src_rect->left < 0
4230 || src_rect->top > src_surface->resource.height || src_rect->top < 0
4231 || src_rect->right > src_surface->resource.width || src_rect->right < 0
4232 || src_rect->bottom > src_surface->resource.height || src_rect->bottom < 0)
4234 WARN("The application gave us a bad source rectangle.\n");
4235 return WINEDDERR_INVALIDRECT;
4237 src_texture = src_surface->container;
4240 if (!fx || !(fx->fx))
4241 flags &= ~WINED3D_BLT_FX;
4243 if (flags & WINED3D_BLT_WAIT)
4244 flags &= ~WINED3D_BLT_WAIT;
4246 if (flags & WINED3D_BLT_ASYNC)
4248 static unsigned int once;
4250 if (!once++)
4251 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
4252 flags &= ~WINED3D_BLT_ASYNC;
4255 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
4256 if (flags & WINED3D_BLT_DO_NOT_WAIT)
4258 static unsigned int once;
4260 if (!once++)
4261 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
4262 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
4265 if (!device->d3d_initialized)
4267 WARN("D3D not initialized, using fallback.\n");
4268 goto cpu;
4271 /* We want to avoid invalidating the sysmem location for converted
4272 * surfaces, since otherwise we'd have to convert the data back when
4273 * locking them. */
4274 if (dst_texture->flags & WINED3D_TEXTURE_CONVERTED || dst_texture->resource.format->convert
4275 || wined3d_format_get_color_key_conversion(dst_texture, TRUE))
4277 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
4278 goto cpu;
4281 if (flags & ~simple_blit)
4283 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
4284 goto fallback;
4287 if (src_surface)
4288 src_swapchain = src_texture->swapchain;
4289 else
4290 src_swapchain = NULL;
4292 dst_swapchain = dst_texture->swapchain;
4294 /* This isn't strictly needed. FBO blits for example could deal with
4295 * cross-swapchain blits by first downloading the source to a texture
4296 * before switching to the destination context. We just have this here to
4297 * not have to deal with the issue, since cross-swapchain blits should be
4298 * rare. */
4299 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
4301 FIXME("Using fallback for cross-swapchain blit.\n");
4302 goto fallback;
4305 scale = src_surface
4306 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
4307 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
4308 convert = src_surface && src_texture->resource.format->id != dst_texture->resource.format->id;
4310 dst_ds_flags = dst_texture->resource.format_flags
4311 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4312 if (src_surface)
4313 src_ds_flags = src_texture->resource.format_flags
4314 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4315 else
4316 src_ds_flags = 0;
4318 if (src_ds_flags || dst_ds_flags)
4320 if (flags & WINED3D_BLT_DEPTH_FILL)
4322 float depth;
4324 TRACE("Depth fill.\n");
4326 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
4327 return WINED3DERR_INVALIDCALL;
4329 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
4330 return WINED3D_OK;
4332 else
4334 if (src_ds_flags != dst_ds_flags)
4336 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
4337 return WINED3DERR_INVALIDCALL;
4340 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_texture->resource.draw_binding,
4341 src_rect, dst_surface, dst_texture->resource.draw_binding, dst_rect)))
4342 return WINED3D_OK;
4345 else
4347 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
4348 const struct blit_shader *blitter;
4350 dst_sub_resource = surface_get_sub_resource(dst_surface);
4351 src_sub_resource = src_surface ? surface_get_sub_resource(src_surface) : NULL;
4353 /* In principle this would apply to depth blits as well, but we don't
4354 * implement those in the CPU blitter at the moment. */
4355 if ((dst_sub_resource->locations & dst_surface->resource.map_binding)
4356 && (!src_surface || (src_sub_resource->locations & src_surface->resource.map_binding)))
4358 if (scale)
4359 TRACE("Not doing sysmem blit because of scaling.\n");
4360 else if (convert)
4361 TRACE("Not doing sysmem blit because of format conversion.\n");
4362 else
4363 goto cpu;
4366 if (flags & WINED3D_BLT_COLOR_FILL)
4368 struct wined3d_color color;
4369 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
4371 TRACE("Color fill.\n");
4373 if (!wined3d_format_convert_color_to_float(dst_texture->resource.format,
4374 palette, fx->fill_color, &color))
4375 goto fallback;
4377 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
4378 return WINED3D_OK;
4380 else
4382 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
4383 const struct wined3d_color_key *color_key = NULL;
4385 TRACE("Color blit.\n");
4386 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
4388 color_key = &fx->src_color_key;
4389 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4391 else if (flags & WINED3D_BLT_SRC_CKEY)
4393 color_key = &src_texture->async.src_blt_color_key;
4394 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4396 else if (flags & WINED3D_BLT_ALPHA_TEST)
4398 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
4400 else if ((src_sub_resource->locations & WINED3D_LOCATION_SYSMEM)
4401 && !(dst_sub_resource->locations & WINED3D_LOCATION_SYSMEM))
4403 /* Upload */
4404 if (scale)
4405 TRACE("Not doing upload because of scaling.\n");
4406 else if (convert)
4407 TRACE("Not doing upload because of format conversion.\n");
4408 else
4410 POINT dst_point = {dst_rect->left, dst_rect->top};
4412 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
4414 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
4416 struct wined3d_context *context = context_acquire(device, dst_surface);
4417 surface_load_location(dst_surface, context, dst_texture->resource.draw_binding);
4418 context_release(context);
4420 return WINED3D_OK;
4424 else if (dst_swapchain && dst_swapchain->back_buffers
4425 && dst_texture == dst_swapchain->front_buffer
4426 && src_texture == dst_swapchain->back_buffers[0])
4428 /* Use present for back -> front blits. The idea behind this is
4429 * that present is potentially faster than a blit, in particular
4430 * when FBO blits aren't available. Some ddraw applications like
4431 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4432 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4433 * applications can't blit directly to the frontbuffer. */
4434 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
4436 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4438 /* Set the swap effect to COPY, we don't want the backbuffer
4439 * to become undefined. */
4440 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
4441 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, 0);
4442 dst_swapchain->desc.swap_effect = swap_effect;
4444 return WINED3D_OK;
4447 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
4448 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4449 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
4451 struct wined3d_context *context;
4452 TRACE("Using FBO blit.\n");
4454 context = context_acquire(device, NULL);
4455 surface_blt_fbo(device, context, filter,
4456 src_surface, src_texture->resource.draw_binding, src_rect,
4457 dst_surface, dst_texture->resource.draw_binding, dst_rect);
4458 context_release(context);
4460 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx,
4461 dst_texture->resource.draw_binding);
4462 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx,
4463 ~dst_texture->resource.draw_binding);
4465 return WINED3D_OK;
4468 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
4469 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4470 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format);
4471 if (blitter)
4473 blitter->blit_surface(device, blit_op, filter, src_surface,
4474 src_rect, dst_surface, dst_rect, color_key);
4475 return WINED3D_OK;
4480 fallback:
4481 /* Special cases for render targets. */
4482 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
4483 return WINED3D_OK;
4485 cpu:
4486 return surface_cpu_blt(dst_texture, surface_get_sub_resource_idx(dst_surface), &dst_box,
4487 src_texture, src_texture ? surface_get_sub_resource_idx(src_surface) : 0, &src_box, flags, fx, filter);
4490 HRESULT wined3d_surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
4491 const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags)
4493 unsigned int sub_resource_idx = layer * container->level_count + level;
4494 struct wined3d_device *device = container->resource.device;
4495 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4496 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format);
4497 BOOL lockable = flags & WINED3D_TEXTURE_CREATE_MAPPABLE;
4498 UINT multisample_quality = desc->multisample_quality;
4499 unsigned int resource_size;
4500 HRESULT hr;
4502 if (container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
4504 unsigned int pow2_width = 1, pow2_height = 1;
4506 /* Find the nearest pow2 match. */
4507 while (pow2_width < desc->width)
4508 pow2_width <<= 1;
4509 while (pow2_height < desc->height)
4510 pow2_height <<= 1;
4512 surface->pow2Width = pow2_width;
4513 surface->pow2Height = pow2_height;
4515 else
4517 surface->pow2Width = desc->width;
4518 surface->pow2Height = desc->height;
4521 /* Quick lockable sanity check.
4522 * TODO: remove this after surfaces, usage and lockability have been debugged properly
4523 * this function is too deep to need to care about things like this.
4524 * Levels need to be checked too, since they all affect what can be done. */
4525 switch (desc->pool)
4527 case WINED3D_POOL_MANAGED:
4528 if (desc->usage & WINED3DUSAGE_DYNAMIC)
4529 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
4530 break;
4532 case WINED3D_POOL_DEFAULT:
4533 if (lockable && !(desc->usage & (WINED3DUSAGE_DYNAMIC
4534 | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4535 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
4536 break;
4538 case WINED3D_POOL_SCRATCH:
4539 case WINED3D_POOL_SYSTEM_MEM:
4540 break;
4542 default:
4543 FIXME("Unknown pool %#x.\n", desc->pool);
4544 break;
4547 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->pool != WINED3D_POOL_DEFAULT)
4548 FIXME("Trying to create a render target that isn't in the default pool.\n");
4550 /* FIXME: Check that the format is supported by the device. */
4552 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, 1);
4553 if (!resource_size)
4554 return WINED3DERR_INVALIDCALL;
4556 if (FAILED(hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE,
4557 format, desc->multisample_type, multisample_quality, desc->usage, desc->pool, desc->width, desc->height,
4558 1, resource_size, NULL, &wined3d_null_parent_ops, &surface_resource_ops)))
4560 WARN("Failed to initialize resource, returning %#x.\n", hr);
4561 return hr;
4564 surface->container = container;
4565 surface->texture_target = target;
4566 surface->texture_level = level;
4567 surface->texture_layer = layer;
4569 list_init(&surface->renderbuffers);
4570 list_init(&surface->overlays);
4572 /* Flags */
4573 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
4574 surface->flags |= SFLAG_DISCARD;
4575 if (lockable || desc->format == WINED3DFMT_D16_LOCKABLE)
4576 surface->resource.access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
4578 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4579 if (container->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4580 container->sub_resources[sub_resource_idx].locations = WINED3D_LOCATION_DISCARDED;
4582 if (wined3d_texture_use_pbo(container, gl_info))
4583 surface->resource.map_binding = WINED3D_LOCATION_BUFFER;
4585 /* Similar to lockable rendertargets above, creating the DIB section
4586 * during surface initialization prevents the sysmem pointer from changing
4587 * after a wined3d_texture_get_dc() call. */
4588 if ((desc->usage & WINED3DUSAGE_OWNDC) || (device->wined3d->flags & WINED3D_NO3D))
4590 if (FAILED(hr = surface_create_dib_section(surface)))
4592 wined3d_surface_cleanup(surface);
4593 return hr;
4595 surface->resource.map_binding = WINED3D_LOCATION_DIB;
4598 if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
4600 wined3d_resource_free_sysmem(&surface->resource);
4601 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_DIB);
4602 wined3d_texture_invalidate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4605 return hr;
4608 /* Context activation is done by the caller. Context may be NULL in
4609 * WINED3D_NO3D mode. */
4610 void wined3d_surface_prepare(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4612 struct wined3d_texture *texture = surface->container;
4614 switch (location)
4616 case WINED3D_LOCATION_SYSMEM:
4617 surface_prepare_system_memory(surface);
4618 break;
4620 case WINED3D_LOCATION_USER_MEMORY:
4621 if (!texture->user_memory)
4622 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
4623 break;
4625 case WINED3D_LOCATION_DIB:
4626 if (!surface->dib.bitmap_data)
4627 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
4628 break;
4630 case WINED3D_LOCATION_BUFFER:
4631 wined3d_texture_prepare_buffer_object(texture,
4632 surface_get_sub_resource_idx(surface), context->gl_info);
4633 break;
4635 case WINED3D_LOCATION_TEXTURE_RGB:
4636 wined3d_texture_prepare_texture(texture, context, FALSE);
4637 break;
4639 case WINED3D_LOCATION_TEXTURE_SRGB:
4640 wined3d_texture_prepare_texture(texture, context, TRUE);
4641 break;
4643 case WINED3D_LOCATION_RB_MULTISAMPLE:
4644 surface_prepare_rb(surface, context->gl_info, TRUE);
4645 break;
4647 case WINED3D_LOCATION_RB_RESOLVED:
4648 surface_prepare_rb(surface, context->gl_info, FALSE);
4649 break;