wined3d: Use the texture dimension helpers in read_from_framebuffer().
[wine.git] / dlls / wined3d / surface.c
blob681caa971a3484dcad8b538e8cfd66f1a83139eb
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 /* Context activation is done by the caller. */
1426 void surface_load(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
1428 DWORD location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
1430 TRACE("surface %p, srgb %#x.\n", surface, srgb);
1432 if (surface->container->resource.pool == WINED3D_POOL_SCRATCH)
1433 ERR("Not supported on scratch surfaces.\n");
1435 if (surface_get_sub_resource(surface)->locations & location)
1437 TRACE("surface is already in texture\n");
1438 return;
1440 TRACE("Reloading because surface is dirty.\n");
1442 surface_load_location(surface, context, location);
1443 surface_evict_sysmem(surface);
1446 /* See also float_16_to_32() in wined3d_private.h */
1447 static inline unsigned short float_32_to_16(const float *in)
1449 int exp = 0;
1450 float tmp = fabsf(*in);
1451 unsigned int mantissa;
1452 unsigned short ret;
1454 /* Deal with special numbers */
1455 if (*in == 0.0f)
1456 return 0x0000;
1457 if (isnan(*in))
1458 return 0x7c01;
1459 if (isinf(*in))
1460 return (*in < 0.0f ? 0xfc00 : 0x7c00);
1462 if (tmp < (float)(1u << 10))
1466 tmp = tmp * 2.0f;
1467 exp--;
1468 } while (tmp < (float)(1u << 10));
1470 else if (tmp >= (float)(1u << 11))
1474 tmp /= 2.0f;
1475 exp++;
1476 } while (tmp >= (float)(1u << 11));
1479 mantissa = (unsigned int)tmp;
1480 if (tmp - mantissa >= 0.5f)
1481 ++mantissa; /* Round to nearest, away from zero. */
1483 exp += 10; /* Normalize the mantissa. */
1484 exp += 15; /* Exponent is encoded with excess 15. */
1486 if (exp > 30) /* too big */
1488 ret = 0x7c00; /* INF */
1490 else if (exp <= 0)
1492 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1493 while (exp <= 0)
1495 mantissa = mantissa >> 1;
1496 ++exp;
1498 ret = mantissa & 0x3ff;
1500 else
1502 ret = (exp << 10) | (mantissa & 0x3ff);
1505 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
1506 return ret;
1509 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
1510 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1512 unsigned short *dst_s;
1513 const float *src_f;
1514 unsigned int x, y;
1516 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1518 for (y = 0; y < h; ++y)
1520 src_f = (const float *)(src + y * pitch_in);
1521 dst_s = (unsigned short *) (dst + y * pitch_out);
1522 for (x = 0; x < w; ++x)
1524 dst_s[x] = float_32_to_16(src_f + x);
1529 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
1530 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1532 static const unsigned char convert_5to8[] =
1534 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1535 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1536 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1537 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1539 static const unsigned char convert_6to8[] =
1541 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1542 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1543 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1544 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1545 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1546 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1547 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1548 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1550 unsigned int x, y;
1552 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1554 for (y = 0; y < h; ++y)
1556 const WORD *src_line = (const WORD *)(src + y * pitch_in);
1557 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1558 for (x = 0; x < w; ++x)
1560 WORD pixel = src_line[x];
1561 dst_line[x] = 0xff000000u
1562 | convert_5to8[(pixel & 0xf800u) >> 11] << 16
1563 | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
1564 | convert_5to8[(pixel & 0x001fu)];
1569 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1570 * in both cases we're just setting the X / Alpha channel to 0xff. */
1571 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
1572 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1574 unsigned int x, y;
1576 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1578 for (y = 0; y < h; ++y)
1580 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
1581 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1583 for (x = 0; x < w; ++x)
1585 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
1590 static inline BYTE cliptobyte(int x)
1592 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
1595 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
1596 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1598 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1599 unsigned int x, y;
1601 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1603 for (y = 0; y < h; ++y)
1605 const BYTE *src_line = src + y * pitch_in;
1606 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1607 for (x = 0; x < w; ++x)
1609 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1610 * C = Y - 16; D = U - 128; E = V - 128;
1611 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1612 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1613 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1614 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1615 * U and V are shared between the pixels. */
1616 if (!(x & 1)) /* For every even pixel, read new U and V. */
1618 d = (int) src_line[1] - 128;
1619 e = (int) src_line[3] - 128;
1620 r2 = 409 * e + 128;
1621 g2 = - 100 * d - 208 * e + 128;
1622 b2 = 516 * d + 128;
1624 c2 = 298 * ((int) src_line[0] - 16);
1625 dst_line[x] = 0xff000000
1626 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
1627 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
1628 | cliptobyte((c2 + b2) >> 8); /* blue */
1629 /* Scale RGB values to 0..255 range,
1630 * then clip them if still not in range (may be negative),
1631 * then shift them within DWORD if necessary. */
1632 src_line += 2;
1637 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
1638 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1640 unsigned int x, y;
1641 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1643 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
1645 for (y = 0; y < h; ++y)
1647 const BYTE *src_line = src + y * pitch_in;
1648 WORD *dst_line = (WORD *)(dst + y * pitch_out);
1649 for (x = 0; x < w; ++x)
1651 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1652 * C = Y - 16; D = U - 128; E = V - 128;
1653 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1654 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1655 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1656 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1657 * U and V are shared between the pixels. */
1658 if (!(x & 1)) /* For every even pixel, read new U and V. */
1660 d = (int) src_line[1] - 128;
1661 e = (int) src_line[3] - 128;
1662 r2 = 409 * e + 128;
1663 g2 = - 100 * d - 208 * e + 128;
1664 b2 = 516 * d + 128;
1666 c2 = 298 * ((int) src_line[0] - 16);
1667 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
1668 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
1669 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
1670 /* Scale RGB values to 0..255 range,
1671 * then clip them if still not in range (may be negative),
1672 * then shift them within DWORD if necessary. */
1673 src_line += 2;
1678 struct d3dfmt_converter_desc
1680 enum wined3d_format_id from, to;
1681 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
1684 static const struct d3dfmt_converter_desc converters[] =
1686 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
1687 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
1688 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1689 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1690 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
1691 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
1694 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
1695 enum wined3d_format_id to)
1697 unsigned int i;
1699 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
1701 if (converters[i].from == from && converters[i].to == to)
1702 return &converters[i];
1705 return NULL;
1708 static struct wined3d_texture *surface_convert_format(struct wined3d_texture *src_texture,
1709 unsigned int sub_resource_idx, const struct wined3d_format *dst_format)
1711 const struct wined3d_format *src_format = src_texture->resource.format;
1712 struct wined3d_device *device = src_texture->resource.device;
1713 const struct d3dfmt_converter_desc *conv = NULL;
1714 struct wined3d_texture *dst_texture;
1715 struct wined3d_resource_desc desc;
1716 struct wined3d_map_desc src_map;
1718 if (!(conv = find_converter(src_format->id, dst_format->id)) && (!device->d3d_initialized
1719 || !is_identity_fixup(src_format->color_fixup) || src_format->convert
1720 || !is_identity_fixup(dst_format->color_fixup) || dst_format->convert))
1722 FIXME("Cannot find a conversion function from format %s to %s.\n",
1723 debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
1724 return NULL;
1727 /* FIXME: Multisampled conversion? */
1728 wined3d_resource_get_desc(src_texture->sub_resources[sub_resource_idx].resource, &desc);
1729 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1730 desc.format = dst_format->id;
1731 desc.usage = 0;
1732 desc.pool = WINED3D_POOL_SCRATCH;
1733 if (FAILED(wined3d_texture_create(device, &desc, 1,
1734 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
1735 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
1737 ERR("Failed to create a destination texture for conversion.\n");
1738 return NULL;
1741 memset(&src_map, 0, sizeof(src_map));
1742 if (FAILED(wined3d_resource_map(&src_texture->resource, sub_resource_idx,
1743 &src_map, NULL, WINED3D_MAP_READONLY)))
1745 ERR("Failed to map the source texture.\n");
1746 wined3d_texture_decref(dst_texture);
1747 return NULL;
1749 if (conv)
1751 struct wined3d_map_desc dst_map;
1753 memset(&dst_map, 0, sizeof(dst_map));
1754 if (FAILED(wined3d_resource_map(&dst_texture->resource, 0, &dst_map, NULL, 0)))
1756 ERR("Failed to map the destination texture.\n");
1757 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1758 wined3d_texture_decref(dst_texture);
1759 return NULL;
1762 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch, desc.width, desc.height);
1764 wined3d_resource_unmap(&dst_texture->resource, 0);
1766 else
1768 struct wined3d_bo_address data = {0, src_map.data};
1769 RECT src_rect = {0, 0, desc.width, desc.height};
1770 const struct wined3d_gl_info *gl_info;
1771 struct wined3d_context *context;
1772 POINT dst_point = {0, 0};
1774 TRACE("Using upload conversion.\n");
1775 context = context_acquire(device, NULL);
1776 gl_info = context->gl_info;
1778 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1779 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1780 wined3d_surface_upload_data(dst_texture->sub_resources[0].u.surface, gl_info, src_format,
1781 &src_rect, src_map.row_pitch, &dst_point, FALSE, wined3d_const_bo_address(&data));
1783 context_release(context);
1785 wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
1786 wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
1788 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1790 return dst_texture;
1793 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
1794 unsigned int bpp, UINT pitch, DWORD color)
1796 BYTE *first;
1797 unsigned int x, y;
1799 /* Do first row */
1801 #define COLORFILL_ROW(type) \
1802 do { \
1803 type *d = (type *)buf; \
1804 for (x = 0; x < width; ++x) \
1805 d[x] = (type)color; \
1806 } while(0)
1808 switch (bpp)
1810 case 1:
1811 COLORFILL_ROW(BYTE);
1812 break;
1814 case 2:
1815 COLORFILL_ROW(WORD);
1816 break;
1818 case 3:
1820 BYTE *d = buf;
1821 for (x = 0; x < width; ++x, d += 3)
1823 d[0] = (color ) & 0xff;
1824 d[1] = (color >> 8) & 0xff;
1825 d[2] = (color >> 16) & 0xff;
1827 break;
1829 case 4:
1830 COLORFILL_ROW(DWORD);
1831 break;
1833 default:
1834 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
1835 return WINED3DERR_NOTAVAILABLE;
1838 #undef COLORFILL_ROW
1840 /* Now copy first row. */
1841 first = buf;
1842 for (y = 1; y < height; ++y)
1844 buf += pitch;
1845 memcpy(buf, first, width * bpp);
1848 return WINED3D_OK;
1851 static void read_from_framebuffer(struct wined3d_surface *surface,
1852 struct wined3d_context *old_ctx, DWORD dst_location)
1854 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
1855 struct wined3d_texture *texture = surface->container;
1856 struct wined3d_device *device = texture->resource.device;
1857 const struct wined3d_gl_info *gl_info;
1858 struct wined3d_context *context = old_ctx;
1859 struct wined3d_surface *restore_rt = NULL;
1860 unsigned int row_pitch, slice_pitch;
1861 unsigned int width, height;
1862 BYTE *mem;
1863 BYTE *row, *top, *bottom;
1864 int i;
1865 BOOL srcIsUpsideDown;
1866 struct wined3d_bo_address data;
1868 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1870 restore_rt = context_get_rt_surface(old_ctx);
1871 if (restore_rt != surface)
1872 context = context_acquire(device, surface);
1873 else
1874 restore_rt = NULL;
1876 context_apply_blit_state(context, device);
1877 gl_info = context->gl_info;
1879 /* Select the correct read buffer, and give some debug output.
1880 * There is no need to keep track of the current read buffer or reset it, every part of the code
1881 * that reads sets the read buffer as desired.
1883 if (wined3d_resource_is_offscreen(&texture->resource))
1885 /* Mapping the primary render target which is not on a swapchain.
1886 * Read from the back buffer. */
1887 TRACE("Mapping offscreen render target.\n");
1888 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1889 srcIsUpsideDown = TRUE;
1891 else
1893 /* Onscreen surfaces are always part of a swapchain */
1894 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
1895 TRACE("Mapping %#x buffer.\n", buffer);
1896 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1897 checkGLcall("glReadBuffer");
1898 srcIsUpsideDown = FALSE;
1901 if (data.buffer_object)
1903 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1904 checkGLcall("glBindBuffer");
1907 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
1909 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1910 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / texture->resource.format->byte_count);
1911 checkGLcall("glPixelStorei");
1913 width = wined3d_texture_get_level_width(texture, surface->texture_level);
1914 height = wined3d_texture_get_level_height(texture, surface->texture_level);
1915 gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
1916 texture->resource.format->glFormat,
1917 texture->resource.format->glType, data.addr);
1918 checkGLcall("glReadPixels");
1920 /* Reset previous pixel store pack state */
1921 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1922 checkGLcall("glPixelStorei");
1924 if (!srcIsUpsideDown)
1926 /* glReadPixels returns the image upside down, and there is no way to
1927 * prevent this. Flip the lines in software. */
1929 if (!(row = HeapAlloc(GetProcessHeap(), 0, row_pitch)))
1930 goto error;
1932 if (data.buffer_object)
1934 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
1935 checkGLcall("glMapBuffer");
1937 else
1938 mem = data.addr;
1940 top = mem;
1941 bottom = mem + row_pitch * (height - 1);
1942 for (i = 0; i < height / 2; i++)
1944 memcpy(row, top, row_pitch);
1945 memcpy(top, bottom, row_pitch);
1946 memcpy(bottom, row, row_pitch);
1947 top += row_pitch;
1948 bottom -= row_pitch;
1950 HeapFree(GetProcessHeap(), 0, row);
1952 if (data.buffer_object)
1953 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
1956 error:
1957 if (data.buffer_object)
1959 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1960 checkGLcall("glBindBuffer");
1963 if (restore_rt)
1964 context_restore(context, restore_rt);
1967 /* Read the framebuffer contents into a texture. Note that this function
1968 * doesn't do any kind of flipping. Using this on an onscreen surface will
1969 * result in a flipped D3D texture.
1971 * Context activation is done by the caller. This function may temporarily
1972 * switch to a different context and restore the original one before return. */
1973 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct wined3d_context *old_ctx)
1975 struct wined3d_texture *texture = surface->container;
1976 struct wined3d_device *device = texture->resource.device;
1977 const struct wined3d_gl_info *gl_info;
1978 struct wined3d_context *context = old_ctx;
1979 struct wined3d_surface *restore_rt = NULL;
1981 restore_rt = context_get_rt_surface(old_ctx);
1982 if (restore_rt != surface)
1983 context = context_acquire(device, surface);
1984 else
1985 restore_rt = NULL;
1987 gl_info = context->gl_info;
1988 device_invalidate_state(device, STATE_FRAMEBUFFER);
1990 wined3d_texture_prepare_texture(texture, context, srgb);
1991 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1993 TRACE("Reading back offscreen render target %p.\n", surface);
1995 if (wined3d_resource_is_offscreen(&texture->resource))
1996 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1997 else
1998 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
1999 checkGLcall("glReadBuffer");
2001 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
2002 0, 0, 0, 0, surface->resource.width, surface->resource.height);
2003 checkGLcall("glCopyTexSubImage2D");
2005 if (restore_rt)
2006 context_restore(context, restore_rt);
2009 static void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
2011 struct wined3d_texture *texture = surface->container;
2012 const struct wined3d_format *format = texture->resource.format;
2014 if (multisample)
2016 DWORD samples;
2018 if (surface->rb_multisample)
2019 return;
2021 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
2022 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
2023 * to GL_NV_framebuffer_multisample_coverage.
2025 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
2026 * but it does not have an equivalent OpenGL extension. */
2028 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
2029 * as the count of advertised multisample types for the surface format. */
2030 if (texture->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE)
2032 unsigned int i, count = 0;
2034 for (i = 0; i < sizeof(format->multisample_types) * 8; ++i)
2036 if (format->multisample_types & 1u << i)
2038 if (texture->resource.multisample_quality == count++)
2039 break;
2042 samples = i + 1;
2044 else
2046 samples = texture->resource.multisample_type;
2049 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
2050 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
2051 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
2052 format->glInternal, surface->pow2Width, surface->pow2Height);
2053 checkGLcall("glRenderbufferStorageMultisample()");
2054 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
2056 else
2058 if (surface->rb_resolved)
2059 return;
2061 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
2062 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
2063 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format->glInternal,
2064 surface->pow2Width, surface->pow2Height);
2065 checkGLcall("glRenderbufferStorage()");
2066 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
2070 /* Does a direct frame buffer -> texture copy. Stretching is done with single
2071 * pixel copy calls. */
2072 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2073 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2075 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2076 struct wined3d_texture *src_texture = src_surface->container;
2077 struct wined3d_texture *dst_texture = dst_surface->container;
2078 struct wined3d_device *device = dst_texture->resource.device;
2079 const struct wined3d_gl_info *gl_info;
2080 float xrel, yrel;
2081 struct wined3d_context *context;
2082 BOOL upsidedown = FALSE;
2083 RECT dst_rect = *dst_rect_in;
2085 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2086 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2088 if(dst_rect.top > dst_rect.bottom) {
2089 UINT tmp = dst_rect.bottom;
2090 dst_rect.bottom = dst_rect.top;
2091 dst_rect.top = tmp;
2092 upsidedown = TRUE;
2095 context = context_acquire(device, src_surface);
2096 gl_info = context->gl_info;
2097 context_apply_blit_state(context, device);
2098 wined3d_texture_load(dst_texture, context, FALSE);
2100 /* Bind the target texture */
2101 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
2102 if (wined3d_resource_is_offscreen(&src_texture->resource))
2104 TRACE("Reading from an offscreen target\n");
2105 upsidedown = !upsidedown;
2106 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
2108 else
2110 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2112 checkGLcall("glReadBuffer");
2114 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
2115 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
2117 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2119 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2121 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2122 ERR("Texture filtering not supported in direct blit.\n");
2124 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2125 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2127 ERR("Texture filtering not supported in direct blit\n");
2130 if (upsidedown
2131 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2132 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2134 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
2135 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2136 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
2137 src_rect->left, src_surface->resource.height - src_rect->bottom,
2138 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2140 else
2142 LONG row;
2143 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
2144 /* I have to process this row by row to swap the image,
2145 * otherwise it would be upside down, so stretching in y direction
2146 * doesn't cost extra time
2148 * However, stretching in x direction can be avoided if not necessary
2150 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
2151 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2153 /* Well, that stuff works, but it's very slow.
2154 * find a better way instead
2156 LONG col;
2158 for (col = dst_rect.left; col < dst_rect.right; ++col)
2160 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2161 dst_rect.left + col /* x offset */, row /* y offset */,
2162 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
2165 else
2167 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2168 dst_rect.left /* x offset */, row /* y offset */,
2169 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
2173 checkGLcall("glCopyTexSubImage2D");
2175 context_release(context);
2177 /* The texture is now most up to date - If the surface is a render target
2178 * and has a drawable, this path is never entered. */
2179 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2180 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2183 /* Uses the hardware to stretch and flip the image */
2184 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2185 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2187 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2188 struct wined3d_texture *src_texture = src_surface->container;
2189 struct wined3d_texture *dst_texture = dst_surface->container;
2190 struct wined3d_device *device = dst_texture->resource.device;
2191 GLuint src, backup = 0;
2192 float left, right, top, bottom; /* Texture coordinates */
2193 UINT fbwidth = src_surface->resource.width;
2194 UINT fbheight = src_surface->resource.height;
2195 const struct wined3d_gl_info *gl_info;
2196 struct wined3d_context *context;
2197 GLenum drawBuffer = GL_BACK;
2198 GLenum offscreen_buffer;
2199 GLenum texture_target;
2200 BOOL noBackBufferBackup;
2201 BOOL src_offscreen;
2202 BOOL upsidedown = FALSE;
2203 RECT dst_rect = *dst_rect_in;
2205 TRACE("Using hwstretch blit\n");
2206 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2207 context = context_acquire(device, src_surface);
2208 gl_info = context->gl_info;
2209 context_apply_blit_state(context, device);
2210 wined3d_texture_load(dst_texture, context, FALSE);
2212 offscreen_buffer = context_get_offscreen_gl_buffer(context);
2214 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
2215 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
2216 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
2218 /* Get it a description */
2219 wined3d_texture_load(src_texture, context, FALSE);
2222 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2223 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2225 if (context->aux_buffers >= 2)
2227 /* Got more than one aux buffer? Use the 2nd aux buffer */
2228 drawBuffer = GL_AUX1;
2230 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
2232 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2233 drawBuffer = GL_AUX0;
2236 if (noBackBufferBackup)
2238 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
2239 checkGLcall("glGenTextures");
2240 context_bind_texture(context, GL_TEXTURE_2D, backup);
2241 texture_target = GL_TEXTURE_2D;
2243 else
2245 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2246 * we are reading from the back buffer, the backup can be used as source texture
2248 texture_target = src_surface->texture_target;
2249 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
2250 gl_info->gl_ops.gl.p_glEnable(texture_target);
2251 checkGLcall("glEnable(texture_target)");
2253 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2254 surface_get_sub_resource(src_surface)->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
2257 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2258 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2260 if(dst_rect.top > dst_rect.bottom) {
2261 UINT tmp = dst_rect.bottom;
2262 dst_rect.bottom = dst_rect.top;
2263 dst_rect.top = tmp;
2264 upsidedown = TRUE;
2267 if (src_offscreen)
2269 TRACE("Reading from an offscreen target\n");
2270 upsidedown = !upsidedown;
2271 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
2273 else
2275 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2278 /* TODO: Only back up the part that will be overwritten */
2279 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
2281 checkGLcall("glCopyTexSubImage2D");
2283 /* No issue with overriding these - the sampler is dirty due to blit usage */
2284 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
2285 checkGLcall("glTexParameteri");
2286 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2287 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
2288 checkGLcall("glTexParameteri");
2290 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
2292 src = backup ? backup : src_texture->texture_rgb.name;
2294 else
2296 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
2297 checkGLcall("glReadBuffer(GL_FRONT)");
2299 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
2300 checkGLcall("glGenTextures(1, &src)");
2301 context_bind_texture(context, GL_TEXTURE_2D, src);
2303 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
2304 * out for power of 2 sizes
2306 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
2307 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2308 checkGLcall("glTexImage2D");
2309 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
2311 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2312 checkGLcall("glTexParameteri");
2313 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2314 checkGLcall("glTexParameteri");
2316 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
2317 checkGLcall("glReadBuffer(GL_BACK)");
2319 if (texture_target != GL_TEXTURE_2D)
2321 gl_info->gl_ops.gl.p_glDisable(texture_target);
2322 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2323 texture_target = GL_TEXTURE_2D;
2326 checkGLcall("glEnd and previous");
2328 left = src_rect->left;
2329 right = src_rect->right;
2331 if (!upsidedown)
2333 top = src_surface->resource.height - src_rect->top;
2334 bottom = src_surface->resource.height - src_rect->bottom;
2336 else
2338 top = src_surface->resource.height - src_rect->bottom;
2339 bottom = src_surface->resource.height - src_rect->top;
2342 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
2344 left /= src_surface->pow2Width;
2345 right /= src_surface->pow2Width;
2346 top /= src_surface->pow2Height;
2347 bottom /= src_surface->pow2Height;
2350 /* draw the source texture stretched and upside down. The correct surface is bound already */
2351 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2352 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2354 context_set_draw_buffer(context, drawBuffer);
2355 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
2357 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2358 /* bottom left */
2359 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
2360 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2362 /* top left */
2363 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
2364 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
2366 /* top right */
2367 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
2368 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2370 /* bottom right */
2371 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
2372 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
2373 gl_info->gl_ops.gl.p_glEnd();
2374 checkGLcall("glEnd and previous");
2376 if (texture_target != dst_surface->texture_target)
2378 gl_info->gl_ops.gl.p_glDisable(texture_target);
2379 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
2380 texture_target = dst_surface->texture_target;
2383 /* Now read the stretched and upside down image into the destination texture */
2384 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
2385 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
2387 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
2388 0, 0, /* We blitted the image to the origin */
2389 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2390 checkGLcall("glCopyTexSubImage2D");
2392 if (drawBuffer == GL_BACK)
2394 /* Write the back buffer backup back. */
2395 if (backup)
2397 if (texture_target != GL_TEXTURE_2D)
2399 gl_info->gl_ops.gl.p_glDisable(texture_target);
2400 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2401 texture_target = GL_TEXTURE_2D;
2403 context_bind_texture(context, GL_TEXTURE_2D, backup);
2405 else
2407 if (texture_target != src_surface->texture_target)
2409 gl_info->gl_ops.gl.p_glDisable(texture_target);
2410 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
2411 texture_target = src_surface->texture_target;
2413 context_bind_texture(context, src_surface->texture_target, src_texture->texture_rgb.name);
2416 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2417 /* top left */
2418 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
2419 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
2421 /* bottom left */
2422 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
2423 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2425 /* bottom right */
2426 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
2427 (float)fbheight / (float)src_surface->pow2Height);
2428 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
2430 /* top right */
2431 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
2432 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
2433 gl_info->gl_ops.gl.p_glEnd();
2435 gl_info->gl_ops.gl.p_glDisable(texture_target);
2436 checkGLcall("glDisable(texture_target)");
2438 /* Cleanup */
2439 if (src != src_texture->texture_rgb.name && src != backup)
2441 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
2442 checkGLcall("glDeleteTextures(1, &src)");
2444 if (backup)
2446 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
2447 checkGLcall("glDeleteTextures(1, &backup)");
2450 if (wined3d_settings.strict_draw_ordering)
2451 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2453 context_release(context);
2455 /* The texture is now most up to date - If the surface is a render target
2456 * and has a drawable, this path is never entered. */
2457 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2458 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2461 /* Front buffer coordinates are always full screen coordinates, but our GL
2462 * drawable is limited to the window's client area. The sysmem and texture
2463 * copies do have the full screen size. Note that GL has a bottom-left
2464 * origin, while D3D has a top-left origin. */
2465 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
2467 UINT drawable_height;
2469 if (surface->container->swapchain && surface->container == surface->container->swapchain->front_buffer)
2471 POINT offset = {0, 0};
2472 RECT windowsize;
2474 ScreenToClient(window, &offset);
2475 OffsetRect(rect, offset.x, offset.y);
2477 GetClientRect(window, &windowsize);
2478 drawable_height = windowsize.bottom - windowsize.top;
2480 else
2482 drawable_height = surface->resource.height;
2485 rect->top = drawable_height - rect->top;
2486 rect->bottom = drawable_height - rect->bottom;
2489 /* Context activation is done by the caller. */
2490 static void surface_blt_to_drawable(const struct wined3d_device *device,
2491 struct wined3d_context *old_ctx,
2492 enum wined3d_texture_filter_type filter, BOOL alpha_test,
2493 struct wined3d_surface *src_surface, const RECT *src_rect_in,
2494 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
2496 struct wined3d_texture *src_texture = src_surface->container;
2497 struct wined3d_texture *dst_texture = dst_surface->container;
2498 const struct wined3d_gl_info *gl_info;
2499 struct wined3d_context *context = old_ctx;
2500 struct wined3d_surface *restore_rt = NULL;
2501 RECT src_rect, dst_rect;
2503 src_rect = *src_rect_in;
2504 dst_rect = *dst_rect_in;
2506 restore_rt = context_get_rt_surface(old_ctx);
2507 if (restore_rt != dst_surface)
2508 context = context_acquire(device, dst_surface);
2509 else
2510 restore_rt = NULL;
2512 gl_info = context->gl_info;
2514 /* Make sure the surface is up-to-date. This should probably use
2515 * surface_load_location() and worry about the destination surface too,
2516 * unless we're overwriting it completely. */
2517 wined3d_texture_load(src_texture, context, FALSE);
2519 /* Activate the destination context, set it up for blitting */
2520 context_apply_blit_state(context, device);
2522 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
2523 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
2525 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
2527 if (alpha_test)
2529 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2530 checkGLcall("glEnable(GL_ALPHA_TEST)");
2532 /* For P8 surfaces, the alpha component contains the palette index.
2533 * Which means that the colorkey is one of the palette entries. In
2534 * other cases pixels that should be masked away have alpha set to 0. */
2535 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2536 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2537 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2538 else
2539 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2540 checkGLcall("glAlphaFunc");
2542 else
2544 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2545 checkGLcall("glDisable(GL_ALPHA_TEST)");
2548 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
2550 if (alpha_test)
2552 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2553 checkGLcall("glDisable(GL_ALPHA_TEST)");
2556 /* Leave the opengl state valid for blitting */
2557 device->blitter->unset_shader(context->gl_info);
2559 if (wined3d_settings.strict_draw_ordering
2560 || (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture))
2561 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2563 if (restore_rt)
2564 context_restore(context, restore_rt);
2567 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
2569 struct wined3d_resource *resource = &s->container->resource;
2570 struct wined3d_device *device = resource->device;
2571 struct wined3d_rendertarget_view_desc view_desc;
2572 struct wined3d_rendertarget_view *view;
2573 const struct blit_shader *blitter;
2574 HRESULT hr;
2576 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
2577 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
2579 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2580 return WINED3DERR_INVALIDCALL;
2583 view_desc.format_id = resource->format->id;
2584 view_desc.u.texture.level_idx = s->texture_level;
2585 view_desc.u.texture.layer_idx = s->texture_layer;
2586 view_desc.u.texture.layer_count = 1;
2587 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
2588 resource, NULL, &wined3d_null_parent_ops, &view)))
2590 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
2591 return hr;
2594 hr = blitter->color_fill(device, view, rect, color);
2595 wined3d_rendertarget_view_decref(view);
2597 return hr;
2600 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
2601 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
2602 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2604 struct wined3d_texture *dst_texture = dst_surface->container;
2605 struct wined3d_device *device = dst_texture->resource.device;
2606 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
2607 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
2608 struct wined3d_texture *src_texture;
2610 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2611 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2612 flags, fx, debug_d3dtexturefiltertype(filter));
2614 /* Get the swapchain. One of the surfaces has to be a primary surface */
2615 if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2617 WARN("Destination is in sysmem, rejecting gl blt\n");
2618 return WINED3DERR_INVALIDCALL;
2621 dst_swapchain = dst_texture->swapchain;
2623 if (src_surface)
2625 src_texture = src_surface->container;
2626 if (src_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2628 WARN("Src is in sysmem, rejecting gl blt\n");
2629 return WINED3DERR_INVALIDCALL;
2632 src_swapchain = src_texture->swapchain;
2634 else
2636 src_texture = NULL;
2637 src_swapchain = NULL;
2640 /* Early sort out of cases where no render target is used */
2641 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
2643 TRACE("No surface is render target, not using hardware blit.\n");
2644 return WINED3DERR_INVALIDCALL;
2647 /* No destination color keying supported */
2648 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
2650 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2651 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2652 return WINED3DERR_INVALIDCALL;
2655 if (dst_swapchain && dst_swapchain == src_swapchain)
2657 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2658 return WINED3DERR_INVALIDCALL;
2661 if (dst_swapchain && src_swapchain)
2663 FIXME("Implement hardware blit between two different swapchains\n");
2664 return WINED3DERR_INVALIDCALL;
2667 if (dst_swapchain)
2669 /* Handled with regular texture -> swapchain blit */
2670 if (src_surface == rt)
2671 TRACE("Blit from active render target to a swapchain\n");
2673 else if (src_swapchain && dst_surface == rt)
2675 FIXME("Implement blit from a swapchain to the active render target\n");
2676 return WINED3DERR_INVALIDCALL;
2679 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
2681 /* Blit from render target to texture */
2682 BOOL stretchx;
2684 /* P8 read back is not implemented */
2685 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
2686 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
2688 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2689 return WINED3DERR_INVALIDCALL;
2692 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
2694 TRACE("Color keying not supported by frame buffer to texture blit\n");
2695 return WINED3DERR_INVALIDCALL;
2696 /* Destination color key is checked above */
2699 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
2700 stretchx = TRUE;
2701 else
2702 stretchx = FALSE;
2704 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2705 * flip the image nor scale it.
2707 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2708 * -> If the app wants an image width an unscaled width, copy it line per line
2709 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2710 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2711 * back buffer. This is slower than reading line per line, thus not used for flipping
2712 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2713 * pixel by pixel. */
2714 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
2715 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
2717 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2718 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
2720 else
2722 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2723 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
2726 surface_evict_sysmem(dst_surface);
2728 return WINED3D_OK;
2731 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2732 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2733 return WINED3DERR_INVALIDCALL;
2736 /* Context activation is done by the caller. */
2737 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
2738 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
2740 struct wined3d_device *device = surface->container->resource.device;
2741 const struct wined3d_gl_info *gl_info = context->gl_info;
2742 GLint compare_mode = GL_NONE;
2743 struct blt_info info;
2744 GLint old_binding = 0;
2745 RECT rect;
2747 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
2749 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2750 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2751 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2752 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2753 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2754 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
2755 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
2756 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
2757 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2758 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
2759 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
2761 SetRect(&rect, 0, h, w, 0);
2762 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
2763 context_active_texture(context, context->gl_info, 0);
2764 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
2765 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
2766 if (gl_info->supported[ARB_SHADOW])
2768 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
2769 if (compare_mode != GL_NONE)
2770 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
2773 device->shader_backend->shader_select_depth_blt(device->shader_priv,
2774 gl_info, info.tex_type, &surface->ds_current_size);
2776 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
2777 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
2778 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
2779 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
2780 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
2781 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
2782 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
2783 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
2784 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
2785 gl_info->gl_ops.gl.p_glEnd();
2787 if (compare_mode != GL_NONE)
2788 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
2789 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
2791 gl_info->gl_ops.gl.p_glPopAttrib();
2793 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
2796 void surface_modify_ds_location(struct wined3d_surface *surface,
2797 DWORD location, UINT w, UINT h)
2799 struct wined3d_texture_sub_resource *sub_resource;
2801 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
2803 sub_resource = surface_get_sub_resource(surface);
2804 if (((sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
2805 || (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
2806 && (location & WINED3D_LOCATION_TEXTURE_RGB)))
2807 wined3d_texture_set_dirty(surface->container);
2809 surface->ds_current_size.cx = w;
2810 surface->ds_current_size.cy = h;
2811 sub_resource->locations = location;
2814 /* Context activation is done by the caller. */
2815 static void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
2817 struct wined3d_texture *texture = surface->container;
2818 struct wined3d_device *device = texture->resource.device;
2819 const struct wined3d_gl_info *gl_info = context->gl_info;
2820 GLsizei w, h;
2822 TRACE("surface %p, context %p, new location %#x.\n", surface, context, location);
2824 /* TODO: Make this work for modes other than FBO */
2825 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
2827 if (!(surface_get_sub_resource(surface)->locations & location))
2829 w = surface->ds_current_size.cx;
2830 h = surface->ds_current_size.cy;
2831 surface->ds_current_size.cx = 0;
2832 surface->ds_current_size.cy = 0;
2834 else
2836 w = surface->resource.width;
2837 h = surface->resource.height;
2840 if (surface->current_renderbuffer)
2842 FIXME("Not supported with fixed up depth stencil.\n");
2843 return;
2846 wined3d_surface_prepare(surface, context, location);
2848 if (location == WINED3D_LOCATION_TEXTURE_RGB)
2850 GLint old_binding = 0;
2851 GLenum bind_target;
2853 /* The render target is allowed to be smaller than the depth/stencil
2854 * buffer, so the onscreen depth/stencil buffer is potentially smaller
2855 * than the offscreen surface. Don't overwrite the offscreen surface
2856 * with undefined data. */
2857 w = min(w, context->swapchain->desc.backbuffer_width);
2858 h = min(h, context->swapchain->desc.backbuffer_height);
2860 TRACE("Copying onscreen depth buffer to depth texture.\n");
2862 if (!device->depth_blt_texture)
2863 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
2865 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2866 * directly on the FBO texture. That's because we need to flip. */
2867 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2868 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2869 NULL, WINED3D_LOCATION_DRAWABLE);
2870 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2872 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
2873 bind_target = GL_TEXTURE_RECTANGLE_ARB;
2875 else
2877 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
2878 bind_target = GL_TEXTURE_2D;
2880 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
2881 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
2882 * internal format, because the internal format might include stencil
2883 * data. In principle we should copy stencil data as well, but unless
2884 * the driver supports stencil export it's hard to do, and doesn't
2885 * seem to be needed in practice. If the hardware doesn't support
2886 * writing stencil data, the glCopyTexImage2D() call might trigger
2887 * software fallbacks. */
2888 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
2889 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2890 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2891 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2892 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2893 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2894 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
2896 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2897 NULL, surface, WINED3D_LOCATION_TEXTURE_RGB);
2898 context_set_draw_buffer(context, GL_NONE);
2900 /* Do the actual blit */
2901 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
2902 checkGLcall("depth_blt");
2904 context_invalidate_state(context, STATE_FRAMEBUFFER);
2906 if (wined3d_settings.strict_draw_ordering)
2907 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2909 else if (location == WINED3D_LOCATION_DRAWABLE)
2911 TRACE("Copying depth texture to onscreen depth buffer.\n");
2913 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2914 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2915 NULL, WINED3D_LOCATION_DRAWABLE);
2916 surface_depth_blt(surface, context, texture->texture_rgb.name,
2917 0, surface->pow2Height - h, w, h, surface->texture_target);
2918 checkGLcall("depth_blt");
2920 context_invalidate_state(context, STATE_FRAMEBUFFER);
2922 if (wined3d_settings.strict_draw_ordering)
2923 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2925 else
2927 ERR("Invalid location (%#x) specified.\n", location);
2931 static DWORD resource_access_from_location(DWORD location)
2933 switch (location)
2935 case WINED3D_LOCATION_SYSMEM:
2936 case WINED3D_LOCATION_USER_MEMORY:
2937 case WINED3D_LOCATION_DIB:
2938 case WINED3D_LOCATION_BUFFER:
2939 return WINED3D_RESOURCE_ACCESS_CPU;
2941 case WINED3D_LOCATION_DRAWABLE:
2942 case WINED3D_LOCATION_TEXTURE_SRGB:
2943 case WINED3D_LOCATION_TEXTURE_RGB:
2944 case WINED3D_LOCATION_RB_MULTISAMPLE:
2945 case WINED3D_LOCATION_RB_RESOLVED:
2946 return WINED3D_RESOURCE_ACCESS_GPU;
2948 default:
2949 FIXME("Unhandled location %#x.\n", location);
2950 return 0;
2954 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
2956 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2957 struct wined3d_texture *texture = surface->container;
2958 struct wined3d_device *device = texture->resource.device;
2959 struct wined3d_context *context;
2960 const struct wined3d_gl_info *gl_info;
2961 struct wined3d_bo_address dst, src;
2962 UINT size = surface->resource.size;
2964 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
2965 wined3d_texture_get_memory(texture, sub_resource_idx, &src,
2966 texture->sub_resources[sub_resource_idx].locations);
2968 if (dst.buffer_object)
2970 context = context_acquire(device, NULL);
2971 gl_info = context->gl_info;
2972 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
2973 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
2974 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2975 checkGLcall("Upload PBO");
2976 context_release(context);
2977 return;
2979 if (src.buffer_object)
2981 context = context_acquire(device, NULL);
2982 gl_info = context->gl_info;
2983 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
2984 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
2985 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2986 checkGLcall("Download PBO");
2987 context_release(context);
2988 return;
2990 memcpy(dst.addr, src.addr, size);
2993 /* Context activation is done by the caller. */
2994 static void surface_load_sysmem(struct wined3d_surface *surface,
2995 struct wined3d_context *context, DWORD dst_location)
2997 const struct wined3d_gl_info *gl_info = context->gl_info;
2998 struct wined3d_texture_sub_resource *sub_resource;
3000 wined3d_surface_prepare(surface, context, dst_location);
3002 sub_resource = surface_get_sub_resource(surface);
3003 if (sub_resource->locations & surface_simple_locations)
3005 surface_copy_simple_location(surface, dst_location);
3006 return;
3009 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
3010 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
3012 /* Download the surface to system memory. */
3013 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
3015 struct wined3d_texture *texture = surface->container;
3017 wined3d_texture_bind_and_dirtify(texture, context,
3018 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
3019 surface_download_data(surface, gl_info, dst_location);
3020 ++texture->download_count;
3022 return;
3025 if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3027 read_from_framebuffer(surface, context, dst_location);
3028 return;
3031 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
3032 surface, wined3d_debug_location(sub_resource->locations));
3035 /* Context activation is done by the caller. */
3036 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
3037 struct wined3d_context *context)
3039 struct wined3d_texture *texture = surface->container;
3040 RECT r;
3042 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3043 && wined3d_resource_is_offscreen(&texture->resource))
3045 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
3046 return WINED3DERR_INVALIDCALL;
3049 surface_get_rect(surface, NULL, &r);
3050 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
3051 surface_blt_to_drawable(texture->resource.device, context,
3052 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
3054 return WINED3D_OK;
3057 static HRESULT surface_load_texture(struct wined3d_surface *surface,
3058 struct wined3d_context *context, BOOL srgb)
3060 unsigned int width, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
3061 const RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
3062 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3063 const struct wined3d_gl_info *gl_info = context->gl_info;
3064 struct wined3d_texture *texture = surface->container;
3065 struct wined3d_device *device = texture->resource.device;
3066 const struct wined3d_color_key_conversion *conversion;
3067 struct wined3d_texture_sub_resource *sub_resource;
3068 struct wined3d_bo_address data;
3069 struct wined3d_format format;
3070 POINT dst_point = {0, 0};
3071 BYTE *mem = NULL;
3073 sub_resource = surface_get_sub_resource(surface);
3074 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
3075 && wined3d_resource_is_offscreen(&texture->resource)
3076 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
3078 surface_load_fb_texture(surface, srgb, context);
3080 return WINED3D_OK;
3083 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
3084 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
3085 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3086 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3087 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3089 if (srgb)
3090 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
3091 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
3092 else
3093 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
3094 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
3096 return WINED3D_OK;
3099 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
3100 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
3101 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3102 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3103 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3105 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
3106 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
3107 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
3108 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
3110 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
3111 &rect, surface, dst_location, &rect);
3113 return WINED3D_OK;
3116 /* Upload from system memory */
3118 if (srgb)
3120 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
3121 == WINED3D_LOCATION_TEXTURE_RGB)
3123 /* Performance warning... */
3124 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
3125 surface_load_location(surface, context, surface->resource.map_binding);
3128 else
3130 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
3131 == WINED3D_LOCATION_TEXTURE_SRGB)
3133 /* Performance warning... */
3134 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
3135 surface_load_location(surface, context, surface->resource.map_binding);
3139 if (!(sub_resource->locations & surface_simple_locations))
3141 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
3142 /* Lets hope we get it from somewhere... */
3143 surface_load_location(surface, context, WINED3D_LOCATION_SYSMEM);
3146 wined3d_texture_prepare_texture(texture, context, srgb);
3147 wined3d_texture_bind_and_dirtify(texture, context, srgb);
3148 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
3150 width = surface->resource.width;
3152 format = *texture->resource.format;
3153 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
3154 format = *wined3d_get_format(gl_info, conversion->dst_format);
3156 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
3157 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
3158 * getting called. */
3159 if ((format.convert || conversion) && texture->sub_resources[sub_resource_idx].buffer_object)
3161 TRACE("Removing the pbo attached to surface %p.\n", surface);
3163 if (surface->flags & SFLAG_DIBSECTION)
3164 surface->resource.map_binding = WINED3D_LOCATION_DIB;
3165 else
3166 surface->resource.map_binding = WINED3D_LOCATION_SYSMEM;
3168 surface_load_location(surface, context, surface->resource.map_binding);
3169 wined3d_texture_remove_buffer_object(texture, sub_resource_idx, gl_info);
3172 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
3173 if (format.convert)
3175 /* This code is entered for texture formats which need a fixup. */
3176 UINT height = surface->resource.height;
3178 format.byte_count = format.conv_byte_count;
3179 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
3181 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3183 ERR("Out of memory (%u).\n", dst_slice_pitch);
3184 context_release(context);
3185 return E_OUTOFMEMORY;
3187 format.convert(data.addr, mem, src_row_pitch, src_slice_pitch,
3188 dst_row_pitch, dst_slice_pitch, width, height, 1);
3189 src_row_pitch = dst_row_pitch;
3190 data.addr = mem;
3192 else if (conversion)
3194 /* This code is only entered for color keying fixups */
3195 struct wined3d_palette *palette = NULL;
3196 UINT height = surface->resource.height;
3198 wined3d_format_calculate_pitch(&format, device->surface_alignment,
3199 width, height, &dst_row_pitch, &dst_slice_pitch);
3201 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3203 ERR("Out of memory (%u).\n", dst_slice_pitch);
3204 context_release(context);
3205 return E_OUTOFMEMORY;
3207 if (texture->swapchain && texture->swapchain->palette)
3208 palette = texture->swapchain->palette;
3209 conversion->convert(data.addr, src_row_pitch, mem, dst_row_pitch,
3210 width, height, palette, &texture->async.gl_color_key);
3211 src_row_pitch = dst_row_pitch;
3212 data.addr = mem;
3215 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
3216 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
3218 HeapFree(GetProcessHeap(), 0, mem);
3220 return WINED3D_OK;
3223 /* Context activation is done by the caller. */
3224 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
3225 DWORD dst_location)
3227 const RECT rect = {0, 0, surface->resource.width, surface->resource.height};
3228 DWORD locations = surface_get_sub_resource(surface)->locations;
3229 DWORD src_location;
3231 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
3232 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
3233 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
3234 src_location = WINED3D_LOCATION_RB_RESOLVED;
3235 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
3236 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
3237 else /* surface_blt_fbo will load the source location if necessary. */
3238 src_location = WINED3D_LOCATION_TEXTURE_RGB;
3240 surface_blt_fbo(surface->container->resource.device, context, WINED3D_TEXF_POINT,
3241 surface, src_location, &rect, surface, dst_location, &rect);
3244 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
3245 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
3247 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3248 struct wined3d_texture *texture = surface->container;
3249 struct wined3d_texture_sub_resource *sub_resource;
3250 HRESULT hr;
3252 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
3254 sub_resource = &texture->sub_resources[sub_resource_idx];
3255 if (sub_resource->locations & location && (!(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3256 || (surface->ds_current_size.cx == surface->resource.width
3257 && surface->ds_current_size.cy == surface->resource.height)))
3259 TRACE("Location (%#x) is already up to date.\n", location);
3260 return WINED3D_OK;
3263 if (WARN_ON(d3d))
3265 DWORD required_access = resource_access_from_location(location);
3266 if ((texture->resource.access_flags & required_access) != required_access)
3267 WARN("Operation requires %#x access, but surface only has %#x.\n",
3268 required_access, texture->resource.access_flags);
3271 if (sub_resource->locations & WINED3D_LOCATION_DISCARDED)
3273 TRACE("Surface previously discarded, nothing to do.\n");
3274 wined3d_surface_prepare(surface, context, location);
3275 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3276 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3277 goto done;
3280 if (!sub_resource->locations)
3282 ERR("Surface %p does not have any up to date location.\n", surface);
3283 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3284 return surface_load_location(surface, context, location);
3287 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3289 if ((location == WINED3D_LOCATION_TEXTURE_RGB && sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3290 || (location == WINED3D_LOCATION_DRAWABLE && sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB))
3292 surface_load_ds_location(surface, context, location);
3293 goto done;
3296 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
3297 wined3d_debug_location(sub_resource->locations), wined3d_debug_location(location));
3298 return WINED3DERR_INVALIDCALL;
3301 switch (location)
3303 case WINED3D_LOCATION_DIB:
3304 case WINED3D_LOCATION_USER_MEMORY:
3305 case WINED3D_LOCATION_SYSMEM:
3306 case WINED3D_LOCATION_BUFFER:
3307 surface_load_sysmem(surface, context, location);
3308 break;
3310 case WINED3D_LOCATION_DRAWABLE:
3311 if (FAILED(hr = surface_load_drawable(surface, context)))
3312 return hr;
3313 break;
3315 case WINED3D_LOCATION_RB_RESOLVED:
3316 case WINED3D_LOCATION_RB_MULTISAMPLE:
3317 surface_load_renderbuffer(surface, context, location);
3318 break;
3320 case WINED3D_LOCATION_TEXTURE_RGB:
3321 case WINED3D_LOCATION_TEXTURE_SRGB:
3322 if (FAILED(hr = surface_load_texture(surface, context,
3323 location == WINED3D_LOCATION_TEXTURE_SRGB)))
3324 return hr;
3325 break;
3327 default:
3328 ERR("Don't know how to handle location %#x.\n", location);
3329 break;
3332 done:
3333 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3335 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3337 surface->ds_current_size.cx = surface->resource.width;
3338 surface->ds_current_size.cy = surface->resource.height;
3341 if (location != WINED3D_LOCATION_SYSMEM && (sub_resource->locations & WINED3D_LOCATION_SYSMEM))
3342 surface_evict_sysmem(surface);
3344 return WINED3D_OK;
3347 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
3348 /* Context activation is done by the caller. */
3349 static void ffp_blit_free(struct wined3d_device *device) { }
3351 /* Context activation is done by the caller. */
3352 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3353 const struct wined3d_color_key *color_key)
3355 const struct wined3d_gl_info *gl_info = context->gl_info;
3357 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
3358 checkGLcall("glEnable(target)");
3360 return WINED3D_OK;
3363 /* Context activation is done by the caller. */
3364 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
3366 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
3367 checkGLcall("glDisable(GL_TEXTURE_2D)");
3368 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
3370 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
3371 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3373 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
3375 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
3376 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
3380 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
3381 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3382 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3383 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3385 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
3387 TRACE("Source or destination is in system memory.\n");
3388 return FALSE;
3391 switch (blit_op)
3393 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3394 if (d3d_info->shader_color_key)
3396 TRACE("Color keying requires converted textures.\n");
3397 return FALSE;
3399 case WINED3D_BLIT_OP_COLOR_BLIT:
3400 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3401 if (TRACE_ON(d3d))
3403 TRACE("Checking support for fixup:\n");
3404 dump_color_fixup_desc(src_format->color_fixup);
3407 /* We only support identity conversions. */
3408 if (!is_identity_fixup(src_format->color_fixup)
3409 || !is_identity_fixup(dst_format->color_fixup))
3411 TRACE("Fixups are not supported.\n");
3412 return FALSE;
3415 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3417 TRACE("Can only blit to render targets.\n");
3418 return FALSE;
3420 return TRUE;
3422 case WINED3D_BLIT_OP_COLOR_FILL:
3423 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3425 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
3426 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
3427 return FALSE;
3429 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3431 TRACE("Color fill not supported\n");
3432 return FALSE;
3435 /* FIXME: We should reject color fills on formats with fixups,
3436 * but this would break P8 color fills for example. */
3438 return TRUE;
3440 case WINED3D_BLIT_OP_DEPTH_FILL:
3441 return TRUE;
3443 default:
3444 TRACE("Unsupported blit_op=%d\n", blit_op);
3445 return FALSE;
3449 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
3450 const RECT *rect, const struct wined3d_color *color)
3452 const RECT draw_rect = {0, 0, view->width, view->height};
3453 struct wined3d_fb_state fb = {&view, NULL};
3455 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
3457 return WINED3D_OK;
3460 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
3461 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3462 float depth, DWORD stencil)
3464 const RECT draw_rect = {0, 0, view->width, view->height};
3465 struct wined3d_fb_state fb = {NULL, view};
3467 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, clear_flags, NULL, depth, stencil);
3469 return WINED3D_OK;
3472 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3473 struct wined3d_surface *src_surface, const RECT *src_rect,
3474 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3475 const struct wined3d_color_key *color_key)
3477 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3478 struct wined3d_texture *dst_texture = dst_surface->container;
3479 struct wined3d_texture *src_texture = src_surface->container;
3480 struct wined3d_context *context;
3482 /* Blit from offscreen surface to render target */
3483 struct wined3d_color_key old_blt_key = src_texture->async.src_blt_color_key;
3484 DWORD old_color_key_flags = src_texture->async.color_key_flags;
3486 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3488 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
3490 context = context_acquire(device, dst_surface);
3492 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3493 glEnable(GL_ALPHA_TEST);
3495 surface_blt_to_drawable(device, context, filter,
3496 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
3498 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3499 glDisable(GL_ALPHA_TEST);
3501 context_release(context);
3503 /* Restore the color key parameters */
3504 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
3505 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
3507 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_texture->resource.draw_binding);
3508 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_texture->resource.draw_binding);
3511 const struct blit_shader ffp_blit = {
3512 ffp_blit_alloc,
3513 ffp_blit_free,
3514 ffp_blit_set,
3515 ffp_blit_unset,
3516 ffp_blit_supported,
3517 ffp_blit_color_fill,
3518 ffp_blit_depth_fill,
3519 ffp_blit_blit_surface,
3522 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
3524 return WINED3D_OK;
3527 /* Context activation is done by the caller. */
3528 static void cpu_blit_free(struct wined3d_device *device)
3532 /* Context activation is done by the caller. */
3533 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3534 const struct wined3d_color_key *color_key)
3536 return WINED3D_OK;
3539 /* Context activation is done by the caller. */
3540 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
3544 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
3545 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3546 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3547 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3549 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
3551 return TRUE;
3554 return FALSE;
3557 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
3558 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
3559 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
3561 UINT row_block_count;
3562 const BYTE *src_row;
3563 BYTE *dst_row;
3564 UINT x, y;
3566 src_row = src_data;
3567 dst_row = dst_data;
3569 row_block_count = (update_w + format->block_width - 1) / format->block_width;
3571 if (!flags)
3573 for (y = 0; y < update_h; y += format->block_height)
3575 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
3576 src_row += src_pitch;
3577 dst_row += dst_pitch;
3580 return WINED3D_OK;
3583 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
3585 src_row += (((update_h / format->block_height) - 1) * src_pitch);
3587 switch (format->id)
3589 case WINED3DFMT_DXT1:
3590 for (y = 0; y < update_h; y += format->block_height)
3592 struct block
3594 WORD color[2];
3595 BYTE control_row[4];
3598 const struct block *s = (const struct block *)src_row;
3599 struct block *d = (struct block *)dst_row;
3601 for (x = 0; x < row_block_count; ++x)
3603 d[x].color[0] = s[x].color[0];
3604 d[x].color[1] = s[x].color[1];
3605 d[x].control_row[0] = s[x].control_row[3];
3606 d[x].control_row[1] = s[x].control_row[2];
3607 d[x].control_row[2] = s[x].control_row[1];
3608 d[x].control_row[3] = s[x].control_row[0];
3610 src_row -= src_pitch;
3611 dst_row += dst_pitch;
3613 return WINED3D_OK;
3615 case WINED3DFMT_DXT2:
3616 case WINED3DFMT_DXT3:
3617 for (y = 0; y < update_h; y += format->block_height)
3619 struct block
3621 WORD alpha_row[4];
3622 WORD color[2];
3623 BYTE control_row[4];
3626 const struct block *s = (const struct block *)src_row;
3627 struct block *d = (struct block *)dst_row;
3629 for (x = 0; x < row_block_count; ++x)
3631 d[x].alpha_row[0] = s[x].alpha_row[3];
3632 d[x].alpha_row[1] = s[x].alpha_row[2];
3633 d[x].alpha_row[2] = s[x].alpha_row[1];
3634 d[x].alpha_row[3] = s[x].alpha_row[0];
3635 d[x].color[0] = s[x].color[0];
3636 d[x].color[1] = s[x].color[1];
3637 d[x].control_row[0] = s[x].control_row[3];
3638 d[x].control_row[1] = s[x].control_row[2];
3639 d[x].control_row[2] = s[x].control_row[1];
3640 d[x].control_row[3] = s[x].control_row[0];
3642 src_row -= src_pitch;
3643 dst_row += dst_pitch;
3645 return WINED3D_OK;
3647 default:
3648 FIXME("Compressed flip not implemented for format %s.\n",
3649 debug_d3dformat(format->id));
3650 return E_NOTIMPL;
3654 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3655 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
3657 return E_NOTIMPL;
3660 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3661 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3662 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3663 enum wined3d_texture_filter_type filter)
3665 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
3666 const struct wined3d_format *src_format, *dst_format;
3667 struct wined3d_texture *converted_texture = NULL;
3668 unsigned int src_fmt_flags, dst_fmt_flags;
3669 struct wined3d_map_desc dst_map, src_map;
3670 const BYTE *sbase = NULL;
3671 HRESULT hr = WINED3D_OK;
3672 BOOL same_sub_resource;
3673 const BYTE *sbuf;
3674 BYTE *dbuf;
3675 int x, y;
3677 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3678 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3679 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
3680 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3682 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
3684 same_sub_resource = TRUE;
3685 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, NULL, 0);
3686 src_map = dst_map;
3687 src_format = dst_texture->resource.format;
3688 dst_format = src_format;
3689 dst_fmt_flags = dst_texture->resource.format_flags;
3690 src_fmt_flags = dst_fmt_flags;
3692 else
3694 same_sub_resource = FALSE;
3695 dst_format = dst_texture->resource.format;
3696 dst_fmt_flags = dst_texture->resource.format_flags;
3697 if (src_texture)
3699 if (dst_texture->resource.format->id != src_texture->resource.format->id)
3701 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
3703 /* The conv function writes a FIXME */
3704 WARN("Cannot convert source surface format to dest format.\n");
3705 goto release;
3707 src_texture = converted_texture;
3708 src_sub_resource_idx = 0;
3710 wined3d_resource_map(&src_texture->resource, src_sub_resource_idx, &src_map, NULL, WINED3D_MAP_READONLY);
3711 src_format = src_texture->resource.format;
3712 src_fmt_flags = src_texture->resource.format_flags;
3714 else
3716 src_format = dst_format;
3717 src_fmt_flags = dst_fmt_flags;
3720 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, dst_box, 0);
3723 bpp = dst_format->byte_count;
3724 src_height = src_box->bottom - src_box->top;
3725 src_width = src_box->right - src_box->left;
3726 dst_height = dst_box->bottom - dst_box->top;
3727 dst_width = dst_box->right - dst_box->left;
3728 row_byte_count = dst_width * bpp;
3730 if (src_texture)
3731 sbase = (BYTE *)src_map.data
3732 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
3733 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
3734 if (same_sub_resource)
3735 dbuf = (BYTE *)dst_map.data
3736 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
3737 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
3738 else
3739 dbuf = dst_map.data;
3741 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
3743 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
3745 if (same_sub_resource)
3747 FIXME("Only plain blits supported on compressed surfaces.\n");
3748 hr = E_NOTIMPL;
3749 goto release;
3752 if (src_height != dst_height || src_width != dst_width)
3754 WARN("Stretching not supported on compressed surfaces.\n");
3755 hr = WINED3DERR_INVALIDCALL;
3756 goto release;
3759 if (!wined3d_texture_check_block_align(src_texture,
3760 src_sub_resource_idx % src_texture->level_count, src_box))
3762 WARN("Source rectangle not block-aligned.\n");
3763 hr = WINED3DERR_INVALIDCALL;
3764 goto release;
3767 if (!wined3d_texture_check_block_align(dst_texture,
3768 dst_sub_resource_idx % dst_texture->level_count, dst_box))
3770 WARN("Destination rectangle not block-aligned.\n");
3771 hr = WINED3DERR_INVALIDCALL;
3772 goto release;
3775 hr = surface_cpu_blt_compressed(sbase, dbuf,
3776 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
3777 src_format, flags, fx);
3778 goto release;
3781 /* First, all the 'source-less' blits */
3782 if (flags & WINED3D_BLT_COLOR_FILL)
3784 hr = _Blt_ColorFill(dbuf, dst_width, dst_height, bpp, dst_map.row_pitch, fx->fill_color);
3785 flags &= ~WINED3D_BLT_COLOR_FILL;
3788 if (flags & WINED3D_BLT_DEPTH_FILL)
3789 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3791 /* Now the 'with source' blits. */
3792 if (src_texture)
3794 int sx, xinc, sy, yinc;
3796 if (!dst_width || !dst_height) /* Hmm... stupid program? */
3797 goto release;
3799 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3800 && (src_width != dst_width || src_height != dst_height))
3802 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3803 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
3806 xinc = (src_width << 16) / dst_width;
3807 yinc = (src_height << 16) / dst_height;
3809 if (!flags)
3811 /* No effects, we can cheat here. */
3812 if (dst_width == src_width)
3814 if (dst_height == src_height)
3816 /* No stretching in either direction. This needs to be as
3817 * fast as possible. */
3818 sbuf = sbase;
3820 /* Check for overlapping surfaces. */
3821 if (!same_sub_resource || dst_box->top < src_box->top
3822 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
3824 /* No overlap, or dst above src, so copy from top downwards. */
3825 for (y = 0; y < dst_height; ++y)
3827 memcpy(dbuf, sbuf, row_byte_count);
3828 sbuf += src_map.row_pitch;
3829 dbuf += dst_map.row_pitch;
3832 else if (dst_box->top > src_box->top)
3834 /* Copy from bottom upwards. */
3835 sbuf += src_map.row_pitch * dst_height;
3836 dbuf += dst_map.row_pitch * dst_height;
3837 for (y = 0; y < dst_height; ++y)
3839 sbuf -= src_map.row_pitch;
3840 dbuf -= dst_map.row_pitch;
3841 memcpy(dbuf, sbuf, row_byte_count);
3844 else
3846 /* Src and dst overlapping on the same line, use memmove. */
3847 for (y = 0; y < dst_height; ++y)
3849 memmove(dbuf, sbuf, row_byte_count);
3850 sbuf += src_map.row_pitch;
3851 dbuf += dst_map.row_pitch;
3855 else
3857 /* Stretching in y direction only. */
3858 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3860 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3861 memcpy(dbuf, sbuf, row_byte_count);
3862 dbuf += dst_map.row_pitch;
3866 else
3868 /* Stretching in X direction. */
3869 int last_sy = -1;
3870 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3872 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3874 if ((sy >> 16) == (last_sy >> 16))
3876 /* This source row is the same as last source row -
3877 * Copy the already stretched row. */
3878 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
3880 else
3882 #define STRETCH_ROW(type) \
3883 do { \
3884 const type *s = (const type *)sbuf; \
3885 type *d = (type *)dbuf; \
3886 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3887 d[x] = s[sx >> 16]; \
3888 } while(0)
3890 switch(bpp)
3892 case 1:
3893 STRETCH_ROW(BYTE);
3894 break;
3895 case 2:
3896 STRETCH_ROW(WORD);
3897 break;
3898 case 4:
3899 STRETCH_ROW(DWORD);
3900 break;
3901 case 3:
3903 const BYTE *s;
3904 BYTE *d = dbuf;
3905 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3907 DWORD pixel;
3909 s = sbuf + 3 * (sx >> 16);
3910 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3911 d[0] = (pixel ) & 0xff;
3912 d[1] = (pixel >> 8) & 0xff;
3913 d[2] = (pixel >> 16) & 0xff;
3914 d += 3;
3916 break;
3918 default:
3919 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
3920 hr = WINED3DERR_NOTAVAILABLE;
3921 goto error;
3923 #undef STRETCH_ROW
3925 dbuf += dst_map.row_pitch;
3926 last_sy = sy;
3930 else
3932 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3933 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3934 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3935 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3936 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3938 /* The color keying flags are checked for correctness in ddraw */
3939 if (flags & WINED3D_BLT_SRC_CKEY)
3941 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
3942 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3944 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3946 keylow = fx->src_color_key.color_space_low_value;
3947 keyhigh = fx->src_color_key.color_space_high_value;
3950 if (flags & WINED3D_BLT_DST_CKEY)
3952 /* Destination color keys are taken from the source surface! */
3953 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3954 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3956 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3958 destkeylow = fx->dst_color_key.color_space_low_value;
3959 destkeyhigh = fx->dst_color_key.color_space_high_value;
3962 if (bpp == 1)
3964 keymask = 0xff;
3966 else
3968 DWORD masks[3];
3969 get_color_masks(src_format, masks);
3970 keymask = masks[0]
3971 | masks[1]
3972 | masks[2];
3974 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3975 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3978 if (flags & WINED3D_BLT_FX)
3980 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3981 LONG tmpxy;
3982 dTopLeft = dbuf;
3983 dTopRight = dbuf + ((dst_width - 1) * bpp);
3984 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3985 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3987 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3989 /* I don't think we need to do anything about this flag */
3990 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3992 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3994 tmp = dTopRight;
3995 dTopRight = dTopLeft;
3996 dTopLeft = tmp;
3997 tmp = dBottomRight;
3998 dBottomRight = dBottomLeft;
3999 dBottomLeft = tmp;
4000 dstxinc = dstxinc * -1;
4002 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
4004 tmp = dTopLeft;
4005 dTopLeft = dBottomLeft;
4006 dBottomLeft = tmp;
4007 tmp = dTopRight;
4008 dTopRight = dBottomRight;
4009 dBottomRight = tmp;
4010 dstyinc = dstyinc * -1;
4012 if (fx->fx & WINEDDBLTFX_NOTEARING)
4014 /* I don't think we need to do anything about this flag */
4015 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
4017 if (fx->fx & WINEDDBLTFX_ROTATE180)
4019 tmp = dBottomRight;
4020 dBottomRight = dTopLeft;
4021 dTopLeft = tmp;
4022 tmp = dBottomLeft;
4023 dBottomLeft = dTopRight;
4024 dTopRight = tmp;
4025 dstxinc = dstxinc * -1;
4026 dstyinc = dstyinc * -1;
4028 if (fx->fx & WINEDDBLTFX_ROTATE270)
4030 tmp = dTopLeft;
4031 dTopLeft = dBottomLeft;
4032 dBottomLeft = dBottomRight;
4033 dBottomRight = dTopRight;
4034 dTopRight = tmp;
4035 tmpxy = dstxinc;
4036 dstxinc = dstyinc;
4037 dstyinc = tmpxy;
4038 dstxinc = dstxinc * -1;
4040 if (fx->fx & WINEDDBLTFX_ROTATE90)
4042 tmp = dTopLeft;
4043 dTopLeft = dTopRight;
4044 dTopRight = dBottomRight;
4045 dBottomRight = dBottomLeft;
4046 dBottomLeft = tmp;
4047 tmpxy = dstxinc;
4048 dstxinc = dstyinc;
4049 dstyinc = tmpxy;
4050 dstyinc = dstyinc * -1;
4052 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
4054 /* I don't think we need to do anything about this flag */
4055 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
4057 dbuf = dTopLeft;
4058 flags &= ~(WINED3D_BLT_FX);
4061 #define COPY_COLORKEY_FX(type) \
4062 do { \
4063 const type *s; \
4064 type *d = (type *)dbuf, *dx, tmp; \
4065 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
4067 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
4068 dx = d; \
4069 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
4071 tmp = s[sx >> 16]; \
4072 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
4073 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
4075 dx[0] = tmp; \
4077 dx = (type *)(((BYTE *)dx) + dstxinc); \
4079 d = (type *)(((BYTE *)d) + dstyinc); \
4081 } while(0)
4083 switch (bpp)
4085 case 1:
4086 COPY_COLORKEY_FX(BYTE);
4087 break;
4088 case 2:
4089 COPY_COLORKEY_FX(WORD);
4090 break;
4091 case 4:
4092 COPY_COLORKEY_FX(DWORD);
4093 break;
4094 case 3:
4096 const BYTE *s;
4097 BYTE *d = dbuf, *dx;
4098 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
4100 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
4101 dx = d;
4102 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
4104 DWORD pixel, dpixel = 0;
4105 s = sbuf + 3 * (sx>>16);
4106 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
4107 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
4108 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
4109 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
4111 dx[0] = (pixel ) & 0xff;
4112 dx[1] = (pixel >> 8) & 0xff;
4113 dx[2] = (pixel >> 16) & 0xff;
4115 dx += dstxinc;
4117 d += dstyinc;
4119 break;
4121 default:
4122 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
4123 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
4124 hr = WINED3DERR_NOTAVAILABLE;
4125 goto error;
4126 #undef COPY_COLORKEY_FX
4131 error:
4132 if (flags)
4133 FIXME(" Unsupported flags %#x.\n", flags);
4135 release:
4136 wined3d_resource_unmap(&dst_texture->resource, dst_sub_resource_idx);
4137 if (src_texture && !same_sub_resource)
4138 wined3d_resource_unmap(&src_texture->resource, src_sub_resource_idx);
4139 if (converted_texture)
4140 wined3d_texture_decref(converted_texture);
4142 return hr;
4145 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
4146 const RECT *rect, const struct wined3d_color *color)
4148 const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
4149 static const struct wined3d_box src_box;
4150 struct wined3d_blt_fx fx;
4152 fx.fill_color = wined3d_format_convert_from_float(view->format, color);
4153 return surface_cpu_blt(wined3d_texture_from_resource(view->resource), view->sub_resource_idx,
4154 &box, NULL, 0, &src_box, WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
4157 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
4158 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
4159 float depth, DWORD stencil)
4161 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
4162 return WINED3DERR_INVALIDCALL;
4165 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
4166 struct wined3d_surface *src_surface, const RECT *src_rect,
4167 struct wined3d_surface *dst_surface, const RECT *dst_rect,
4168 const struct wined3d_color_key *color_key)
4170 /* FIXME: Remove error returns from surface_blt_cpu. */
4171 ERR("Blit method not implemented by cpu_blit.\n");
4174 const struct blit_shader cpu_blit = {
4175 cpu_blit_alloc,
4176 cpu_blit_free,
4177 cpu_blit_set,
4178 cpu_blit_unset,
4179 cpu_blit_supported,
4180 cpu_blit_color_fill,
4181 cpu_blit_depth_fill,
4182 cpu_blit_blit_surface,
4185 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
4186 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
4187 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
4189 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
4190 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
4191 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
4192 struct wined3d_texture *dst_texture = dst_surface->container;
4193 struct wined3d_device *device = dst_texture->resource.device;
4194 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
4195 struct wined3d_texture *src_texture = NULL;
4196 DWORD src_ds_flags, dst_ds_flags;
4197 BOOL scale, convert;
4199 static const DWORD simple_blit = WINED3D_BLT_ASYNC
4200 | WINED3D_BLT_COLOR_FILL
4201 | WINED3D_BLT_SRC_CKEY
4202 | WINED3D_BLT_SRC_CKEY_OVERRIDE
4203 | WINED3D_BLT_WAIT
4204 | WINED3D_BLT_DEPTH_FILL
4205 | WINED3D_BLT_DO_NOT_WAIT
4206 | WINED3D_BLT_ALPHA_TEST;
4208 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4209 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
4210 flags, fx, debug_d3dtexturefiltertype(filter));
4211 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
4213 if (fx)
4215 TRACE("fx %#x.\n", fx->fx);
4216 TRACE("fill_color 0x%08x.\n", fx->fill_color);
4217 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
4218 fx->dst_color_key.color_space_low_value,
4219 fx->dst_color_key.color_space_high_value);
4220 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
4221 fx->src_color_key.color_space_low_value,
4222 fx->src_color_key.color_space_high_value);
4225 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
4227 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
4228 return WINEDDERR_SURFACEBUSY;
4231 if (dst_rect->left >= dst_rect->right || dst_rect->top >= dst_rect->bottom
4232 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
4233 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
4234 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
4235 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0)
4237 WARN("The application gave us a bad destination rectangle.\n");
4238 return WINEDDERR_INVALIDRECT;
4241 if (src_surface)
4243 if (src_rect->left >= src_rect->right || src_rect->top >= src_rect->bottom
4244 || src_rect->left > src_surface->resource.width || src_rect->left < 0
4245 || src_rect->top > src_surface->resource.height || src_rect->top < 0
4246 || src_rect->right > src_surface->resource.width || src_rect->right < 0
4247 || src_rect->bottom > src_surface->resource.height || src_rect->bottom < 0)
4249 WARN("The application gave us a bad source rectangle.\n");
4250 return WINEDDERR_INVALIDRECT;
4252 src_texture = src_surface->container;
4255 if (!fx || !(fx->fx))
4256 flags &= ~WINED3D_BLT_FX;
4258 if (flags & WINED3D_BLT_WAIT)
4259 flags &= ~WINED3D_BLT_WAIT;
4261 if (flags & WINED3D_BLT_ASYNC)
4263 static unsigned int once;
4265 if (!once++)
4266 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
4267 flags &= ~WINED3D_BLT_ASYNC;
4270 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
4271 if (flags & WINED3D_BLT_DO_NOT_WAIT)
4273 static unsigned int once;
4275 if (!once++)
4276 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
4277 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
4280 if (!device->d3d_initialized)
4282 WARN("D3D not initialized, using fallback.\n");
4283 goto cpu;
4286 /* We want to avoid invalidating the sysmem location for converted
4287 * surfaces, since otherwise we'd have to convert the data back when
4288 * locking them. */
4289 if (dst_texture->flags & WINED3D_TEXTURE_CONVERTED || dst_texture->resource.format->convert
4290 || wined3d_format_get_color_key_conversion(dst_texture, TRUE))
4292 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
4293 goto cpu;
4296 if (flags & ~simple_blit)
4298 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
4299 goto fallback;
4302 if (src_surface)
4303 src_swapchain = src_texture->swapchain;
4304 else
4305 src_swapchain = NULL;
4307 dst_swapchain = dst_texture->swapchain;
4309 /* This isn't strictly needed. FBO blits for example could deal with
4310 * cross-swapchain blits by first downloading the source to a texture
4311 * before switching to the destination context. We just have this here to
4312 * not have to deal with the issue, since cross-swapchain blits should be
4313 * rare. */
4314 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
4316 FIXME("Using fallback for cross-swapchain blit.\n");
4317 goto fallback;
4320 scale = src_surface
4321 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
4322 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
4323 convert = src_surface && src_texture->resource.format->id != dst_texture->resource.format->id;
4325 dst_ds_flags = dst_texture->resource.format_flags
4326 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4327 if (src_surface)
4328 src_ds_flags = src_texture->resource.format_flags
4329 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4330 else
4331 src_ds_flags = 0;
4333 if (src_ds_flags || dst_ds_flags)
4335 if (flags & WINED3D_BLT_DEPTH_FILL)
4337 float depth;
4339 TRACE("Depth fill.\n");
4341 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
4342 return WINED3DERR_INVALIDCALL;
4344 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
4345 return WINED3D_OK;
4347 else
4349 if (src_ds_flags != dst_ds_flags)
4351 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
4352 return WINED3DERR_INVALIDCALL;
4355 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_texture->resource.draw_binding,
4356 src_rect, dst_surface, dst_texture->resource.draw_binding, dst_rect)))
4357 return WINED3D_OK;
4360 else
4362 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
4363 const struct blit_shader *blitter;
4365 dst_sub_resource = surface_get_sub_resource(dst_surface);
4366 src_sub_resource = src_surface ? surface_get_sub_resource(src_surface) : NULL;
4368 /* In principle this would apply to depth blits as well, but we don't
4369 * implement those in the CPU blitter at the moment. */
4370 if ((dst_sub_resource->locations & dst_surface->resource.map_binding)
4371 && (!src_surface || (src_sub_resource->locations & src_surface->resource.map_binding)))
4373 if (scale)
4374 TRACE("Not doing sysmem blit because of scaling.\n");
4375 else if (convert)
4376 TRACE("Not doing sysmem blit because of format conversion.\n");
4377 else
4378 goto cpu;
4381 if (flags & WINED3D_BLT_COLOR_FILL)
4383 struct wined3d_color color;
4384 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
4386 TRACE("Color fill.\n");
4388 if (!wined3d_format_convert_color_to_float(dst_texture->resource.format,
4389 palette, fx->fill_color, &color))
4390 goto fallback;
4392 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
4393 return WINED3D_OK;
4395 else
4397 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
4398 const struct wined3d_color_key *color_key = NULL;
4400 TRACE("Color blit.\n");
4401 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
4403 color_key = &fx->src_color_key;
4404 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4406 else if (flags & WINED3D_BLT_SRC_CKEY)
4408 color_key = &src_texture->async.src_blt_color_key;
4409 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4411 else if (flags & WINED3D_BLT_ALPHA_TEST)
4413 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
4415 else if ((src_sub_resource->locations & WINED3D_LOCATION_SYSMEM)
4416 && !(dst_sub_resource->locations & WINED3D_LOCATION_SYSMEM))
4418 /* Upload */
4419 if (scale)
4420 TRACE("Not doing upload because of scaling.\n");
4421 else if (convert)
4422 TRACE("Not doing upload because of format conversion.\n");
4423 else
4425 POINT dst_point = {dst_rect->left, dst_rect->top};
4427 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
4429 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
4431 struct wined3d_context *context = context_acquire(device, dst_surface);
4432 surface_load_location(dst_surface, context, dst_texture->resource.draw_binding);
4433 context_release(context);
4435 return WINED3D_OK;
4439 else if (dst_swapchain && dst_swapchain->back_buffers
4440 && dst_texture == dst_swapchain->front_buffer
4441 && src_texture == dst_swapchain->back_buffers[0])
4443 /* Use present for back -> front blits. The idea behind this is
4444 * that present is potentially faster than a blit, in particular
4445 * when FBO blits aren't available. Some ddraw applications like
4446 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4447 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4448 * applications can't blit directly to the frontbuffer. */
4449 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
4451 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4453 /* Set the swap effect to COPY, we don't want the backbuffer
4454 * to become undefined. */
4455 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
4456 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, 0);
4457 dst_swapchain->desc.swap_effect = swap_effect;
4459 return WINED3D_OK;
4462 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
4463 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4464 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
4466 struct wined3d_context *context;
4467 TRACE("Using FBO blit.\n");
4469 context = context_acquire(device, NULL);
4470 surface_blt_fbo(device, context, filter,
4471 src_surface, src_texture->resource.draw_binding, src_rect,
4472 dst_surface, dst_texture->resource.draw_binding, dst_rect);
4473 context_release(context);
4475 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx,
4476 dst_texture->resource.draw_binding);
4477 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx,
4478 ~dst_texture->resource.draw_binding);
4480 return WINED3D_OK;
4483 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
4484 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4485 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format);
4486 if (blitter)
4488 blitter->blit_surface(device, blit_op, filter, src_surface,
4489 src_rect, dst_surface, dst_rect, color_key);
4490 return WINED3D_OK;
4495 fallback:
4496 /* Special cases for render targets. */
4497 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
4498 return WINED3D_OK;
4500 cpu:
4501 return surface_cpu_blt(dst_texture, surface_get_sub_resource_idx(dst_surface), &dst_box,
4502 src_texture, src_texture ? surface_get_sub_resource_idx(src_surface) : 0, &src_box, flags, fx, filter);
4505 HRESULT wined3d_surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
4506 const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags)
4508 unsigned int sub_resource_idx = layer * container->level_count + level;
4509 struct wined3d_device *device = container->resource.device;
4510 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4511 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format);
4512 BOOL lockable = flags & WINED3D_TEXTURE_CREATE_MAPPABLE;
4513 UINT multisample_quality = desc->multisample_quality;
4514 unsigned int resource_size;
4515 HRESULT hr;
4517 if (container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
4519 unsigned int pow2_width = 1, pow2_height = 1;
4521 /* Find the nearest pow2 match. */
4522 while (pow2_width < desc->width)
4523 pow2_width <<= 1;
4524 while (pow2_height < desc->height)
4525 pow2_height <<= 1;
4527 surface->pow2Width = pow2_width;
4528 surface->pow2Height = pow2_height;
4530 else
4532 surface->pow2Width = desc->width;
4533 surface->pow2Height = desc->height;
4536 /* Quick lockable sanity check.
4537 * TODO: remove this after surfaces, usage and lockability have been debugged properly
4538 * this function is too deep to need to care about things like this.
4539 * Levels need to be checked too, since they all affect what can be done. */
4540 switch (desc->pool)
4542 case WINED3D_POOL_MANAGED:
4543 if (desc->usage & WINED3DUSAGE_DYNAMIC)
4544 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
4545 break;
4547 case WINED3D_POOL_DEFAULT:
4548 if (lockable && !(desc->usage & (WINED3DUSAGE_DYNAMIC
4549 | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4550 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
4551 break;
4553 case WINED3D_POOL_SCRATCH:
4554 case WINED3D_POOL_SYSTEM_MEM:
4555 break;
4557 default:
4558 FIXME("Unknown pool %#x.\n", desc->pool);
4559 break;
4562 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->pool != WINED3D_POOL_DEFAULT)
4563 FIXME("Trying to create a render target that isn't in the default pool.\n");
4565 /* FIXME: Check that the format is supported by the device. */
4567 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, 1);
4568 if (!resource_size)
4569 return WINED3DERR_INVALIDCALL;
4571 if (FAILED(hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE,
4572 format, desc->multisample_type, multisample_quality, desc->usage, desc->pool, desc->width, desc->height,
4573 1, resource_size, NULL, &wined3d_null_parent_ops, &surface_resource_ops)))
4575 WARN("Failed to initialize resource, returning %#x.\n", hr);
4576 return hr;
4579 surface->container = container;
4580 surface->texture_target = target;
4581 surface->texture_level = level;
4582 surface->texture_layer = layer;
4584 list_init(&surface->renderbuffers);
4585 list_init(&surface->overlays);
4587 /* Flags */
4588 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
4589 surface->flags |= SFLAG_DISCARD;
4590 if (lockable || desc->format == WINED3DFMT_D16_LOCKABLE)
4591 surface->resource.access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
4593 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4594 if (container->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4595 container->sub_resources[sub_resource_idx].locations = WINED3D_LOCATION_DISCARDED;
4597 if (wined3d_texture_use_pbo(container, gl_info))
4598 surface->resource.map_binding = WINED3D_LOCATION_BUFFER;
4600 /* Similar to lockable rendertargets above, creating the DIB section
4601 * during surface initialization prevents the sysmem pointer from changing
4602 * after a wined3d_texture_get_dc() call. */
4603 if ((desc->usage & WINED3DUSAGE_OWNDC) || (device->wined3d->flags & WINED3D_NO3D))
4605 if (FAILED(hr = surface_create_dib_section(surface)))
4607 wined3d_surface_cleanup(surface);
4608 return hr;
4610 surface->resource.map_binding = WINED3D_LOCATION_DIB;
4613 if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
4615 wined3d_resource_free_sysmem(&surface->resource);
4616 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_DIB);
4617 wined3d_texture_invalidate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4620 return hr;
4623 /* Context activation is done by the caller. Context may be NULL in
4624 * WINED3D_NO3D mode. */
4625 void wined3d_surface_prepare(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4627 struct wined3d_texture *texture = surface->container;
4629 switch (location)
4631 case WINED3D_LOCATION_SYSMEM:
4632 surface_prepare_system_memory(surface);
4633 break;
4635 case WINED3D_LOCATION_USER_MEMORY:
4636 if (!texture->user_memory)
4637 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
4638 break;
4640 case WINED3D_LOCATION_DIB:
4641 if (!surface->dib.bitmap_data)
4642 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
4643 break;
4645 case WINED3D_LOCATION_BUFFER:
4646 wined3d_texture_prepare_buffer_object(texture,
4647 surface_get_sub_resource_idx(surface), context->gl_info);
4648 break;
4650 case WINED3D_LOCATION_TEXTURE_RGB:
4651 wined3d_texture_prepare_texture(texture, context, FALSE);
4652 break;
4654 case WINED3D_LOCATION_TEXTURE_SRGB:
4655 wined3d_texture_prepare_texture(texture, context, TRUE);
4656 break;
4658 case WINED3D_LOCATION_RB_MULTISAMPLE:
4659 surface_prepare_rb(surface, context->gl_info, TRUE);
4660 break;
4662 case WINED3D_LOCATION_RB_RESOLVED:
4663 surface_prepare_rb(surface, context->gl_info, FALSE);
4664 break;