wined3d: Use the texture dimension helpers in surface_load_fb_texture().
[wine.git] / dlls / wined3d / surface.c
blob67ec03fa87090c2ffbe30b50664c39ab3270ea3e
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, wined3d_texture_get_level_width(texture, surface->texture_level),
2003 wined3d_texture_get_level_height(texture, surface->texture_level));
2004 checkGLcall("glCopyTexSubImage2D");
2006 if (restore_rt)
2007 context_restore(context, restore_rt);
2010 static void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
2012 struct wined3d_texture *texture = surface->container;
2013 const struct wined3d_format *format = texture->resource.format;
2015 if (multisample)
2017 DWORD samples;
2019 if (surface->rb_multisample)
2020 return;
2022 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
2023 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
2024 * to GL_NV_framebuffer_multisample_coverage.
2026 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
2027 * but it does not have an equivalent OpenGL extension. */
2029 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
2030 * as the count of advertised multisample types for the surface format. */
2031 if (texture->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE)
2033 unsigned int i, count = 0;
2035 for (i = 0; i < sizeof(format->multisample_types) * 8; ++i)
2037 if (format->multisample_types & 1u << i)
2039 if (texture->resource.multisample_quality == count++)
2040 break;
2043 samples = i + 1;
2045 else
2047 samples = texture->resource.multisample_type;
2050 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
2051 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
2052 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
2053 format->glInternal, surface->pow2Width, surface->pow2Height);
2054 checkGLcall("glRenderbufferStorageMultisample()");
2055 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
2057 else
2059 if (surface->rb_resolved)
2060 return;
2062 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
2063 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
2064 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format->glInternal,
2065 surface->pow2Width, surface->pow2Height);
2066 checkGLcall("glRenderbufferStorage()");
2067 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
2071 /* Does a direct frame buffer -> texture copy. Stretching is done with single
2072 * pixel copy calls. */
2073 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2074 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2076 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2077 struct wined3d_texture *src_texture = src_surface->container;
2078 struct wined3d_texture *dst_texture = dst_surface->container;
2079 struct wined3d_device *device = dst_texture->resource.device;
2080 const struct wined3d_gl_info *gl_info;
2081 float xrel, yrel;
2082 struct wined3d_context *context;
2083 BOOL upsidedown = FALSE;
2084 RECT dst_rect = *dst_rect_in;
2086 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2087 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2089 if(dst_rect.top > dst_rect.bottom) {
2090 UINT tmp = dst_rect.bottom;
2091 dst_rect.bottom = dst_rect.top;
2092 dst_rect.top = tmp;
2093 upsidedown = TRUE;
2096 context = context_acquire(device, src_surface);
2097 gl_info = context->gl_info;
2098 context_apply_blit_state(context, device);
2099 wined3d_texture_load(dst_texture, context, FALSE);
2101 /* Bind the target texture */
2102 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
2103 if (wined3d_resource_is_offscreen(&src_texture->resource))
2105 TRACE("Reading from an offscreen target\n");
2106 upsidedown = !upsidedown;
2107 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
2109 else
2111 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2113 checkGLcall("glReadBuffer");
2115 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
2116 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
2118 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2120 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2122 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2123 ERR("Texture filtering not supported in direct blit.\n");
2125 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2126 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2128 ERR("Texture filtering not supported in direct blit\n");
2131 if (upsidedown
2132 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2133 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2135 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
2136 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2137 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
2138 src_rect->left, src_surface->resource.height - src_rect->bottom,
2139 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2141 else
2143 LONG row;
2144 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
2145 /* I have to process this row by row to swap the image,
2146 * otherwise it would be upside down, so stretching in y direction
2147 * doesn't cost extra time
2149 * However, stretching in x direction can be avoided if not necessary
2151 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
2152 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2154 /* Well, that stuff works, but it's very slow.
2155 * find a better way instead
2157 LONG col;
2159 for (col = dst_rect.left; col < dst_rect.right; ++col)
2161 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2162 dst_rect.left + col /* x offset */, row /* y offset */,
2163 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
2166 else
2168 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2169 dst_rect.left /* x offset */, row /* y offset */,
2170 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
2174 checkGLcall("glCopyTexSubImage2D");
2176 context_release(context);
2178 /* The texture is now most up to date - If the surface is a render target
2179 * and has a drawable, this path is never entered. */
2180 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2181 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2184 /* Uses the hardware to stretch and flip the image */
2185 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2186 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2188 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2189 struct wined3d_texture *src_texture = src_surface->container;
2190 struct wined3d_texture *dst_texture = dst_surface->container;
2191 struct wined3d_device *device = dst_texture->resource.device;
2192 GLuint src, backup = 0;
2193 float left, right, top, bottom; /* Texture coordinates */
2194 UINT fbwidth = src_surface->resource.width;
2195 UINT fbheight = src_surface->resource.height;
2196 const struct wined3d_gl_info *gl_info;
2197 struct wined3d_context *context;
2198 GLenum drawBuffer = GL_BACK;
2199 GLenum offscreen_buffer;
2200 GLenum texture_target;
2201 BOOL noBackBufferBackup;
2202 BOOL src_offscreen;
2203 BOOL upsidedown = FALSE;
2204 RECT dst_rect = *dst_rect_in;
2206 TRACE("Using hwstretch blit\n");
2207 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2208 context = context_acquire(device, src_surface);
2209 gl_info = context->gl_info;
2210 context_apply_blit_state(context, device);
2211 wined3d_texture_load(dst_texture, context, FALSE);
2213 offscreen_buffer = context_get_offscreen_gl_buffer(context);
2215 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
2216 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
2217 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
2219 /* Get it a description */
2220 wined3d_texture_load(src_texture, context, FALSE);
2223 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2224 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2226 if (context->aux_buffers >= 2)
2228 /* Got more than one aux buffer? Use the 2nd aux buffer */
2229 drawBuffer = GL_AUX1;
2231 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
2233 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2234 drawBuffer = GL_AUX0;
2237 if (noBackBufferBackup)
2239 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
2240 checkGLcall("glGenTextures");
2241 context_bind_texture(context, GL_TEXTURE_2D, backup);
2242 texture_target = GL_TEXTURE_2D;
2244 else
2246 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2247 * we are reading from the back buffer, the backup can be used as source texture
2249 texture_target = src_surface->texture_target;
2250 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
2251 gl_info->gl_ops.gl.p_glEnable(texture_target);
2252 checkGLcall("glEnable(texture_target)");
2254 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2255 surface_get_sub_resource(src_surface)->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
2258 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2259 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2261 if(dst_rect.top > dst_rect.bottom) {
2262 UINT tmp = dst_rect.bottom;
2263 dst_rect.bottom = dst_rect.top;
2264 dst_rect.top = tmp;
2265 upsidedown = TRUE;
2268 if (src_offscreen)
2270 TRACE("Reading from an offscreen target\n");
2271 upsidedown = !upsidedown;
2272 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
2274 else
2276 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2279 /* TODO: Only back up the part that will be overwritten */
2280 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
2282 checkGLcall("glCopyTexSubImage2D");
2284 /* No issue with overriding these - the sampler is dirty due to blit usage */
2285 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
2286 checkGLcall("glTexParameteri");
2287 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2288 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
2289 checkGLcall("glTexParameteri");
2291 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
2293 src = backup ? backup : src_texture->texture_rgb.name;
2295 else
2297 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
2298 checkGLcall("glReadBuffer(GL_FRONT)");
2300 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
2301 checkGLcall("glGenTextures(1, &src)");
2302 context_bind_texture(context, GL_TEXTURE_2D, src);
2304 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
2305 * out for power of 2 sizes
2307 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
2308 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2309 checkGLcall("glTexImage2D");
2310 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
2312 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2313 checkGLcall("glTexParameteri");
2314 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2315 checkGLcall("glTexParameteri");
2317 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
2318 checkGLcall("glReadBuffer(GL_BACK)");
2320 if (texture_target != GL_TEXTURE_2D)
2322 gl_info->gl_ops.gl.p_glDisable(texture_target);
2323 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2324 texture_target = GL_TEXTURE_2D;
2327 checkGLcall("glEnd and previous");
2329 left = src_rect->left;
2330 right = src_rect->right;
2332 if (!upsidedown)
2334 top = src_surface->resource.height - src_rect->top;
2335 bottom = src_surface->resource.height - src_rect->bottom;
2337 else
2339 top = src_surface->resource.height - src_rect->bottom;
2340 bottom = src_surface->resource.height - src_rect->top;
2343 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
2345 left /= src_surface->pow2Width;
2346 right /= src_surface->pow2Width;
2347 top /= src_surface->pow2Height;
2348 bottom /= src_surface->pow2Height;
2351 /* draw the source texture stretched and upside down. The correct surface is bound already */
2352 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2353 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2355 context_set_draw_buffer(context, drawBuffer);
2356 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
2358 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2359 /* bottom left */
2360 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
2361 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2363 /* top left */
2364 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
2365 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
2367 /* top right */
2368 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
2369 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2371 /* bottom right */
2372 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
2373 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
2374 gl_info->gl_ops.gl.p_glEnd();
2375 checkGLcall("glEnd and previous");
2377 if (texture_target != dst_surface->texture_target)
2379 gl_info->gl_ops.gl.p_glDisable(texture_target);
2380 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
2381 texture_target = dst_surface->texture_target;
2384 /* Now read the stretched and upside down image into the destination texture */
2385 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
2386 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
2388 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
2389 0, 0, /* We blitted the image to the origin */
2390 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2391 checkGLcall("glCopyTexSubImage2D");
2393 if (drawBuffer == GL_BACK)
2395 /* Write the back buffer backup back. */
2396 if (backup)
2398 if (texture_target != GL_TEXTURE_2D)
2400 gl_info->gl_ops.gl.p_glDisable(texture_target);
2401 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2402 texture_target = GL_TEXTURE_2D;
2404 context_bind_texture(context, GL_TEXTURE_2D, backup);
2406 else
2408 if (texture_target != src_surface->texture_target)
2410 gl_info->gl_ops.gl.p_glDisable(texture_target);
2411 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
2412 texture_target = src_surface->texture_target;
2414 context_bind_texture(context, src_surface->texture_target, src_texture->texture_rgb.name);
2417 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2418 /* top left */
2419 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
2420 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
2422 /* bottom left */
2423 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
2424 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2426 /* bottom right */
2427 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
2428 (float)fbheight / (float)src_surface->pow2Height);
2429 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
2431 /* top right */
2432 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
2433 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
2434 gl_info->gl_ops.gl.p_glEnd();
2436 gl_info->gl_ops.gl.p_glDisable(texture_target);
2437 checkGLcall("glDisable(texture_target)");
2439 /* Cleanup */
2440 if (src != src_texture->texture_rgb.name && src != backup)
2442 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
2443 checkGLcall("glDeleteTextures(1, &src)");
2445 if (backup)
2447 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
2448 checkGLcall("glDeleteTextures(1, &backup)");
2451 if (wined3d_settings.strict_draw_ordering)
2452 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2454 context_release(context);
2456 /* The texture is now most up to date - If the surface is a render target
2457 * and has a drawable, this path is never entered. */
2458 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2459 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2462 /* Front buffer coordinates are always full screen coordinates, but our GL
2463 * drawable is limited to the window's client area. The sysmem and texture
2464 * copies do have the full screen size. Note that GL has a bottom-left
2465 * origin, while D3D has a top-left origin. */
2466 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
2468 UINT drawable_height;
2470 if (surface->container->swapchain && surface->container == surface->container->swapchain->front_buffer)
2472 POINT offset = {0, 0};
2473 RECT windowsize;
2475 ScreenToClient(window, &offset);
2476 OffsetRect(rect, offset.x, offset.y);
2478 GetClientRect(window, &windowsize);
2479 drawable_height = windowsize.bottom - windowsize.top;
2481 else
2483 drawable_height = surface->resource.height;
2486 rect->top = drawable_height - rect->top;
2487 rect->bottom = drawable_height - rect->bottom;
2490 /* Context activation is done by the caller. */
2491 static void surface_blt_to_drawable(const struct wined3d_device *device,
2492 struct wined3d_context *old_ctx,
2493 enum wined3d_texture_filter_type filter, BOOL alpha_test,
2494 struct wined3d_surface *src_surface, const RECT *src_rect_in,
2495 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
2497 struct wined3d_texture *src_texture = src_surface->container;
2498 struct wined3d_texture *dst_texture = dst_surface->container;
2499 const struct wined3d_gl_info *gl_info;
2500 struct wined3d_context *context = old_ctx;
2501 struct wined3d_surface *restore_rt = NULL;
2502 RECT src_rect, dst_rect;
2504 src_rect = *src_rect_in;
2505 dst_rect = *dst_rect_in;
2507 restore_rt = context_get_rt_surface(old_ctx);
2508 if (restore_rt != dst_surface)
2509 context = context_acquire(device, dst_surface);
2510 else
2511 restore_rt = NULL;
2513 gl_info = context->gl_info;
2515 /* Make sure the surface is up-to-date. This should probably use
2516 * surface_load_location() and worry about the destination surface too,
2517 * unless we're overwriting it completely. */
2518 wined3d_texture_load(src_texture, context, FALSE);
2520 /* Activate the destination context, set it up for blitting */
2521 context_apply_blit_state(context, device);
2523 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
2524 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
2526 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
2528 if (alpha_test)
2530 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2531 checkGLcall("glEnable(GL_ALPHA_TEST)");
2533 /* For P8 surfaces, the alpha component contains the palette index.
2534 * Which means that the colorkey is one of the palette entries. In
2535 * other cases pixels that should be masked away have alpha set to 0. */
2536 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2537 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2538 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2539 else
2540 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2541 checkGLcall("glAlphaFunc");
2543 else
2545 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2546 checkGLcall("glDisable(GL_ALPHA_TEST)");
2549 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
2551 if (alpha_test)
2553 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2554 checkGLcall("glDisable(GL_ALPHA_TEST)");
2557 /* Leave the opengl state valid for blitting */
2558 device->blitter->unset_shader(context->gl_info);
2560 if (wined3d_settings.strict_draw_ordering
2561 || (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture))
2562 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2564 if (restore_rt)
2565 context_restore(context, restore_rt);
2568 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
2570 struct wined3d_resource *resource = &s->container->resource;
2571 struct wined3d_device *device = resource->device;
2572 struct wined3d_rendertarget_view_desc view_desc;
2573 struct wined3d_rendertarget_view *view;
2574 const struct blit_shader *blitter;
2575 HRESULT hr;
2577 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
2578 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
2580 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2581 return WINED3DERR_INVALIDCALL;
2584 view_desc.format_id = resource->format->id;
2585 view_desc.u.texture.level_idx = s->texture_level;
2586 view_desc.u.texture.layer_idx = s->texture_layer;
2587 view_desc.u.texture.layer_count = 1;
2588 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
2589 resource, NULL, &wined3d_null_parent_ops, &view)))
2591 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
2592 return hr;
2595 hr = blitter->color_fill(device, view, rect, color);
2596 wined3d_rendertarget_view_decref(view);
2598 return hr;
2601 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
2602 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
2603 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2605 struct wined3d_texture *dst_texture = dst_surface->container;
2606 struct wined3d_device *device = dst_texture->resource.device;
2607 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
2608 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
2609 struct wined3d_texture *src_texture;
2611 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2612 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2613 flags, fx, debug_d3dtexturefiltertype(filter));
2615 /* Get the swapchain. One of the surfaces has to be a primary surface */
2616 if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2618 WARN("Destination is in sysmem, rejecting gl blt\n");
2619 return WINED3DERR_INVALIDCALL;
2622 dst_swapchain = dst_texture->swapchain;
2624 if (src_surface)
2626 src_texture = src_surface->container;
2627 if (src_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2629 WARN("Src is in sysmem, rejecting gl blt\n");
2630 return WINED3DERR_INVALIDCALL;
2633 src_swapchain = src_texture->swapchain;
2635 else
2637 src_texture = NULL;
2638 src_swapchain = NULL;
2641 /* Early sort out of cases where no render target is used */
2642 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
2644 TRACE("No surface is render target, not using hardware blit.\n");
2645 return WINED3DERR_INVALIDCALL;
2648 /* No destination color keying supported */
2649 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
2651 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2652 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2653 return WINED3DERR_INVALIDCALL;
2656 if (dst_swapchain && dst_swapchain == src_swapchain)
2658 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2659 return WINED3DERR_INVALIDCALL;
2662 if (dst_swapchain && src_swapchain)
2664 FIXME("Implement hardware blit between two different swapchains\n");
2665 return WINED3DERR_INVALIDCALL;
2668 if (dst_swapchain)
2670 /* Handled with regular texture -> swapchain blit */
2671 if (src_surface == rt)
2672 TRACE("Blit from active render target to a swapchain\n");
2674 else if (src_swapchain && dst_surface == rt)
2676 FIXME("Implement blit from a swapchain to the active render target\n");
2677 return WINED3DERR_INVALIDCALL;
2680 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
2682 /* Blit from render target to texture */
2683 BOOL stretchx;
2685 /* P8 read back is not implemented */
2686 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
2687 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
2689 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2690 return WINED3DERR_INVALIDCALL;
2693 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
2695 TRACE("Color keying not supported by frame buffer to texture blit\n");
2696 return WINED3DERR_INVALIDCALL;
2697 /* Destination color key is checked above */
2700 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
2701 stretchx = TRUE;
2702 else
2703 stretchx = FALSE;
2705 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2706 * flip the image nor scale it.
2708 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2709 * -> If the app wants an image width an unscaled width, copy it line per line
2710 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2711 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2712 * back buffer. This is slower than reading line per line, thus not used for flipping
2713 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2714 * pixel by pixel. */
2715 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
2716 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
2718 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2719 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
2721 else
2723 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2724 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
2727 surface_evict_sysmem(dst_surface);
2729 return WINED3D_OK;
2732 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2733 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2734 return WINED3DERR_INVALIDCALL;
2737 /* Context activation is done by the caller. */
2738 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
2739 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
2741 struct wined3d_device *device = surface->container->resource.device;
2742 const struct wined3d_gl_info *gl_info = context->gl_info;
2743 GLint compare_mode = GL_NONE;
2744 struct blt_info info;
2745 GLint old_binding = 0;
2746 RECT rect;
2748 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
2750 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2751 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2752 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2753 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2754 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2755 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
2756 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
2757 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
2758 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2759 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
2760 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
2762 SetRect(&rect, 0, h, w, 0);
2763 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
2764 context_active_texture(context, context->gl_info, 0);
2765 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
2766 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
2767 if (gl_info->supported[ARB_SHADOW])
2769 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
2770 if (compare_mode != GL_NONE)
2771 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
2774 device->shader_backend->shader_select_depth_blt(device->shader_priv,
2775 gl_info, info.tex_type, &surface->ds_current_size);
2777 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
2778 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
2779 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
2780 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
2781 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
2782 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
2783 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
2784 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
2785 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
2786 gl_info->gl_ops.gl.p_glEnd();
2788 if (compare_mode != GL_NONE)
2789 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
2790 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
2792 gl_info->gl_ops.gl.p_glPopAttrib();
2794 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
2797 void surface_modify_ds_location(struct wined3d_surface *surface,
2798 DWORD location, UINT w, UINT h)
2800 struct wined3d_texture_sub_resource *sub_resource;
2802 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
2804 sub_resource = surface_get_sub_resource(surface);
2805 if (((sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
2806 || (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
2807 && (location & WINED3D_LOCATION_TEXTURE_RGB)))
2808 wined3d_texture_set_dirty(surface->container);
2810 surface->ds_current_size.cx = w;
2811 surface->ds_current_size.cy = h;
2812 sub_resource->locations = location;
2815 /* Context activation is done by the caller. */
2816 static void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
2818 struct wined3d_texture *texture = surface->container;
2819 struct wined3d_device *device = texture->resource.device;
2820 const struct wined3d_gl_info *gl_info = context->gl_info;
2821 GLsizei w, h;
2823 TRACE("surface %p, context %p, new location %#x.\n", surface, context, location);
2825 /* TODO: Make this work for modes other than FBO */
2826 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
2828 if (!(surface_get_sub_resource(surface)->locations & location))
2830 w = surface->ds_current_size.cx;
2831 h = surface->ds_current_size.cy;
2832 surface->ds_current_size.cx = 0;
2833 surface->ds_current_size.cy = 0;
2835 else
2837 w = surface->resource.width;
2838 h = surface->resource.height;
2841 if (surface->current_renderbuffer)
2843 FIXME("Not supported with fixed up depth stencil.\n");
2844 return;
2847 wined3d_surface_prepare(surface, context, location);
2849 if (location == WINED3D_LOCATION_TEXTURE_RGB)
2851 GLint old_binding = 0;
2852 GLenum bind_target;
2854 /* The render target is allowed to be smaller than the depth/stencil
2855 * buffer, so the onscreen depth/stencil buffer is potentially smaller
2856 * than the offscreen surface. Don't overwrite the offscreen surface
2857 * with undefined data. */
2858 w = min(w, context->swapchain->desc.backbuffer_width);
2859 h = min(h, context->swapchain->desc.backbuffer_height);
2861 TRACE("Copying onscreen depth buffer to depth texture.\n");
2863 if (!device->depth_blt_texture)
2864 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
2866 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2867 * directly on the FBO texture. That's because we need to flip. */
2868 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2869 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2870 NULL, WINED3D_LOCATION_DRAWABLE);
2871 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2873 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
2874 bind_target = GL_TEXTURE_RECTANGLE_ARB;
2876 else
2878 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
2879 bind_target = GL_TEXTURE_2D;
2881 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
2882 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
2883 * internal format, because the internal format might include stencil
2884 * data. In principle we should copy stencil data as well, but unless
2885 * the driver supports stencil export it's hard to do, and doesn't
2886 * seem to be needed in practice. If the hardware doesn't support
2887 * writing stencil data, the glCopyTexImage2D() call might trigger
2888 * software fallbacks. */
2889 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
2890 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2891 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2892 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2893 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2894 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2895 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
2897 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2898 NULL, surface, WINED3D_LOCATION_TEXTURE_RGB);
2899 context_set_draw_buffer(context, GL_NONE);
2901 /* Do the actual blit */
2902 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
2903 checkGLcall("depth_blt");
2905 context_invalidate_state(context, STATE_FRAMEBUFFER);
2907 if (wined3d_settings.strict_draw_ordering)
2908 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2910 else if (location == WINED3D_LOCATION_DRAWABLE)
2912 TRACE("Copying depth texture to onscreen depth buffer.\n");
2914 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2915 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2916 NULL, WINED3D_LOCATION_DRAWABLE);
2917 surface_depth_blt(surface, context, texture->texture_rgb.name,
2918 0, surface->pow2Height - h, w, h, surface->texture_target);
2919 checkGLcall("depth_blt");
2921 context_invalidate_state(context, STATE_FRAMEBUFFER);
2923 if (wined3d_settings.strict_draw_ordering)
2924 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2926 else
2928 ERR("Invalid location (%#x) specified.\n", location);
2932 static DWORD resource_access_from_location(DWORD location)
2934 switch (location)
2936 case WINED3D_LOCATION_SYSMEM:
2937 case WINED3D_LOCATION_USER_MEMORY:
2938 case WINED3D_LOCATION_DIB:
2939 case WINED3D_LOCATION_BUFFER:
2940 return WINED3D_RESOURCE_ACCESS_CPU;
2942 case WINED3D_LOCATION_DRAWABLE:
2943 case WINED3D_LOCATION_TEXTURE_SRGB:
2944 case WINED3D_LOCATION_TEXTURE_RGB:
2945 case WINED3D_LOCATION_RB_MULTISAMPLE:
2946 case WINED3D_LOCATION_RB_RESOLVED:
2947 return WINED3D_RESOURCE_ACCESS_GPU;
2949 default:
2950 FIXME("Unhandled location %#x.\n", location);
2951 return 0;
2955 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
2957 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2958 struct wined3d_texture *texture = surface->container;
2959 struct wined3d_device *device = texture->resource.device;
2960 struct wined3d_context *context;
2961 const struct wined3d_gl_info *gl_info;
2962 struct wined3d_bo_address dst, src;
2963 UINT size = surface->resource.size;
2965 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
2966 wined3d_texture_get_memory(texture, sub_resource_idx, &src,
2967 texture->sub_resources[sub_resource_idx].locations);
2969 if (dst.buffer_object)
2971 context = context_acquire(device, NULL);
2972 gl_info = context->gl_info;
2973 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
2974 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
2975 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2976 checkGLcall("Upload PBO");
2977 context_release(context);
2978 return;
2980 if (src.buffer_object)
2982 context = context_acquire(device, NULL);
2983 gl_info = context->gl_info;
2984 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
2985 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
2986 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2987 checkGLcall("Download PBO");
2988 context_release(context);
2989 return;
2991 memcpy(dst.addr, src.addr, size);
2994 /* Context activation is done by the caller. */
2995 static void surface_load_sysmem(struct wined3d_surface *surface,
2996 struct wined3d_context *context, DWORD dst_location)
2998 const struct wined3d_gl_info *gl_info = context->gl_info;
2999 struct wined3d_texture_sub_resource *sub_resource;
3001 wined3d_surface_prepare(surface, context, dst_location);
3003 sub_resource = surface_get_sub_resource(surface);
3004 if (sub_resource->locations & surface_simple_locations)
3006 surface_copy_simple_location(surface, dst_location);
3007 return;
3010 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
3011 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
3013 /* Download the surface to system memory. */
3014 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
3016 struct wined3d_texture *texture = surface->container;
3018 wined3d_texture_bind_and_dirtify(texture, context,
3019 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
3020 surface_download_data(surface, gl_info, dst_location);
3021 ++texture->download_count;
3023 return;
3026 if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3028 read_from_framebuffer(surface, context, dst_location);
3029 return;
3032 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
3033 surface, wined3d_debug_location(sub_resource->locations));
3036 /* Context activation is done by the caller. */
3037 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
3038 struct wined3d_context *context)
3040 struct wined3d_texture *texture = surface->container;
3041 RECT r;
3043 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3044 && wined3d_resource_is_offscreen(&texture->resource))
3046 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
3047 return WINED3DERR_INVALIDCALL;
3050 surface_get_rect(surface, NULL, &r);
3051 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
3052 surface_blt_to_drawable(texture->resource.device, context,
3053 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
3055 return WINED3D_OK;
3058 static HRESULT surface_load_texture(struct wined3d_surface *surface,
3059 struct wined3d_context *context, BOOL srgb)
3061 unsigned int width, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
3062 const RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
3063 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3064 const struct wined3d_gl_info *gl_info = context->gl_info;
3065 struct wined3d_texture *texture = surface->container;
3066 struct wined3d_device *device = texture->resource.device;
3067 const struct wined3d_color_key_conversion *conversion;
3068 struct wined3d_texture_sub_resource *sub_resource;
3069 struct wined3d_bo_address data;
3070 struct wined3d_format format;
3071 POINT dst_point = {0, 0};
3072 BYTE *mem = NULL;
3074 sub_resource = surface_get_sub_resource(surface);
3075 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
3076 && wined3d_resource_is_offscreen(&texture->resource)
3077 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
3079 surface_load_fb_texture(surface, srgb, context);
3081 return WINED3D_OK;
3084 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
3085 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
3086 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3087 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3088 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3090 if (srgb)
3091 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
3092 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
3093 else
3094 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
3095 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
3097 return WINED3D_OK;
3100 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
3101 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
3102 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3103 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3104 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3106 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
3107 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
3108 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
3109 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
3111 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
3112 &rect, surface, dst_location, &rect);
3114 return WINED3D_OK;
3117 /* Upload from system memory */
3119 if (srgb)
3121 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
3122 == WINED3D_LOCATION_TEXTURE_RGB)
3124 /* Performance warning... */
3125 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
3126 surface_load_location(surface, context, surface->resource.map_binding);
3129 else
3131 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
3132 == WINED3D_LOCATION_TEXTURE_SRGB)
3134 /* Performance warning... */
3135 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
3136 surface_load_location(surface, context, surface->resource.map_binding);
3140 if (!(sub_resource->locations & surface_simple_locations))
3142 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
3143 /* Lets hope we get it from somewhere... */
3144 surface_load_location(surface, context, WINED3D_LOCATION_SYSMEM);
3147 wined3d_texture_prepare_texture(texture, context, srgb);
3148 wined3d_texture_bind_and_dirtify(texture, context, srgb);
3149 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
3151 width = surface->resource.width;
3153 format = *texture->resource.format;
3154 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
3155 format = *wined3d_get_format(gl_info, conversion->dst_format);
3157 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
3158 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
3159 * getting called. */
3160 if ((format.convert || conversion) && texture->sub_resources[sub_resource_idx].buffer_object)
3162 TRACE("Removing the pbo attached to surface %p.\n", surface);
3164 if (surface->flags & SFLAG_DIBSECTION)
3165 surface->resource.map_binding = WINED3D_LOCATION_DIB;
3166 else
3167 surface->resource.map_binding = WINED3D_LOCATION_SYSMEM;
3169 surface_load_location(surface, context, surface->resource.map_binding);
3170 wined3d_texture_remove_buffer_object(texture, sub_resource_idx, gl_info);
3173 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
3174 if (format.convert)
3176 /* This code is entered for texture formats which need a fixup. */
3177 UINT height = surface->resource.height;
3179 format.byte_count = format.conv_byte_count;
3180 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
3182 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3184 ERR("Out of memory (%u).\n", dst_slice_pitch);
3185 context_release(context);
3186 return E_OUTOFMEMORY;
3188 format.convert(data.addr, mem, src_row_pitch, src_slice_pitch,
3189 dst_row_pitch, dst_slice_pitch, width, height, 1);
3190 src_row_pitch = dst_row_pitch;
3191 data.addr = mem;
3193 else if (conversion)
3195 /* This code is only entered for color keying fixups */
3196 struct wined3d_palette *palette = NULL;
3197 UINT height = surface->resource.height;
3199 wined3d_format_calculate_pitch(&format, device->surface_alignment,
3200 width, height, &dst_row_pitch, &dst_slice_pitch);
3202 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3204 ERR("Out of memory (%u).\n", dst_slice_pitch);
3205 context_release(context);
3206 return E_OUTOFMEMORY;
3208 if (texture->swapchain && texture->swapchain->palette)
3209 palette = texture->swapchain->palette;
3210 conversion->convert(data.addr, src_row_pitch, mem, dst_row_pitch,
3211 width, height, palette, &texture->async.gl_color_key);
3212 src_row_pitch = dst_row_pitch;
3213 data.addr = mem;
3216 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
3217 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
3219 HeapFree(GetProcessHeap(), 0, mem);
3221 return WINED3D_OK;
3224 /* Context activation is done by the caller. */
3225 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
3226 DWORD dst_location)
3228 const RECT rect = {0, 0, surface->resource.width, surface->resource.height};
3229 DWORD locations = surface_get_sub_resource(surface)->locations;
3230 DWORD src_location;
3232 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
3233 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
3234 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
3235 src_location = WINED3D_LOCATION_RB_RESOLVED;
3236 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
3237 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
3238 else /* surface_blt_fbo will load the source location if necessary. */
3239 src_location = WINED3D_LOCATION_TEXTURE_RGB;
3241 surface_blt_fbo(surface->container->resource.device, context, WINED3D_TEXF_POINT,
3242 surface, src_location, &rect, surface, dst_location, &rect);
3245 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
3246 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
3248 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3249 struct wined3d_texture *texture = surface->container;
3250 struct wined3d_texture_sub_resource *sub_resource;
3251 HRESULT hr;
3253 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
3255 sub_resource = &texture->sub_resources[sub_resource_idx];
3256 if (sub_resource->locations & location && (!(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3257 || (surface->ds_current_size.cx == surface->resource.width
3258 && surface->ds_current_size.cy == surface->resource.height)))
3260 TRACE("Location (%#x) is already up to date.\n", location);
3261 return WINED3D_OK;
3264 if (WARN_ON(d3d))
3266 DWORD required_access = resource_access_from_location(location);
3267 if ((texture->resource.access_flags & required_access) != required_access)
3268 WARN("Operation requires %#x access, but surface only has %#x.\n",
3269 required_access, texture->resource.access_flags);
3272 if (sub_resource->locations & WINED3D_LOCATION_DISCARDED)
3274 TRACE("Surface previously discarded, nothing to do.\n");
3275 wined3d_surface_prepare(surface, context, location);
3276 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3277 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3278 goto done;
3281 if (!sub_resource->locations)
3283 ERR("Surface %p does not have any up to date location.\n", surface);
3284 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3285 return surface_load_location(surface, context, location);
3288 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3290 if ((location == WINED3D_LOCATION_TEXTURE_RGB && sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3291 || (location == WINED3D_LOCATION_DRAWABLE && sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB))
3293 surface_load_ds_location(surface, context, location);
3294 goto done;
3297 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
3298 wined3d_debug_location(sub_resource->locations), wined3d_debug_location(location));
3299 return WINED3DERR_INVALIDCALL;
3302 switch (location)
3304 case WINED3D_LOCATION_DIB:
3305 case WINED3D_LOCATION_USER_MEMORY:
3306 case WINED3D_LOCATION_SYSMEM:
3307 case WINED3D_LOCATION_BUFFER:
3308 surface_load_sysmem(surface, context, location);
3309 break;
3311 case WINED3D_LOCATION_DRAWABLE:
3312 if (FAILED(hr = surface_load_drawable(surface, context)))
3313 return hr;
3314 break;
3316 case WINED3D_LOCATION_RB_RESOLVED:
3317 case WINED3D_LOCATION_RB_MULTISAMPLE:
3318 surface_load_renderbuffer(surface, context, location);
3319 break;
3321 case WINED3D_LOCATION_TEXTURE_RGB:
3322 case WINED3D_LOCATION_TEXTURE_SRGB:
3323 if (FAILED(hr = surface_load_texture(surface, context,
3324 location == WINED3D_LOCATION_TEXTURE_SRGB)))
3325 return hr;
3326 break;
3328 default:
3329 ERR("Don't know how to handle location %#x.\n", location);
3330 break;
3333 done:
3334 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3336 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3338 surface->ds_current_size.cx = surface->resource.width;
3339 surface->ds_current_size.cy = surface->resource.height;
3342 if (location != WINED3D_LOCATION_SYSMEM && (sub_resource->locations & WINED3D_LOCATION_SYSMEM))
3343 surface_evict_sysmem(surface);
3345 return WINED3D_OK;
3348 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
3349 /* Context activation is done by the caller. */
3350 static void ffp_blit_free(struct wined3d_device *device) { }
3352 /* Context activation is done by the caller. */
3353 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3354 const struct wined3d_color_key *color_key)
3356 const struct wined3d_gl_info *gl_info = context->gl_info;
3358 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
3359 checkGLcall("glEnable(target)");
3361 return WINED3D_OK;
3364 /* Context activation is done by the caller. */
3365 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
3367 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
3368 checkGLcall("glDisable(GL_TEXTURE_2D)");
3369 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
3371 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
3372 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3374 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
3376 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
3377 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
3381 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
3382 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3383 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3384 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3386 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
3388 TRACE("Source or destination is in system memory.\n");
3389 return FALSE;
3392 switch (blit_op)
3394 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3395 if (d3d_info->shader_color_key)
3397 TRACE("Color keying requires converted textures.\n");
3398 return FALSE;
3400 case WINED3D_BLIT_OP_COLOR_BLIT:
3401 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3402 if (TRACE_ON(d3d))
3404 TRACE("Checking support for fixup:\n");
3405 dump_color_fixup_desc(src_format->color_fixup);
3408 /* We only support identity conversions. */
3409 if (!is_identity_fixup(src_format->color_fixup)
3410 || !is_identity_fixup(dst_format->color_fixup))
3412 TRACE("Fixups are not supported.\n");
3413 return FALSE;
3416 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3418 TRACE("Can only blit to render targets.\n");
3419 return FALSE;
3421 return TRUE;
3423 case WINED3D_BLIT_OP_COLOR_FILL:
3424 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3426 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
3427 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
3428 return FALSE;
3430 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3432 TRACE("Color fill not supported\n");
3433 return FALSE;
3436 /* FIXME: We should reject color fills on formats with fixups,
3437 * but this would break P8 color fills for example. */
3439 return TRUE;
3441 case WINED3D_BLIT_OP_DEPTH_FILL:
3442 return TRUE;
3444 default:
3445 TRACE("Unsupported blit_op=%d\n", blit_op);
3446 return FALSE;
3450 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
3451 const RECT *rect, const struct wined3d_color *color)
3453 const RECT draw_rect = {0, 0, view->width, view->height};
3454 struct wined3d_fb_state fb = {&view, NULL};
3456 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
3458 return WINED3D_OK;
3461 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
3462 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3463 float depth, DWORD stencil)
3465 const RECT draw_rect = {0, 0, view->width, view->height};
3466 struct wined3d_fb_state fb = {NULL, view};
3468 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, clear_flags, NULL, depth, stencil);
3470 return WINED3D_OK;
3473 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3474 struct wined3d_surface *src_surface, const RECT *src_rect,
3475 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3476 const struct wined3d_color_key *color_key)
3478 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3479 struct wined3d_texture *dst_texture = dst_surface->container;
3480 struct wined3d_texture *src_texture = src_surface->container;
3481 struct wined3d_context *context;
3483 /* Blit from offscreen surface to render target */
3484 struct wined3d_color_key old_blt_key = src_texture->async.src_blt_color_key;
3485 DWORD old_color_key_flags = src_texture->async.color_key_flags;
3487 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3489 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
3491 context = context_acquire(device, dst_surface);
3493 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3494 glEnable(GL_ALPHA_TEST);
3496 surface_blt_to_drawable(device, context, filter,
3497 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
3499 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3500 glDisable(GL_ALPHA_TEST);
3502 context_release(context);
3504 /* Restore the color key parameters */
3505 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
3506 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
3508 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_texture->resource.draw_binding);
3509 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_texture->resource.draw_binding);
3512 const struct blit_shader ffp_blit = {
3513 ffp_blit_alloc,
3514 ffp_blit_free,
3515 ffp_blit_set,
3516 ffp_blit_unset,
3517 ffp_blit_supported,
3518 ffp_blit_color_fill,
3519 ffp_blit_depth_fill,
3520 ffp_blit_blit_surface,
3523 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
3525 return WINED3D_OK;
3528 /* Context activation is done by the caller. */
3529 static void cpu_blit_free(struct wined3d_device *device)
3533 /* Context activation is done by the caller. */
3534 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3535 const struct wined3d_color_key *color_key)
3537 return WINED3D_OK;
3540 /* Context activation is done by the caller. */
3541 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
3545 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
3546 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3547 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3548 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3550 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
3552 return TRUE;
3555 return FALSE;
3558 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
3559 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
3560 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
3562 UINT row_block_count;
3563 const BYTE *src_row;
3564 BYTE *dst_row;
3565 UINT x, y;
3567 src_row = src_data;
3568 dst_row = dst_data;
3570 row_block_count = (update_w + format->block_width - 1) / format->block_width;
3572 if (!flags)
3574 for (y = 0; y < update_h; y += format->block_height)
3576 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
3577 src_row += src_pitch;
3578 dst_row += dst_pitch;
3581 return WINED3D_OK;
3584 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
3586 src_row += (((update_h / format->block_height) - 1) * src_pitch);
3588 switch (format->id)
3590 case WINED3DFMT_DXT1:
3591 for (y = 0; y < update_h; y += format->block_height)
3593 struct block
3595 WORD color[2];
3596 BYTE control_row[4];
3599 const struct block *s = (const struct block *)src_row;
3600 struct block *d = (struct block *)dst_row;
3602 for (x = 0; x < row_block_count; ++x)
3604 d[x].color[0] = s[x].color[0];
3605 d[x].color[1] = s[x].color[1];
3606 d[x].control_row[0] = s[x].control_row[3];
3607 d[x].control_row[1] = s[x].control_row[2];
3608 d[x].control_row[2] = s[x].control_row[1];
3609 d[x].control_row[3] = s[x].control_row[0];
3611 src_row -= src_pitch;
3612 dst_row += dst_pitch;
3614 return WINED3D_OK;
3616 case WINED3DFMT_DXT2:
3617 case WINED3DFMT_DXT3:
3618 for (y = 0; y < update_h; y += format->block_height)
3620 struct block
3622 WORD alpha_row[4];
3623 WORD color[2];
3624 BYTE control_row[4];
3627 const struct block *s = (const struct block *)src_row;
3628 struct block *d = (struct block *)dst_row;
3630 for (x = 0; x < row_block_count; ++x)
3632 d[x].alpha_row[0] = s[x].alpha_row[3];
3633 d[x].alpha_row[1] = s[x].alpha_row[2];
3634 d[x].alpha_row[2] = s[x].alpha_row[1];
3635 d[x].alpha_row[3] = s[x].alpha_row[0];
3636 d[x].color[0] = s[x].color[0];
3637 d[x].color[1] = s[x].color[1];
3638 d[x].control_row[0] = s[x].control_row[3];
3639 d[x].control_row[1] = s[x].control_row[2];
3640 d[x].control_row[2] = s[x].control_row[1];
3641 d[x].control_row[3] = s[x].control_row[0];
3643 src_row -= src_pitch;
3644 dst_row += dst_pitch;
3646 return WINED3D_OK;
3648 default:
3649 FIXME("Compressed flip not implemented for format %s.\n",
3650 debug_d3dformat(format->id));
3651 return E_NOTIMPL;
3655 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3656 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
3658 return E_NOTIMPL;
3661 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3662 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3663 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3664 enum wined3d_texture_filter_type filter)
3666 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
3667 const struct wined3d_format *src_format, *dst_format;
3668 struct wined3d_texture *converted_texture = NULL;
3669 unsigned int src_fmt_flags, dst_fmt_flags;
3670 struct wined3d_map_desc dst_map, src_map;
3671 const BYTE *sbase = NULL;
3672 HRESULT hr = WINED3D_OK;
3673 BOOL same_sub_resource;
3674 const BYTE *sbuf;
3675 BYTE *dbuf;
3676 int x, y;
3678 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3679 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3680 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
3681 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3683 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
3685 same_sub_resource = TRUE;
3686 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, NULL, 0);
3687 src_map = dst_map;
3688 src_format = dst_texture->resource.format;
3689 dst_format = src_format;
3690 dst_fmt_flags = dst_texture->resource.format_flags;
3691 src_fmt_flags = dst_fmt_flags;
3693 else
3695 same_sub_resource = FALSE;
3696 dst_format = dst_texture->resource.format;
3697 dst_fmt_flags = dst_texture->resource.format_flags;
3698 if (src_texture)
3700 if (dst_texture->resource.format->id != src_texture->resource.format->id)
3702 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
3704 /* The conv function writes a FIXME */
3705 WARN("Cannot convert source surface format to dest format.\n");
3706 goto release;
3708 src_texture = converted_texture;
3709 src_sub_resource_idx = 0;
3711 wined3d_resource_map(&src_texture->resource, src_sub_resource_idx, &src_map, NULL, WINED3D_MAP_READONLY);
3712 src_format = src_texture->resource.format;
3713 src_fmt_flags = src_texture->resource.format_flags;
3715 else
3717 src_format = dst_format;
3718 src_fmt_flags = dst_fmt_flags;
3721 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, dst_box, 0);
3724 bpp = dst_format->byte_count;
3725 src_height = src_box->bottom - src_box->top;
3726 src_width = src_box->right - src_box->left;
3727 dst_height = dst_box->bottom - dst_box->top;
3728 dst_width = dst_box->right - dst_box->left;
3729 row_byte_count = dst_width * bpp;
3731 if (src_texture)
3732 sbase = (BYTE *)src_map.data
3733 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
3734 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
3735 if (same_sub_resource)
3736 dbuf = (BYTE *)dst_map.data
3737 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
3738 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
3739 else
3740 dbuf = dst_map.data;
3742 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
3744 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
3746 if (same_sub_resource)
3748 FIXME("Only plain blits supported on compressed surfaces.\n");
3749 hr = E_NOTIMPL;
3750 goto release;
3753 if (src_height != dst_height || src_width != dst_width)
3755 WARN("Stretching not supported on compressed surfaces.\n");
3756 hr = WINED3DERR_INVALIDCALL;
3757 goto release;
3760 if (!wined3d_texture_check_block_align(src_texture,
3761 src_sub_resource_idx % src_texture->level_count, src_box))
3763 WARN("Source rectangle not block-aligned.\n");
3764 hr = WINED3DERR_INVALIDCALL;
3765 goto release;
3768 if (!wined3d_texture_check_block_align(dst_texture,
3769 dst_sub_resource_idx % dst_texture->level_count, dst_box))
3771 WARN("Destination rectangle not block-aligned.\n");
3772 hr = WINED3DERR_INVALIDCALL;
3773 goto release;
3776 hr = surface_cpu_blt_compressed(sbase, dbuf,
3777 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
3778 src_format, flags, fx);
3779 goto release;
3782 /* First, all the 'source-less' blits */
3783 if (flags & WINED3D_BLT_COLOR_FILL)
3785 hr = _Blt_ColorFill(dbuf, dst_width, dst_height, bpp, dst_map.row_pitch, fx->fill_color);
3786 flags &= ~WINED3D_BLT_COLOR_FILL;
3789 if (flags & WINED3D_BLT_DEPTH_FILL)
3790 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3792 /* Now the 'with source' blits. */
3793 if (src_texture)
3795 int sx, xinc, sy, yinc;
3797 if (!dst_width || !dst_height) /* Hmm... stupid program? */
3798 goto release;
3800 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3801 && (src_width != dst_width || src_height != dst_height))
3803 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3804 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
3807 xinc = (src_width << 16) / dst_width;
3808 yinc = (src_height << 16) / dst_height;
3810 if (!flags)
3812 /* No effects, we can cheat here. */
3813 if (dst_width == src_width)
3815 if (dst_height == src_height)
3817 /* No stretching in either direction. This needs to be as
3818 * fast as possible. */
3819 sbuf = sbase;
3821 /* Check for overlapping surfaces. */
3822 if (!same_sub_resource || dst_box->top < src_box->top
3823 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
3825 /* No overlap, or dst above src, so copy from top downwards. */
3826 for (y = 0; y < dst_height; ++y)
3828 memcpy(dbuf, sbuf, row_byte_count);
3829 sbuf += src_map.row_pitch;
3830 dbuf += dst_map.row_pitch;
3833 else if (dst_box->top > src_box->top)
3835 /* Copy from bottom upwards. */
3836 sbuf += src_map.row_pitch * dst_height;
3837 dbuf += dst_map.row_pitch * dst_height;
3838 for (y = 0; y < dst_height; ++y)
3840 sbuf -= src_map.row_pitch;
3841 dbuf -= dst_map.row_pitch;
3842 memcpy(dbuf, sbuf, row_byte_count);
3845 else
3847 /* Src and dst overlapping on the same line, use memmove. */
3848 for (y = 0; y < dst_height; ++y)
3850 memmove(dbuf, sbuf, row_byte_count);
3851 sbuf += src_map.row_pitch;
3852 dbuf += dst_map.row_pitch;
3856 else
3858 /* Stretching in y direction only. */
3859 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3861 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3862 memcpy(dbuf, sbuf, row_byte_count);
3863 dbuf += dst_map.row_pitch;
3867 else
3869 /* Stretching in X direction. */
3870 int last_sy = -1;
3871 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3873 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3875 if ((sy >> 16) == (last_sy >> 16))
3877 /* This source row is the same as last source row -
3878 * Copy the already stretched row. */
3879 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
3881 else
3883 #define STRETCH_ROW(type) \
3884 do { \
3885 const type *s = (const type *)sbuf; \
3886 type *d = (type *)dbuf; \
3887 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3888 d[x] = s[sx >> 16]; \
3889 } while(0)
3891 switch(bpp)
3893 case 1:
3894 STRETCH_ROW(BYTE);
3895 break;
3896 case 2:
3897 STRETCH_ROW(WORD);
3898 break;
3899 case 4:
3900 STRETCH_ROW(DWORD);
3901 break;
3902 case 3:
3904 const BYTE *s;
3905 BYTE *d = dbuf;
3906 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3908 DWORD pixel;
3910 s = sbuf + 3 * (sx >> 16);
3911 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3912 d[0] = (pixel ) & 0xff;
3913 d[1] = (pixel >> 8) & 0xff;
3914 d[2] = (pixel >> 16) & 0xff;
3915 d += 3;
3917 break;
3919 default:
3920 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
3921 hr = WINED3DERR_NOTAVAILABLE;
3922 goto error;
3924 #undef STRETCH_ROW
3926 dbuf += dst_map.row_pitch;
3927 last_sy = sy;
3931 else
3933 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3934 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3935 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3936 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3937 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3939 /* The color keying flags are checked for correctness in ddraw */
3940 if (flags & WINED3D_BLT_SRC_CKEY)
3942 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
3943 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3945 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3947 keylow = fx->src_color_key.color_space_low_value;
3948 keyhigh = fx->src_color_key.color_space_high_value;
3951 if (flags & WINED3D_BLT_DST_CKEY)
3953 /* Destination color keys are taken from the source surface! */
3954 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3955 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3957 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3959 destkeylow = fx->dst_color_key.color_space_low_value;
3960 destkeyhigh = fx->dst_color_key.color_space_high_value;
3963 if (bpp == 1)
3965 keymask = 0xff;
3967 else
3969 DWORD masks[3];
3970 get_color_masks(src_format, masks);
3971 keymask = masks[0]
3972 | masks[1]
3973 | masks[2];
3975 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3976 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3979 if (flags & WINED3D_BLT_FX)
3981 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3982 LONG tmpxy;
3983 dTopLeft = dbuf;
3984 dTopRight = dbuf + ((dst_width - 1) * bpp);
3985 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3986 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3988 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3990 /* I don't think we need to do anything about this flag */
3991 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3993 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3995 tmp = dTopRight;
3996 dTopRight = dTopLeft;
3997 dTopLeft = tmp;
3998 tmp = dBottomRight;
3999 dBottomRight = dBottomLeft;
4000 dBottomLeft = tmp;
4001 dstxinc = dstxinc * -1;
4003 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
4005 tmp = dTopLeft;
4006 dTopLeft = dBottomLeft;
4007 dBottomLeft = tmp;
4008 tmp = dTopRight;
4009 dTopRight = dBottomRight;
4010 dBottomRight = tmp;
4011 dstyinc = dstyinc * -1;
4013 if (fx->fx & WINEDDBLTFX_NOTEARING)
4015 /* I don't think we need to do anything about this flag */
4016 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
4018 if (fx->fx & WINEDDBLTFX_ROTATE180)
4020 tmp = dBottomRight;
4021 dBottomRight = dTopLeft;
4022 dTopLeft = tmp;
4023 tmp = dBottomLeft;
4024 dBottomLeft = dTopRight;
4025 dTopRight = tmp;
4026 dstxinc = dstxinc * -1;
4027 dstyinc = dstyinc * -1;
4029 if (fx->fx & WINEDDBLTFX_ROTATE270)
4031 tmp = dTopLeft;
4032 dTopLeft = dBottomLeft;
4033 dBottomLeft = dBottomRight;
4034 dBottomRight = dTopRight;
4035 dTopRight = tmp;
4036 tmpxy = dstxinc;
4037 dstxinc = dstyinc;
4038 dstyinc = tmpxy;
4039 dstxinc = dstxinc * -1;
4041 if (fx->fx & WINEDDBLTFX_ROTATE90)
4043 tmp = dTopLeft;
4044 dTopLeft = dTopRight;
4045 dTopRight = dBottomRight;
4046 dBottomRight = dBottomLeft;
4047 dBottomLeft = tmp;
4048 tmpxy = dstxinc;
4049 dstxinc = dstyinc;
4050 dstyinc = tmpxy;
4051 dstyinc = dstyinc * -1;
4053 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
4055 /* I don't think we need to do anything about this flag */
4056 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
4058 dbuf = dTopLeft;
4059 flags &= ~(WINED3D_BLT_FX);
4062 #define COPY_COLORKEY_FX(type) \
4063 do { \
4064 const type *s; \
4065 type *d = (type *)dbuf, *dx, tmp; \
4066 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
4068 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
4069 dx = d; \
4070 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
4072 tmp = s[sx >> 16]; \
4073 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
4074 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
4076 dx[0] = tmp; \
4078 dx = (type *)(((BYTE *)dx) + dstxinc); \
4080 d = (type *)(((BYTE *)d) + dstyinc); \
4082 } while(0)
4084 switch (bpp)
4086 case 1:
4087 COPY_COLORKEY_FX(BYTE);
4088 break;
4089 case 2:
4090 COPY_COLORKEY_FX(WORD);
4091 break;
4092 case 4:
4093 COPY_COLORKEY_FX(DWORD);
4094 break;
4095 case 3:
4097 const BYTE *s;
4098 BYTE *d = dbuf, *dx;
4099 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
4101 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
4102 dx = d;
4103 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
4105 DWORD pixel, dpixel = 0;
4106 s = sbuf + 3 * (sx>>16);
4107 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
4108 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
4109 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
4110 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
4112 dx[0] = (pixel ) & 0xff;
4113 dx[1] = (pixel >> 8) & 0xff;
4114 dx[2] = (pixel >> 16) & 0xff;
4116 dx += dstxinc;
4118 d += dstyinc;
4120 break;
4122 default:
4123 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
4124 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
4125 hr = WINED3DERR_NOTAVAILABLE;
4126 goto error;
4127 #undef COPY_COLORKEY_FX
4132 error:
4133 if (flags)
4134 FIXME(" Unsupported flags %#x.\n", flags);
4136 release:
4137 wined3d_resource_unmap(&dst_texture->resource, dst_sub_resource_idx);
4138 if (src_texture && !same_sub_resource)
4139 wined3d_resource_unmap(&src_texture->resource, src_sub_resource_idx);
4140 if (converted_texture)
4141 wined3d_texture_decref(converted_texture);
4143 return hr;
4146 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
4147 const RECT *rect, const struct wined3d_color *color)
4149 const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
4150 static const struct wined3d_box src_box;
4151 struct wined3d_blt_fx fx;
4153 fx.fill_color = wined3d_format_convert_from_float(view->format, color);
4154 return surface_cpu_blt(wined3d_texture_from_resource(view->resource), view->sub_resource_idx,
4155 &box, NULL, 0, &src_box, WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
4158 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
4159 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
4160 float depth, DWORD stencil)
4162 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
4163 return WINED3DERR_INVALIDCALL;
4166 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
4167 struct wined3d_surface *src_surface, const RECT *src_rect,
4168 struct wined3d_surface *dst_surface, const RECT *dst_rect,
4169 const struct wined3d_color_key *color_key)
4171 /* FIXME: Remove error returns from surface_blt_cpu. */
4172 ERR("Blit method not implemented by cpu_blit.\n");
4175 const struct blit_shader cpu_blit = {
4176 cpu_blit_alloc,
4177 cpu_blit_free,
4178 cpu_blit_set,
4179 cpu_blit_unset,
4180 cpu_blit_supported,
4181 cpu_blit_color_fill,
4182 cpu_blit_depth_fill,
4183 cpu_blit_blit_surface,
4186 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
4187 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
4188 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
4190 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
4191 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
4192 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
4193 struct wined3d_texture *dst_texture = dst_surface->container;
4194 struct wined3d_device *device = dst_texture->resource.device;
4195 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
4196 struct wined3d_texture *src_texture = NULL;
4197 DWORD src_ds_flags, dst_ds_flags;
4198 BOOL scale, convert;
4200 static const DWORD simple_blit = WINED3D_BLT_ASYNC
4201 | WINED3D_BLT_COLOR_FILL
4202 | WINED3D_BLT_SRC_CKEY
4203 | WINED3D_BLT_SRC_CKEY_OVERRIDE
4204 | WINED3D_BLT_WAIT
4205 | WINED3D_BLT_DEPTH_FILL
4206 | WINED3D_BLT_DO_NOT_WAIT
4207 | WINED3D_BLT_ALPHA_TEST;
4209 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4210 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
4211 flags, fx, debug_d3dtexturefiltertype(filter));
4212 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
4214 if (fx)
4216 TRACE("fx %#x.\n", fx->fx);
4217 TRACE("fill_color 0x%08x.\n", fx->fill_color);
4218 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
4219 fx->dst_color_key.color_space_low_value,
4220 fx->dst_color_key.color_space_high_value);
4221 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
4222 fx->src_color_key.color_space_low_value,
4223 fx->src_color_key.color_space_high_value);
4226 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
4228 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
4229 return WINEDDERR_SURFACEBUSY;
4232 if (dst_rect->left >= dst_rect->right || dst_rect->top >= dst_rect->bottom
4233 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
4234 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
4235 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
4236 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0)
4238 WARN("The application gave us a bad destination rectangle.\n");
4239 return WINEDDERR_INVALIDRECT;
4242 if (src_surface)
4244 if (src_rect->left >= src_rect->right || src_rect->top >= src_rect->bottom
4245 || src_rect->left > src_surface->resource.width || src_rect->left < 0
4246 || src_rect->top > src_surface->resource.height || src_rect->top < 0
4247 || src_rect->right > src_surface->resource.width || src_rect->right < 0
4248 || src_rect->bottom > src_surface->resource.height || src_rect->bottom < 0)
4250 WARN("The application gave us a bad source rectangle.\n");
4251 return WINEDDERR_INVALIDRECT;
4253 src_texture = src_surface->container;
4256 if (!fx || !(fx->fx))
4257 flags &= ~WINED3D_BLT_FX;
4259 if (flags & WINED3D_BLT_WAIT)
4260 flags &= ~WINED3D_BLT_WAIT;
4262 if (flags & WINED3D_BLT_ASYNC)
4264 static unsigned int once;
4266 if (!once++)
4267 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
4268 flags &= ~WINED3D_BLT_ASYNC;
4271 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
4272 if (flags & WINED3D_BLT_DO_NOT_WAIT)
4274 static unsigned int once;
4276 if (!once++)
4277 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
4278 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
4281 if (!device->d3d_initialized)
4283 WARN("D3D not initialized, using fallback.\n");
4284 goto cpu;
4287 /* We want to avoid invalidating the sysmem location for converted
4288 * surfaces, since otherwise we'd have to convert the data back when
4289 * locking them. */
4290 if (dst_texture->flags & WINED3D_TEXTURE_CONVERTED || dst_texture->resource.format->convert
4291 || wined3d_format_get_color_key_conversion(dst_texture, TRUE))
4293 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
4294 goto cpu;
4297 if (flags & ~simple_blit)
4299 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
4300 goto fallback;
4303 if (src_surface)
4304 src_swapchain = src_texture->swapchain;
4305 else
4306 src_swapchain = NULL;
4308 dst_swapchain = dst_texture->swapchain;
4310 /* This isn't strictly needed. FBO blits for example could deal with
4311 * cross-swapchain blits by first downloading the source to a texture
4312 * before switching to the destination context. We just have this here to
4313 * not have to deal with the issue, since cross-swapchain blits should be
4314 * rare. */
4315 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
4317 FIXME("Using fallback for cross-swapchain blit.\n");
4318 goto fallback;
4321 scale = src_surface
4322 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
4323 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
4324 convert = src_surface && src_texture->resource.format->id != dst_texture->resource.format->id;
4326 dst_ds_flags = dst_texture->resource.format_flags
4327 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4328 if (src_surface)
4329 src_ds_flags = src_texture->resource.format_flags
4330 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4331 else
4332 src_ds_flags = 0;
4334 if (src_ds_flags || dst_ds_flags)
4336 if (flags & WINED3D_BLT_DEPTH_FILL)
4338 float depth;
4340 TRACE("Depth fill.\n");
4342 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
4343 return WINED3DERR_INVALIDCALL;
4345 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
4346 return WINED3D_OK;
4348 else
4350 if (src_ds_flags != dst_ds_flags)
4352 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
4353 return WINED3DERR_INVALIDCALL;
4356 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_texture->resource.draw_binding,
4357 src_rect, dst_surface, dst_texture->resource.draw_binding, dst_rect)))
4358 return WINED3D_OK;
4361 else
4363 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
4364 const struct blit_shader *blitter;
4366 dst_sub_resource = surface_get_sub_resource(dst_surface);
4367 src_sub_resource = src_surface ? surface_get_sub_resource(src_surface) : NULL;
4369 /* In principle this would apply to depth blits as well, but we don't
4370 * implement those in the CPU blitter at the moment. */
4371 if ((dst_sub_resource->locations & dst_surface->resource.map_binding)
4372 && (!src_surface || (src_sub_resource->locations & src_surface->resource.map_binding)))
4374 if (scale)
4375 TRACE("Not doing sysmem blit because of scaling.\n");
4376 else if (convert)
4377 TRACE("Not doing sysmem blit because of format conversion.\n");
4378 else
4379 goto cpu;
4382 if (flags & WINED3D_BLT_COLOR_FILL)
4384 struct wined3d_color color;
4385 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
4387 TRACE("Color fill.\n");
4389 if (!wined3d_format_convert_color_to_float(dst_texture->resource.format,
4390 palette, fx->fill_color, &color))
4391 goto fallback;
4393 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
4394 return WINED3D_OK;
4396 else
4398 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
4399 const struct wined3d_color_key *color_key = NULL;
4401 TRACE("Color blit.\n");
4402 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
4404 color_key = &fx->src_color_key;
4405 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4407 else if (flags & WINED3D_BLT_SRC_CKEY)
4409 color_key = &src_texture->async.src_blt_color_key;
4410 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4412 else if (flags & WINED3D_BLT_ALPHA_TEST)
4414 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
4416 else if ((src_sub_resource->locations & WINED3D_LOCATION_SYSMEM)
4417 && !(dst_sub_resource->locations & WINED3D_LOCATION_SYSMEM))
4419 /* Upload */
4420 if (scale)
4421 TRACE("Not doing upload because of scaling.\n");
4422 else if (convert)
4423 TRACE("Not doing upload because of format conversion.\n");
4424 else
4426 POINT dst_point = {dst_rect->left, dst_rect->top};
4428 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
4430 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
4432 struct wined3d_context *context = context_acquire(device, dst_surface);
4433 surface_load_location(dst_surface, context, dst_texture->resource.draw_binding);
4434 context_release(context);
4436 return WINED3D_OK;
4440 else if (dst_swapchain && dst_swapchain->back_buffers
4441 && dst_texture == dst_swapchain->front_buffer
4442 && src_texture == dst_swapchain->back_buffers[0])
4444 /* Use present for back -> front blits. The idea behind this is
4445 * that present is potentially faster than a blit, in particular
4446 * when FBO blits aren't available. Some ddraw applications like
4447 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4448 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4449 * applications can't blit directly to the frontbuffer. */
4450 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
4452 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4454 /* Set the swap effect to COPY, we don't want the backbuffer
4455 * to become undefined. */
4456 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
4457 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, 0);
4458 dst_swapchain->desc.swap_effect = swap_effect;
4460 return WINED3D_OK;
4463 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
4464 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4465 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
4467 struct wined3d_context *context;
4468 TRACE("Using FBO blit.\n");
4470 context = context_acquire(device, NULL);
4471 surface_blt_fbo(device, context, filter,
4472 src_surface, src_texture->resource.draw_binding, src_rect,
4473 dst_surface, dst_texture->resource.draw_binding, dst_rect);
4474 context_release(context);
4476 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx,
4477 dst_texture->resource.draw_binding);
4478 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx,
4479 ~dst_texture->resource.draw_binding);
4481 return WINED3D_OK;
4484 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
4485 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4486 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format);
4487 if (blitter)
4489 blitter->blit_surface(device, blit_op, filter, src_surface,
4490 src_rect, dst_surface, dst_rect, color_key);
4491 return WINED3D_OK;
4496 fallback:
4497 /* Special cases for render targets. */
4498 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
4499 return WINED3D_OK;
4501 cpu:
4502 return surface_cpu_blt(dst_texture, surface_get_sub_resource_idx(dst_surface), &dst_box,
4503 src_texture, src_texture ? surface_get_sub_resource_idx(src_surface) : 0, &src_box, flags, fx, filter);
4506 HRESULT wined3d_surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
4507 const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags)
4509 unsigned int sub_resource_idx = layer * container->level_count + level;
4510 struct wined3d_device *device = container->resource.device;
4511 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4512 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format);
4513 BOOL lockable = flags & WINED3D_TEXTURE_CREATE_MAPPABLE;
4514 UINT multisample_quality = desc->multisample_quality;
4515 unsigned int resource_size;
4516 HRESULT hr;
4518 if (container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
4520 unsigned int pow2_width = 1, pow2_height = 1;
4522 /* Find the nearest pow2 match. */
4523 while (pow2_width < desc->width)
4524 pow2_width <<= 1;
4525 while (pow2_height < desc->height)
4526 pow2_height <<= 1;
4528 surface->pow2Width = pow2_width;
4529 surface->pow2Height = pow2_height;
4531 else
4533 surface->pow2Width = desc->width;
4534 surface->pow2Height = desc->height;
4537 /* Quick lockable sanity check.
4538 * TODO: remove this after surfaces, usage and lockability have been debugged properly
4539 * this function is too deep to need to care about things like this.
4540 * Levels need to be checked too, since they all affect what can be done. */
4541 switch (desc->pool)
4543 case WINED3D_POOL_MANAGED:
4544 if (desc->usage & WINED3DUSAGE_DYNAMIC)
4545 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
4546 break;
4548 case WINED3D_POOL_DEFAULT:
4549 if (lockable && !(desc->usage & (WINED3DUSAGE_DYNAMIC
4550 | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4551 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
4552 break;
4554 case WINED3D_POOL_SCRATCH:
4555 case WINED3D_POOL_SYSTEM_MEM:
4556 break;
4558 default:
4559 FIXME("Unknown pool %#x.\n", desc->pool);
4560 break;
4563 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->pool != WINED3D_POOL_DEFAULT)
4564 FIXME("Trying to create a render target that isn't in the default pool.\n");
4566 /* FIXME: Check that the format is supported by the device. */
4568 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, 1);
4569 if (!resource_size)
4570 return WINED3DERR_INVALIDCALL;
4572 if (FAILED(hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE,
4573 format, desc->multisample_type, multisample_quality, desc->usage, desc->pool, desc->width, desc->height,
4574 1, resource_size, NULL, &wined3d_null_parent_ops, &surface_resource_ops)))
4576 WARN("Failed to initialize resource, returning %#x.\n", hr);
4577 return hr;
4580 surface->container = container;
4581 surface->texture_target = target;
4582 surface->texture_level = level;
4583 surface->texture_layer = layer;
4585 list_init(&surface->renderbuffers);
4586 list_init(&surface->overlays);
4588 /* Flags */
4589 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
4590 surface->flags |= SFLAG_DISCARD;
4591 if (lockable || desc->format == WINED3DFMT_D16_LOCKABLE)
4592 surface->resource.access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
4594 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4595 if (container->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4596 container->sub_resources[sub_resource_idx].locations = WINED3D_LOCATION_DISCARDED;
4598 if (wined3d_texture_use_pbo(container, gl_info))
4599 surface->resource.map_binding = WINED3D_LOCATION_BUFFER;
4601 /* Similar to lockable rendertargets above, creating the DIB section
4602 * during surface initialization prevents the sysmem pointer from changing
4603 * after a wined3d_texture_get_dc() call. */
4604 if ((desc->usage & WINED3DUSAGE_OWNDC) || (device->wined3d->flags & WINED3D_NO3D))
4606 if (FAILED(hr = surface_create_dib_section(surface)))
4608 wined3d_surface_cleanup(surface);
4609 return hr;
4611 surface->resource.map_binding = WINED3D_LOCATION_DIB;
4614 if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
4616 wined3d_resource_free_sysmem(&surface->resource);
4617 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_DIB);
4618 wined3d_texture_invalidate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4621 return hr;
4624 /* Context activation is done by the caller. Context may be NULL in
4625 * WINED3D_NO3D mode. */
4626 void wined3d_surface_prepare(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4628 struct wined3d_texture *texture = surface->container;
4630 switch (location)
4632 case WINED3D_LOCATION_SYSMEM:
4633 surface_prepare_system_memory(surface);
4634 break;
4636 case WINED3D_LOCATION_USER_MEMORY:
4637 if (!texture->user_memory)
4638 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
4639 break;
4641 case WINED3D_LOCATION_DIB:
4642 if (!surface->dib.bitmap_data)
4643 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
4644 break;
4646 case WINED3D_LOCATION_BUFFER:
4647 wined3d_texture_prepare_buffer_object(texture,
4648 surface_get_sub_resource_idx(surface), context->gl_info);
4649 break;
4651 case WINED3D_LOCATION_TEXTURE_RGB:
4652 wined3d_texture_prepare_texture(texture, context, FALSE);
4653 break;
4655 case WINED3D_LOCATION_TEXTURE_SRGB:
4656 wined3d_texture_prepare_texture(texture, context, TRUE);
4657 break;
4659 case WINED3D_LOCATION_RB_MULTISAMPLE:
4660 surface_prepare_rb(surface, context->gl_info, TRUE);
4661 break;
4663 case WINED3D_LOCATION_RB_RESOLVED:
4664 surface_prepare_rb(surface, context->gl_info, FALSE);
4665 break;