wined3d: Store sub-resource map counts in the sub-resource structure.
[wine.git] / dlls / wined3d / surface.c
blobbbf05db9dddc65f269db9118dce0179669580130
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 (texture->sub_resources[sub_resource_idx].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 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
1128 struct wined3d_texture *texture = surface->container;
1129 UINT update_w = src_rect->right - src_rect->left;
1130 UINT update_h = src_rect->bottom - src_rect->top;
1132 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1133 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
1134 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
1136 if (texture->sub_resources[sub_resource_idx].map_count)
1138 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1139 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
1142 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
1144 update_h *= format->height_scale.numerator;
1145 update_h /= format->height_scale.denominator;
1148 if (data->buffer_object)
1150 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, data->buffer_object));
1151 checkGLcall("glBindBuffer");
1154 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1156 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1, 1);
1157 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
1158 const BYTE *addr = data->addr;
1159 GLenum internal;
1161 addr += (src_rect->top / format->block_height) * src_pitch;
1162 addr += (src_rect->left / format->block_width) * format->block_byte_count;
1164 if (srgb)
1165 internal = format->glGammaInternal;
1166 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET
1167 && wined3d_resource_is_offscreen(&texture->resource))
1168 internal = format->rtInternal;
1169 else
1170 internal = format->glInternal;
1172 TRACE("glCompressedTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, "
1173 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
1174 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
1176 if (row_length == src_pitch)
1178 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1179 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
1181 else
1183 UINT row, y;
1185 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1186 * can't use the unpack row length like for glTexSubImage2D. */
1187 for (row = 0, y = dst_point->y; row < row_count; ++row)
1189 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1190 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
1191 y += format->block_height;
1192 addr += src_pitch;
1195 checkGLcall("glCompressedTexSubImage2D");
1197 else
1199 const BYTE *addr = data->addr;
1201 addr += src_rect->top * src_pitch;
1202 addr += src_rect->left * format->byte_count;
1204 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1205 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
1206 update_w, update_h, format->glFormat, format->glType, addr);
1208 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
1209 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
1210 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
1211 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1212 checkGLcall("glTexSubImage2D");
1215 if (data->buffer_object)
1217 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1218 checkGLcall("glBindBuffer");
1221 if (wined3d_settings.strict_draw_ordering)
1222 gl_info->gl_ops.gl.p_glFlush();
1224 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1226 struct wined3d_device *device = texture->resource.device;
1227 unsigned int i;
1229 for (i = 0; i < device->context_count; ++i)
1231 context_surface_update(device->contexts[i], surface);
1236 static BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
1238 struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
1240 return wined3d_texture_check_block_align(surface->container, surface->texture_level, &box);
1243 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
1244 struct wined3d_surface *src_surface, const RECT *src_rect)
1246 unsigned int src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
1247 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1248 struct wined3d_texture *src_texture = src_surface->container;
1249 struct wined3d_texture *dst_texture = dst_surface->container;
1250 unsigned int src_row_pitch, src_slice_pitch;
1251 const struct wined3d_format *src_format;
1252 const struct wined3d_format *dst_format;
1253 unsigned int src_fmt_flags, dst_fmt_flags;
1254 const struct wined3d_gl_info *gl_info;
1255 struct wined3d_context *context;
1256 struct wined3d_bo_address data;
1257 UINT update_w, update_h;
1258 UINT dst_w, dst_h;
1259 RECT r, dst_rect;
1260 POINT p;
1262 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1263 dst_surface, wine_dbgstr_point(dst_point),
1264 src_surface, wine_dbgstr_rect(src_rect));
1266 src_format = src_texture->resource.format;
1267 dst_format = dst_texture->resource.format;
1268 src_fmt_flags = src_texture->resource.format_flags;
1269 dst_fmt_flags = dst_texture->resource.format_flags;
1271 if (src_format->id != dst_format->id)
1273 WARN("Source and destination surfaces should have the same format.\n");
1274 return WINED3DERR_INVALIDCALL;
1277 if (!dst_point)
1279 p.x = 0;
1280 p.y = 0;
1281 dst_point = &p;
1283 else if (dst_point->x < 0 || dst_point->y < 0)
1285 WARN("Invalid destination point.\n");
1286 return WINED3DERR_INVALIDCALL;
1289 if (!src_rect)
1291 SetRect(&r, 0, 0, wined3d_texture_get_level_width(src_texture, src_surface->texture_level),
1292 wined3d_texture_get_level_height(src_texture, src_surface->texture_level));
1293 src_rect = &r;
1295 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
1296 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
1298 WARN("Invalid source rectangle.\n");
1299 return WINED3DERR_INVALIDCALL;
1302 dst_w = wined3d_texture_get_level_width(dst_texture, dst_surface->texture_level);
1303 dst_h = wined3d_texture_get_level_height(dst_texture, dst_surface->texture_level);
1305 update_w = src_rect->right - src_rect->left;
1306 update_h = src_rect->bottom - src_rect->top;
1308 if (update_w > dst_w || dst_point->x > dst_w - update_w
1309 || update_h > dst_h || dst_point->y > dst_h - update_h)
1311 WARN("Destination out of bounds.\n");
1312 return WINED3DERR_INVALIDCALL;
1315 if ((src_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(src_surface, src_rect))
1317 WARN("Source rectangle not block-aligned.\n");
1318 return WINED3DERR_INVALIDCALL;
1321 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
1322 if ((dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(dst_surface, &dst_rect))
1324 WARN("Destination rectangle not block-aligned.\n");
1325 return WINED3DERR_INVALIDCALL;
1328 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1329 if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_texture, FALSE))
1330 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
1332 context = context_acquire(dst_texture->resource.device, NULL);
1333 gl_info = context->gl_info;
1335 /* Only load the surface for partial updates. For newly allocated texture
1336 * the texture wouldn't be the current location, and we'd upload zeroes
1337 * just to overwrite them again. */
1338 if (update_w == dst_w && update_h == dst_h)
1339 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1340 else
1341 surface_load_location(dst_surface, context, WINED3D_LOCATION_TEXTURE_RGB);
1342 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1344 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data,
1345 src_texture->sub_resources[src_sub_resource_idx].locations);
1346 wined3d_texture_get_pitch(src_texture, src_surface->texture_level, &src_row_pitch, &src_slice_pitch);
1348 wined3d_surface_upload_data(dst_surface, gl_info, src_format, src_rect,
1349 src_row_pitch, dst_point, FALSE, wined3d_const_bo_address(&data));
1351 context_release(context);
1353 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1354 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1356 return WINED3D_OK;
1359 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1360 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1361 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1362 /* Context activation is done by the caller. */
1363 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
1365 const struct wined3d_gl_info *gl_info = &surface->container->resource.device->adapter->gl_info;
1366 struct wined3d_renderbuffer_entry *entry;
1367 GLuint renderbuffer = 0;
1368 unsigned int src_width, src_height;
1369 unsigned int width, height;
1371 if (rt && rt->container->resource.format->id != WINED3DFMT_NULL)
1373 width = rt->pow2Width;
1374 height = rt->pow2Height;
1376 else
1378 width = surface->pow2Width;
1379 height = surface->pow2Height;
1382 src_width = surface->pow2Width;
1383 src_height = surface->pow2Height;
1385 /* A depth stencil smaller than the render target is not valid */
1386 if (width > src_width || height > src_height) return;
1388 /* Remove any renderbuffer set if the sizes match */
1389 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1390 || (width == src_width && height == src_height))
1392 surface->current_renderbuffer = NULL;
1393 return;
1396 /* Look if we've already got a renderbuffer of the correct dimensions */
1397 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1399 if (entry->width == width && entry->height == height)
1401 renderbuffer = entry->id;
1402 surface->current_renderbuffer = entry;
1403 break;
1407 if (!renderbuffer)
1409 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1410 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1411 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1412 surface->container->resource.format->glInternal, width, height);
1414 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
1415 entry->width = width;
1416 entry->height = height;
1417 entry->id = renderbuffer;
1418 list_add_head(&surface->renderbuffers, &entry->entry);
1420 surface->current_renderbuffer = entry;
1423 checkGLcall("set_compatible_renderbuffer");
1426 /* See also float_16_to_32() in wined3d_private.h */
1427 static inline unsigned short float_32_to_16(const float *in)
1429 int exp = 0;
1430 float tmp = fabsf(*in);
1431 unsigned int mantissa;
1432 unsigned short ret;
1434 /* Deal with special numbers */
1435 if (*in == 0.0f)
1436 return 0x0000;
1437 if (isnan(*in))
1438 return 0x7c01;
1439 if (isinf(*in))
1440 return (*in < 0.0f ? 0xfc00 : 0x7c00);
1442 if (tmp < (float)(1u << 10))
1446 tmp = tmp * 2.0f;
1447 exp--;
1448 } while (tmp < (float)(1u << 10));
1450 else if (tmp >= (float)(1u << 11))
1454 tmp /= 2.0f;
1455 exp++;
1456 } while (tmp >= (float)(1u << 11));
1459 mantissa = (unsigned int)tmp;
1460 if (tmp - mantissa >= 0.5f)
1461 ++mantissa; /* Round to nearest, away from zero. */
1463 exp += 10; /* Normalize the mantissa. */
1464 exp += 15; /* Exponent is encoded with excess 15. */
1466 if (exp > 30) /* too big */
1468 ret = 0x7c00; /* INF */
1470 else if (exp <= 0)
1472 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1473 while (exp <= 0)
1475 mantissa = mantissa >> 1;
1476 ++exp;
1478 ret = mantissa & 0x3ff;
1480 else
1482 ret = (exp << 10) | (mantissa & 0x3ff);
1485 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
1486 return ret;
1489 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
1490 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1492 unsigned short *dst_s;
1493 const float *src_f;
1494 unsigned int x, y;
1496 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1498 for (y = 0; y < h; ++y)
1500 src_f = (const float *)(src + y * pitch_in);
1501 dst_s = (unsigned short *) (dst + y * pitch_out);
1502 for (x = 0; x < w; ++x)
1504 dst_s[x] = float_32_to_16(src_f + x);
1509 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
1510 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1512 static const unsigned char convert_5to8[] =
1514 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1515 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1516 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1517 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1519 static const unsigned char convert_6to8[] =
1521 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1522 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1523 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1524 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1525 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1526 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1527 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1528 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1530 unsigned int x, y;
1532 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1534 for (y = 0; y < h; ++y)
1536 const WORD *src_line = (const WORD *)(src + y * pitch_in);
1537 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1538 for (x = 0; x < w; ++x)
1540 WORD pixel = src_line[x];
1541 dst_line[x] = 0xff000000u
1542 | convert_5to8[(pixel & 0xf800u) >> 11] << 16
1543 | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
1544 | convert_5to8[(pixel & 0x001fu)];
1549 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1550 * in both cases we're just setting the X / Alpha channel to 0xff. */
1551 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
1552 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1554 unsigned int x, y;
1556 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1558 for (y = 0; y < h; ++y)
1560 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
1561 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1563 for (x = 0; x < w; ++x)
1565 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
1570 static inline BYTE cliptobyte(int x)
1572 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
1575 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
1576 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1578 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1579 unsigned int x, y;
1581 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1583 for (y = 0; y < h; ++y)
1585 const BYTE *src_line = src + y * pitch_in;
1586 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1587 for (x = 0; x < w; ++x)
1589 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1590 * C = Y - 16; D = U - 128; E = V - 128;
1591 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1592 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1593 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1594 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1595 * U and V are shared between the pixels. */
1596 if (!(x & 1)) /* For every even pixel, read new U and V. */
1598 d = (int) src_line[1] - 128;
1599 e = (int) src_line[3] - 128;
1600 r2 = 409 * e + 128;
1601 g2 = - 100 * d - 208 * e + 128;
1602 b2 = 516 * d + 128;
1604 c2 = 298 * ((int) src_line[0] - 16);
1605 dst_line[x] = 0xff000000
1606 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
1607 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
1608 | cliptobyte((c2 + b2) >> 8); /* blue */
1609 /* Scale RGB values to 0..255 range,
1610 * then clip them if still not in range (may be negative),
1611 * then shift them within DWORD if necessary. */
1612 src_line += 2;
1617 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
1618 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1620 unsigned int x, y;
1621 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1623 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
1625 for (y = 0; y < h; ++y)
1627 const BYTE *src_line = src + y * pitch_in;
1628 WORD *dst_line = (WORD *)(dst + y * pitch_out);
1629 for (x = 0; x < w; ++x)
1631 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1632 * C = Y - 16; D = U - 128; E = V - 128;
1633 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1634 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1635 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1636 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1637 * U and V are shared between the pixels. */
1638 if (!(x & 1)) /* For every even pixel, read new U and V. */
1640 d = (int) src_line[1] - 128;
1641 e = (int) src_line[3] - 128;
1642 r2 = 409 * e + 128;
1643 g2 = - 100 * d - 208 * e + 128;
1644 b2 = 516 * d + 128;
1646 c2 = 298 * ((int) src_line[0] - 16);
1647 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
1648 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
1649 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
1650 /* Scale RGB values to 0..255 range,
1651 * then clip them if still not in range (may be negative),
1652 * then shift them within DWORD if necessary. */
1653 src_line += 2;
1658 struct d3dfmt_converter_desc
1660 enum wined3d_format_id from, to;
1661 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
1664 static const struct d3dfmt_converter_desc converters[] =
1666 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
1667 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
1668 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1669 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1670 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
1671 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
1674 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
1675 enum wined3d_format_id to)
1677 unsigned int i;
1679 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
1681 if (converters[i].from == from && converters[i].to == to)
1682 return &converters[i];
1685 return NULL;
1688 static struct wined3d_texture *surface_convert_format(struct wined3d_texture *src_texture,
1689 unsigned int sub_resource_idx, const struct wined3d_format *dst_format)
1691 const struct wined3d_format *src_format = src_texture->resource.format;
1692 struct wined3d_device *device = src_texture->resource.device;
1693 const struct d3dfmt_converter_desc *conv = NULL;
1694 struct wined3d_texture *dst_texture;
1695 struct wined3d_resource_desc desc;
1696 struct wined3d_map_desc src_map;
1698 if (!(conv = find_converter(src_format->id, dst_format->id)) && (!device->d3d_initialized
1699 || !is_identity_fixup(src_format->color_fixup) || src_format->convert
1700 || !is_identity_fixup(dst_format->color_fixup) || dst_format->convert))
1702 FIXME("Cannot find a conversion function from format %s to %s.\n",
1703 debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
1704 return NULL;
1707 /* FIXME: Multisampled conversion? */
1708 wined3d_resource_get_desc(src_texture->sub_resources[sub_resource_idx].resource, &desc);
1709 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1710 desc.format = dst_format->id;
1711 desc.usage = 0;
1712 desc.pool = WINED3D_POOL_SCRATCH;
1713 if (FAILED(wined3d_texture_create(device, &desc, 1,
1714 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
1715 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
1717 ERR("Failed to create a destination texture for conversion.\n");
1718 return NULL;
1721 memset(&src_map, 0, sizeof(src_map));
1722 if (FAILED(wined3d_resource_map(&src_texture->resource, sub_resource_idx,
1723 &src_map, NULL, WINED3D_MAP_READONLY)))
1725 ERR("Failed to map the source texture.\n");
1726 wined3d_texture_decref(dst_texture);
1727 return NULL;
1729 if (conv)
1731 struct wined3d_map_desc dst_map;
1733 memset(&dst_map, 0, sizeof(dst_map));
1734 if (FAILED(wined3d_resource_map(&dst_texture->resource, 0, &dst_map, NULL, 0)))
1736 ERR("Failed to map the destination texture.\n");
1737 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1738 wined3d_texture_decref(dst_texture);
1739 return NULL;
1742 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch, desc.width, desc.height);
1744 wined3d_resource_unmap(&dst_texture->resource, 0);
1746 else
1748 struct wined3d_bo_address data = {0, src_map.data};
1749 RECT src_rect = {0, 0, desc.width, desc.height};
1750 const struct wined3d_gl_info *gl_info;
1751 struct wined3d_context *context;
1752 POINT dst_point = {0, 0};
1754 TRACE("Using upload conversion.\n");
1755 context = context_acquire(device, NULL);
1756 gl_info = context->gl_info;
1758 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1759 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1760 wined3d_surface_upload_data(dst_texture->sub_resources[0].u.surface, gl_info, src_format,
1761 &src_rect, src_map.row_pitch, &dst_point, FALSE, wined3d_const_bo_address(&data));
1763 context_release(context);
1765 wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
1766 wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
1768 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1770 return dst_texture;
1773 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
1774 unsigned int bpp, UINT pitch, DWORD color)
1776 BYTE *first;
1777 unsigned int x, y;
1779 /* Do first row */
1781 #define COLORFILL_ROW(type) \
1782 do { \
1783 type *d = (type *)buf; \
1784 for (x = 0; x < width; ++x) \
1785 d[x] = (type)color; \
1786 } while(0)
1788 switch (bpp)
1790 case 1:
1791 COLORFILL_ROW(BYTE);
1792 break;
1794 case 2:
1795 COLORFILL_ROW(WORD);
1796 break;
1798 case 3:
1800 BYTE *d = buf;
1801 for (x = 0; x < width; ++x, d += 3)
1803 d[0] = (color ) & 0xff;
1804 d[1] = (color >> 8) & 0xff;
1805 d[2] = (color >> 16) & 0xff;
1807 break;
1809 case 4:
1810 COLORFILL_ROW(DWORD);
1811 break;
1813 default:
1814 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
1815 return WINED3DERR_NOTAVAILABLE;
1818 #undef COLORFILL_ROW
1820 /* Now copy first row. */
1821 first = buf;
1822 for (y = 1; y < height; ++y)
1824 buf += pitch;
1825 memcpy(buf, first, width * bpp);
1828 return WINED3D_OK;
1831 static void read_from_framebuffer(struct wined3d_surface *surface,
1832 struct wined3d_context *old_ctx, DWORD dst_location)
1834 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
1835 struct wined3d_texture *texture = surface->container;
1836 struct wined3d_device *device = texture->resource.device;
1837 const struct wined3d_gl_info *gl_info;
1838 struct wined3d_context *context = old_ctx;
1839 struct wined3d_surface *restore_rt = NULL;
1840 unsigned int row_pitch, slice_pitch;
1841 unsigned int width, height;
1842 BYTE *mem;
1843 BYTE *row, *top, *bottom;
1844 int i;
1845 BOOL srcIsUpsideDown;
1846 struct wined3d_bo_address data;
1848 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1850 restore_rt = context_get_rt_surface(old_ctx);
1851 if (restore_rt != surface)
1852 context = context_acquire(device, surface);
1853 else
1854 restore_rt = NULL;
1856 context_apply_blit_state(context, device);
1857 gl_info = context->gl_info;
1859 /* Select the correct read buffer, and give some debug output.
1860 * There is no need to keep track of the current read buffer or reset it, every part of the code
1861 * that reads sets the read buffer as desired.
1863 if (wined3d_resource_is_offscreen(&texture->resource))
1865 /* Mapping the primary render target which is not on a swapchain.
1866 * Read from the back buffer. */
1867 TRACE("Mapping offscreen render target.\n");
1868 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1869 srcIsUpsideDown = TRUE;
1871 else
1873 /* Onscreen surfaces are always part of a swapchain */
1874 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
1875 TRACE("Mapping %#x buffer.\n", buffer);
1876 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1877 checkGLcall("glReadBuffer");
1878 srcIsUpsideDown = FALSE;
1881 if (data.buffer_object)
1883 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1884 checkGLcall("glBindBuffer");
1887 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
1889 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1890 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / texture->resource.format->byte_count);
1891 checkGLcall("glPixelStorei");
1893 width = wined3d_texture_get_level_width(texture, surface->texture_level);
1894 height = wined3d_texture_get_level_height(texture, surface->texture_level);
1895 gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
1896 texture->resource.format->glFormat,
1897 texture->resource.format->glType, data.addr);
1898 checkGLcall("glReadPixels");
1900 /* Reset previous pixel store pack state */
1901 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1902 checkGLcall("glPixelStorei");
1904 if (!srcIsUpsideDown)
1906 /* glReadPixels returns the image upside down, and there is no way to
1907 * prevent this. Flip the lines in software. */
1909 if (!(row = HeapAlloc(GetProcessHeap(), 0, row_pitch)))
1910 goto error;
1912 if (data.buffer_object)
1914 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
1915 checkGLcall("glMapBuffer");
1917 else
1918 mem = data.addr;
1920 top = mem;
1921 bottom = mem + row_pitch * (height - 1);
1922 for (i = 0; i < height / 2; i++)
1924 memcpy(row, top, row_pitch);
1925 memcpy(top, bottom, row_pitch);
1926 memcpy(bottom, row, row_pitch);
1927 top += row_pitch;
1928 bottom -= row_pitch;
1930 HeapFree(GetProcessHeap(), 0, row);
1932 if (data.buffer_object)
1933 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
1936 error:
1937 if (data.buffer_object)
1939 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1940 checkGLcall("glBindBuffer");
1943 if (restore_rt)
1944 context_restore(context, restore_rt);
1947 /* Read the framebuffer contents into a texture. Note that this function
1948 * doesn't do any kind of flipping. Using this on an onscreen surface will
1949 * result in a flipped D3D texture.
1951 * Context activation is done by the caller. This function may temporarily
1952 * switch to a different context and restore the original one before return. */
1953 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct wined3d_context *old_ctx)
1955 struct wined3d_texture *texture = surface->container;
1956 struct wined3d_device *device = texture->resource.device;
1957 const struct wined3d_gl_info *gl_info;
1958 struct wined3d_context *context = old_ctx;
1959 struct wined3d_surface *restore_rt = NULL;
1961 restore_rt = context_get_rt_surface(old_ctx);
1962 if (restore_rt != surface)
1963 context = context_acquire(device, surface);
1964 else
1965 restore_rt = NULL;
1967 gl_info = context->gl_info;
1968 device_invalidate_state(device, STATE_FRAMEBUFFER);
1970 wined3d_texture_prepare_texture(texture, context, srgb);
1971 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1973 TRACE("Reading back offscreen render target %p.\n", surface);
1975 if (wined3d_resource_is_offscreen(&texture->resource))
1976 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1977 else
1978 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
1979 checkGLcall("glReadBuffer");
1981 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
1982 0, 0, 0, 0, wined3d_texture_get_level_width(texture, surface->texture_level),
1983 wined3d_texture_get_level_height(texture, surface->texture_level));
1984 checkGLcall("glCopyTexSubImage2D");
1986 if (restore_rt)
1987 context_restore(context, restore_rt);
1990 static void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
1992 struct wined3d_texture *texture = surface->container;
1993 const struct wined3d_format *format = texture->resource.format;
1995 if (multisample)
1997 DWORD samples;
1999 if (surface->rb_multisample)
2000 return;
2002 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
2003 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
2004 * to GL_NV_framebuffer_multisample_coverage.
2006 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
2007 * but it does not have an equivalent OpenGL extension. */
2009 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
2010 * as the count of advertised multisample types for the surface format. */
2011 if (texture->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE)
2013 unsigned int i, count = 0;
2015 for (i = 0; i < sizeof(format->multisample_types) * 8; ++i)
2017 if (format->multisample_types & 1u << i)
2019 if (texture->resource.multisample_quality == count++)
2020 break;
2023 samples = i + 1;
2025 else
2027 samples = texture->resource.multisample_type;
2030 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
2031 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
2032 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
2033 format->glInternal, surface->pow2Width, surface->pow2Height);
2034 checkGLcall("glRenderbufferStorageMultisample()");
2035 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
2037 else
2039 if (surface->rb_resolved)
2040 return;
2042 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
2043 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
2044 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format->glInternal,
2045 surface->pow2Width, surface->pow2Height);
2046 checkGLcall("glRenderbufferStorage()");
2047 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
2051 /* Does a direct frame buffer -> texture copy. Stretching is done with single
2052 * pixel copy calls. */
2053 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2054 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2056 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2057 struct wined3d_texture *src_texture = src_surface->container;
2058 struct wined3d_texture *dst_texture = dst_surface->container;
2059 struct wined3d_device *device = dst_texture->resource.device;
2060 const struct wined3d_gl_info *gl_info;
2061 float xrel, yrel;
2062 struct wined3d_context *context;
2063 BOOL upsidedown = FALSE;
2064 RECT dst_rect = *dst_rect_in;
2065 unsigned int src_height;
2067 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2068 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2070 if(dst_rect.top > dst_rect.bottom) {
2071 UINT tmp = dst_rect.bottom;
2072 dst_rect.bottom = dst_rect.top;
2073 dst_rect.top = tmp;
2074 upsidedown = TRUE;
2077 context = context_acquire(device, src_surface);
2078 gl_info = context->gl_info;
2079 context_apply_blit_state(context, device);
2080 wined3d_texture_load(dst_texture, context, FALSE);
2082 /* Bind the target texture */
2083 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
2084 if (wined3d_resource_is_offscreen(&src_texture->resource))
2086 TRACE("Reading from an offscreen target\n");
2087 upsidedown = !upsidedown;
2088 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
2090 else
2092 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2094 checkGLcall("glReadBuffer");
2096 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
2097 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
2099 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2101 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2103 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2104 ERR("Texture filtering not supported in direct blit.\n");
2106 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2107 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2109 ERR("Texture filtering not supported in direct blit\n");
2112 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2113 if (upsidedown
2114 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2115 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2117 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
2118 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2119 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
2120 src_rect->left, src_height - src_rect->bottom,
2121 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2123 else
2125 LONG row;
2126 UINT yoffset = src_height - src_rect->top + dst_rect.top - 1;
2127 /* I have to process this row by row to swap the image,
2128 * otherwise it would be upside down, so stretching in y direction
2129 * doesn't cost extra time
2131 * However, stretching in x direction can be avoided if not necessary
2133 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
2134 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2136 /* Well, that stuff works, but it's very slow.
2137 * find a better way instead
2139 LONG col;
2141 for (col = dst_rect.left; col < dst_rect.right; ++col)
2143 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2144 dst_rect.left + col /* x offset */, row /* y offset */,
2145 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
2148 else
2150 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2151 dst_rect.left /* x offset */, row /* y offset */,
2152 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
2156 checkGLcall("glCopyTexSubImage2D");
2158 context_release(context);
2160 /* The texture is now most up to date - If the surface is a render target
2161 * and has a drawable, this path is never entered. */
2162 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2163 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2166 /* Uses the hardware to stretch and flip the image */
2167 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2168 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2170 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2171 struct wined3d_texture *src_texture = src_surface->container;
2172 struct wined3d_texture *dst_texture = dst_surface->container;
2173 struct wined3d_device *device = dst_texture->resource.device;
2174 GLuint src, backup = 0;
2175 float left, right, top, bottom; /* Texture coordinates */
2176 const struct wined3d_gl_info *gl_info;
2177 unsigned int src_width, src_height;
2178 struct wined3d_context *context;
2179 GLenum drawBuffer = GL_BACK;
2180 GLenum offscreen_buffer;
2181 GLenum texture_target;
2182 BOOL noBackBufferBackup;
2183 BOOL src_offscreen;
2184 BOOL upsidedown = FALSE;
2185 RECT dst_rect = *dst_rect_in;
2187 TRACE("Using hwstretch blit\n");
2188 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2189 context = context_acquire(device, src_surface);
2190 gl_info = context->gl_info;
2191 context_apply_blit_state(context, device);
2192 wined3d_texture_load(dst_texture, context, FALSE);
2194 offscreen_buffer = context_get_offscreen_gl_buffer(context);
2195 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
2196 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2198 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
2199 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
2200 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
2202 /* Get it a description */
2203 wined3d_texture_load(src_texture, context, FALSE);
2206 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2207 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2209 if (context->aux_buffers >= 2)
2211 /* Got more than one aux buffer? Use the 2nd aux buffer */
2212 drawBuffer = GL_AUX1;
2214 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
2216 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2217 drawBuffer = GL_AUX0;
2220 if (noBackBufferBackup)
2222 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
2223 checkGLcall("glGenTextures");
2224 context_bind_texture(context, GL_TEXTURE_2D, backup);
2225 texture_target = GL_TEXTURE_2D;
2227 else
2229 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2230 * we are reading from the back buffer, the backup can be used as source texture
2232 texture_target = src_surface->texture_target;
2233 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
2234 gl_info->gl_ops.gl.p_glEnable(texture_target);
2235 checkGLcall("glEnable(texture_target)");
2237 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2238 surface_get_sub_resource(src_surface)->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
2241 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2242 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2244 if(dst_rect.top > dst_rect.bottom) {
2245 UINT tmp = dst_rect.bottom;
2246 dst_rect.bottom = dst_rect.top;
2247 dst_rect.top = tmp;
2248 upsidedown = TRUE;
2251 if (src_offscreen)
2253 TRACE("Reading from an offscreen target\n");
2254 upsidedown = !upsidedown;
2255 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
2257 else
2259 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2262 /* TODO: Only back up the part that will be overwritten */
2263 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, src_width, src_height);
2265 checkGLcall("glCopyTexSubImage2D");
2267 /* No issue with overriding these - the sampler is dirty due to blit usage */
2268 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
2269 checkGLcall("glTexParameteri");
2270 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2271 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
2272 checkGLcall("glTexParameteri");
2274 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
2276 src = backup ? backup : src_texture->texture_rgb.name;
2278 else
2280 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
2281 checkGLcall("glReadBuffer(GL_FRONT)");
2283 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
2284 checkGLcall("glGenTextures(1, &src)");
2285 context_bind_texture(context, GL_TEXTURE_2D, src);
2287 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
2288 * out for power of 2 sizes
2290 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
2291 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2292 checkGLcall("glTexImage2D");
2293 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_width, src_height);
2295 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2296 checkGLcall("glTexParameteri");
2297 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2298 checkGLcall("glTexParameteri");
2300 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
2301 checkGLcall("glReadBuffer(GL_BACK)");
2303 if (texture_target != GL_TEXTURE_2D)
2305 gl_info->gl_ops.gl.p_glDisable(texture_target);
2306 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2307 texture_target = GL_TEXTURE_2D;
2310 checkGLcall("glEnd and previous");
2312 left = src_rect->left;
2313 right = src_rect->right;
2315 if (!upsidedown)
2317 top = src_height - src_rect->top;
2318 bottom = src_height - src_rect->bottom;
2320 else
2322 top = src_height - src_rect->bottom;
2323 bottom = src_height - src_rect->top;
2326 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
2328 left /= src_surface->pow2Width;
2329 right /= src_surface->pow2Width;
2330 top /= src_surface->pow2Height;
2331 bottom /= src_surface->pow2Height;
2334 /* draw the source texture stretched and upside down. The correct surface is bound already */
2335 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2336 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2338 context_set_draw_buffer(context, drawBuffer);
2339 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
2341 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2342 /* bottom left */
2343 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
2344 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2346 /* top left */
2347 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
2348 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
2350 /* top right */
2351 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
2352 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2354 /* bottom right */
2355 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
2356 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
2357 gl_info->gl_ops.gl.p_glEnd();
2358 checkGLcall("glEnd and previous");
2360 if (texture_target != dst_surface->texture_target)
2362 gl_info->gl_ops.gl.p_glDisable(texture_target);
2363 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
2364 texture_target = dst_surface->texture_target;
2367 /* Now read the stretched and upside down image into the destination texture */
2368 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
2369 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
2371 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
2372 0, 0, /* We blitted the image to the origin */
2373 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2374 checkGLcall("glCopyTexSubImage2D");
2376 if (drawBuffer == GL_BACK)
2378 /* Write the back buffer backup back. */
2379 if (backup)
2381 if (texture_target != GL_TEXTURE_2D)
2383 gl_info->gl_ops.gl.p_glDisable(texture_target);
2384 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2385 texture_target = GL_TEXTURE_2D;
2387 context_bind_texture(context, GL_TEXTURE_2D, backup);
2389 else
2391 if (texture_target != src_surface->texture_target)
2393 gl_info->gl_ops.gl.p_glDisable(texture_target);
2394 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
2395 texture_target = src_surface->texture_target;
2397 context_bind_texture(context, src_surface->texture_target, src_texture->texture_rgb.name);
2400 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2401 /* top left */
2402 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
2403 gl_info->gl_ops.gl.p_glVertex2i(0, src_height);
2405 /* bottom left */
2406 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)src_height / (float)src_surface->pow2Height);
2407 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2409 /* bottom right */
2410 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_surface->pow2Width,
2411 (float)src_height / (float)src_surface->pow2Height);
2412 gl_info->gl_ops.gl.p_glVertex2i(src_width, 0);
2414 /* top right */
2415 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_surface->pow2Width, 0.0f);
2416 gl_info->gl_ops.gl.p_glVertex2i(src_width, src_height);
2417 gl_info->gl_ops.gl.p_glEnd();
2419 gl_info->gl_ops.gl.p_glDisable(texture_target);
2420 checkGLcall("glDisable(texture_target)");
2422 /* Cleanup */
2423 if (src != src_texture->texture_rgb.name && src != backup)
2425 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
2426 checkGLcall("glDeleteTextures(1, &src)");
2428 if (backup)
2430 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
2431 checkGLcall("glDeleteTextures(1, &backup)");
2434 if (wined3d_settings.strict_draw_ordering)
2435 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2437 context_release(context);
2439 /* The texture is now most up to date - If the surface is a render target
2440 * and has a drawable, this path is never entered. */
2441 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2442 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2445 /* Front buffer coordinates are always full screen coordinates, but our GL
2446 * drawable is limited to the window's client area. The sysmem and texture
2447 * copies do have the full screen size. Note that GL has a bottom-left
2448 * origin, while D3D has a top-left origin. */
2449 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
2451 struct wined3d_texture *texture = surface->container;
2452 UINT drawable_height;
2454 if (texture->swapchain && texture == texture->swapchain->front_buffer)
2456 POINT offset = {0, 0};
2457 RECT windowsize;
2459 ScreenToClient(window, &offset);
2460 OffsetRect(rect, offset.x, offset.y);
2462 GetClientRect(window, &windowsize);
2463 drawable_height = windowsize.bottom - windowsize.top;
2465 else
2467 drawable_height = wined3d_texture_get_level_height(texture, surface->texture_level);
2470 rect->top = drawable_height - rect->top;
2471 rect->bottom = drawable_height - rect->bottom;
2474 /* Context activation is done by the caller. */
2475 static void surface_blt_to_drawable(const struct wined3d_device *device,
2476 struct wined3d_context *old_ctx,
2477 enum wined3d_texture_filter_type filter, BOOL alpha_test,
2478 struct wined3d_surface *src_surface, const RECT *src_rect_in,
2479 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
2481 struct wined3d_texture *src_texture = src_surface->container;
2482 struct wined3d_texture *dst_texture = dst_surface->container;
2483 const struct wined3d_gl_info *gl_info;
2484 struct wined3d_context *context = old_ctx;
2485 struct wined3d_surface *restore_rt = NULL;
2486 RECT src_rect, dst_rect;
2488 src_rect = *src_rect_in;
2489 dst_rect = *dst_rect_in;
2491 restore_rt = context_get_rt_surface(old_ctx);
2492 if (restore_rt != dst_surface)
2493 context = context_acquire(device, dst_surface);
2494 else
2495 restore_rt = NULL;
2497 gl_info = context->gl_info;
2499 /* Make sure the surface is up-to-date. This should probably use
2500 * surface_load_location() and worry about the destination surface too,
2501 * unless we're overwriting it completely. */
2502 wined3d_texture_load(src_texture, context, FALSE);
2504 /* Activate the destination context, set it up for blitting */
2505 context_apply_blit_state(context, device);
2507 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
2508 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
2510 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
2512 if (alpha_test)
2514 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2515 checkGLcall("glEnable(GL_ALPHA_TEST)");
2517 /* For P8 surfaces, the alpha component contains the palette index.
2518 * Which means that the colorkey is one of the palette entries. In
2519 * other cases pixels that should be masked away have alpha set to 0. */
2520 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2521 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2522 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2523 else
2524 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2525 checkGLcall("glAlphaFunc");
2527 else
2529 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2530 checkGLcall("glDisable(GL_ALPHA_TEST)");
2533 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
2535 if (alpha_test)
2537 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2538 checkGLcall("glDisable(GL_ALPHA_TEST)");
2541 /* Leave the opengl state valid for blitting */
2542 device->blitter->unset_shader(context->gl_info);
2544 if (wined3d_settings.strict_draw_ordering
2545 || (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture))
2546 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2548 if (restore_rt)
2549 context_restore(context, restore_rt);
2552 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
2554 struct wined3d_resource *resource = &s->container->resource;
2555 struct wined3d_device *device = resource->device;
2556 struct wined3d_rendertarget_view_desc view_desc;
2557 struct wined3d_rendertarget_view *view;
2558 const struct blit_shader *blitter;
2559 HRESULT hr;
2561 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
2562 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
2564 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2565 return WINED3DERR_INVALIDCALL;
2568 view_desc.format_id = resource->format->id;
2569 view_desc.u.texture.level_idx = s->texture_level;
2570 view_desc.u.texture.layer_idx = s->texture_layer;
2571 view_desc.u.texture.layer_count = 1;
2572 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
2573 resource, NULL, &wined3d_null_parent_ops, &view)))
2575 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
2576 return hr;
2579 hr = blitter->color_fill(device, view, rect, color);
2580 wined3d_rendertarget_view_decref(view);
2582 return hr;
2585 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
2586 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
2587 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2589 struct wined3d_texture *dst_texture = dst_surface->container;
2590 struct wined3d_device *device = dst_texture->resource.device;
2591 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
2592 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
2593 struct wined3d_texture *src_texture;
2595 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2596 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2597 flags, fx, debug_d3dtexturefiltertype(filter));
2599 /* Get the swapchain. One of the surfaces has to be a primary surface */
2600 if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2602 WARN("Destination is in sysmem, rejecting gl blt\n");
2603 return WINED3DERR_INVALIDCALL;
2606 dst_swapchain = dst_texture->swapchain;
2608 if (src_surface)
2610 src_texture = src_surface->container;
2611 if (src_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2613 WARN("Src is in sysmem, rejecting gl blt\n");
2614 return WINED3DERR_INVALIDCALL;
2617 src_swapchain = src_texture->swapchain;
2619 else
2621 src_texture = NULL;
2622 src_swapchain = NULL;
2625 /* Early sort out of cases where no render target is used */
2626 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
2628 TRACE("No surface is render target, not using hardware blit.\n");
2629 return WINED3DERR_INVALIDCALL;
2632 /* No destination color keying supported */
2633 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
2635 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2636 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2637 return WINED3DERR_INVALIDCALL;
2640 if (dst_swapchain && dst_swapchain == src_swapchain)
2642 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2643 return WINED3DERR_INVALIDCALL;
2646 if (dst_swapchain && src_swapchain)
2648 FIXME("Implement hardware blit between two different swapchains\n");
2649 return WINED3DERR_INVALIDCALL;
2652 if (dst_swapchain)
2654 /* Handled with regular texture -> swapchain blit */
2655 if (src_surface == rt)
2656 TRACE("Blit from active render target to a swapchain\n");
2658 else if (src_swapchain && dst_surface == rt)
2660 FIXME("Implement blit from a swapchain to the active render target\n");
2661 return WINED3DERR_INVALIDCALL;
2664 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
2666 unsigned int src_width, src_height;
2667 /* Blit from render target to texture */
2668 BOOL stretchx;
2670 /* P8 read back is not implemented */
2671 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
2672 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
2674 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2675 return WINED3DERR_INVALIDCALL;
2678 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
2680 TRACE("Color keying not supported by frame buffer to texture blit\n");
2681 return WINED3DERR_INVALIDCALL;
2682 /* Destination color key is checked above */
2685 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
2686 stretchx = TRUE;
2687 else
2688 stretchx = FALSE;
2690 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2691 * flip the image nor scale it.
2693 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2694 * -> If the app wants an image width an unscaled width, copy it line per line
2695 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2696 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2697 * back buffer. This is slower than reading line per line, thus not used for flipping
2698 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2699 * pixel by pixel. */
2700 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
2701 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2702 if (!stretchx || dst_rect->right - dst_rect->left > src_width
2703 || dst_rect->bottom - dst_rect->top > src_height)
2705 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2706 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
2708 else
2710 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2711 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
2714 surface_evict_sysmem(dst_surface);
2716 return WINED3D_OK;
2719 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2720 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2721 return WINED3DERR_INVALIDCALL;
2724 /* Context activation is done by the caller. */
2725 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
2726 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
2728 struct wined3d_device *device = surface->container->resource.device;
2729 const struct wined3d_gl_info *gl_info = context->gl_info;
2730 GLint compare_mode = GL_NONE;
2731 struct blt_info info;
2732 GLint old_binding = 0;
2733 RECT rect;
2735 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
2737 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2738 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2739 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2740 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2741 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2742 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
2743 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
2744 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
2745 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2746 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
2747 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
2749 SetRect(&rect, 0, h, w, 0);
2750 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
2751 context_active_texture(context, context->gl_info, 0);
2752 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
2753 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
2754 if (gl_info->supported[ARB_SHADOW])
2756 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
2757 if (compare_mode != GL_NONE)
2758 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
2761 device->shader_backend->shader_select_depth_blt(device->shader_priv,
2762 gl_info, info.tex_type, &surface->ds_current_size);
2764 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
2765 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
2766 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
2767 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
2768 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
2769 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
2770 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
2771 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
2772 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
2773 gl_info->gl_ops.gl.p_glEnd();
2775 if (compare_mode != GL_NONE)
2776 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
2777 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
2779 gl_info->gl_ops.gl.p_glPopAttrib();
2781 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
2784 void surface_modify_ds_location(struct wined3d_surface *surface,
2785 DWORD location, UINT w, UINT h)
2787 struct wined3d_texture_sub_resource *sub_resource;
2789 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
2791 sub_resource = surface_get_sub_resource(surface);
2792 if (((sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
2793 || (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
2794 && (location & WINED3D_LOCATION_TEXTURE_RGB)))
2795 wined3d_texture_set_dirty(surface->container);
2797 surface->ds_current_size.cx = w;
2798 surface->ds_current_size.cy = h;
2799 sub_resource->locations = location;
2802 /* Context activation is done by the caller. */
2803 static void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
2805 struct wined3d_texture *texture = surface->container;
2806 struct wined3d_device *device = texture->resource.device;
2807 const struct wined3d_gl_info *gl_info = context->gl_info;
2808 GLsizei w, h;
2810 TRACE("surface %p, context %p, new location %#x.\n", surface, context, location);
2812 /* TODO: Make this work for modes other than FBO */
2813 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
2815 if (!(surface_get_sub_resource(surface)->locations & location))
2817 w = surface->ds_current_size.cx;
2818 h = surface->ds_current_size.cy;
2819 surface->ds_current_size.cx = 0;
2820 surface->ds_current_size.cy = 0;
2822 else
2824 w = wined3d_texture_get_level_width(surface->container, surface->texture_level);
2825 h = wined3d_texture_get_level_height(surface->container, surface->texture_level);
2828 if (surface->current_renderbuffer)
2830 FIXME("Not supported with fixed up depth stencil.\n");
2831 return;
2834 wined3d_surface_prepare(surface, context, location);
2836 if (location == WINED3D_LOCATION_TEXTURE_RGB)
2838 GLint old_binding = 0;
2839 GLenum bind_target;
2841 /* The render target is allowed to be smaller than the depth/stencil
2842 * buffer, so the onscreen depth/stencil buffer is potentially smaller
2843 * than the offscreen surface. Don't overwrite the offscreen surface
2844 * with undefined data. */
2845 w = min(w, context->swapchain->desc.backbuffer_width);
2846 h = min(h, context->swapchain->desc.backbuffer_height);
2848 TRACE("Copying onscreen depth buffer to depth texture.\n");
2850 if (!device->depth_blt_texture)
2851 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
2853 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2854 * directly on the FBO texture. That's because we need to flip. */
2855 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2856 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2857 NULL, WINED3D_LOCATION_DRAWABLE);
2858 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2860 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
2861 bind_target = GL_TEXTURE_RECTANGLE_ARB;
2863 else
2865 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
2866 bind_target = GL_TEXTURE_2D;
2868 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
2869 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
2870 * internal format, because the internal format might include stencil
2871 * data. In principle we should copy stencil data as well, but unless
2872 * the driver supports stencil export it's hard to do, and doesn't
2873 * seem to be needed in practice. If the hardware doesn't support
2874 * writing stencil data, the glCopyTexImage2D() call might trigger
2875 * software fallbacks. */
2876 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
2877 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2878 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2879 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2880 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2881 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2882 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
2884 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2885 NULL, surface, WINED3D_LOCATION_TEXTURE_RGB);
2886 context_set_draw_buffer(context, GL_NONE);
2888 /* Do the actual blit */
2889 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
2890 checkGLcall("depth_blt");
2892 context_invalidate_state(context, STATE_FRAMEBUFFER);
2894 if (wined3d_settings.strict_draw_ordering)
2895 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2897 else if (location == WINED3D_LOCATION_DRAWABLE)
2899 TRACE("Copying depth texture to onscreen depth buffer.\n");
2901 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2902 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2903 NULL, WINED3D_LOCATION_DRAWABLE);
2904 surface_depth_blt(surface, context, texture->texture_rgb.name,
2905 0, surface->pow2Height - h, w, h, surface->texture_target);
2906 checkGLcall("depth_blt");
2908 context_invalidate_state(context, STATE_FRAMEBUFFER);
2910 if (wined3d_settings.strict_draw_ordering)
2911 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2913 else
2915 ERR("Invalid location (%#x) specified.\n", location);
2919 static DWORD resource_access_from_location(DWORD location)
2921 switch (location)
2923 case WINED3D_LOCATION_SYSMEM:
2924 case WINED3D_LOCATION_USER_MEMORY:
2925 case WINED3D_LOCATION_DIB:
2926 case WINED3D_LOCATION_BUFFER:
2927 return WINED3D_RESOURCE_ACCESS_CPU;
2929 case WINED3D_LOCATION_DRAWABLE:
2930 case WINED3D_LOCATION_TEXTURE_SRGB:
2931 case WINED3D_LOCATION_TEXTURE_RGB:
2932 case WINED3D_LOCATION_RB_MULTISAMPLE:
2933 case WINED3D_LOCATION_RB_RESOLVED:
2934 return WINED3D_RESOURCE_ACCESS_GPU;
2936 default:
2937 FIXME("Unhandled location %#x.\n", location);
2938 return 0;
2942 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
2944 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2945 struct wined3d_texture *texture = surface->container;
2946 struct wined3d_device *device = texture->resource.device;
2947 struct wined3d_context *context;
2948 const struct wined3d_gl_info *gl_info;
2949 struct wined3d_bo_address dst, src;
2950 UINT size = surface->resource.size;
2952 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
2953 wined3d_texture_get_memory(texture, sub_resource_idx, &src,
2954 texture->sub_resources[sub_resource_idx].locations);
2956 if (dst.buffer_object)
2958 context = context_acquire(device, NULL);
2959 gl_info = context->gl_info;
2960 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
2961 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
2962 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2963 checkGLcall("Upload PBO");
2964 context_release(context);
2965 return;
2967 if (src.buffer_object)
2969 context = context_acquire(device, NULL);
2970 gl_info = context->gl_info;
2971 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
2972 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
2973 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2974 checkGLcall("Download PBO");
2975 context_release(context);
2976 return;
2978 memcpy(dst.addr, src.addr, size);
2981 /* Context activation is done by the caller. */
2982 static void surface_load_sysmem(struct wined3d_surface *surface,
2983 struct wined3d_context *context, DWORD dst_location)
2985 const struct wined3d_gl_info *gl_info = context->gl_info;
2986 struct wined3d_texture_sub_resource *sub_resource;
2988 wined3d_surface_prepare(surface, context, dst_location);
2990 sub_resource = surface_get_sub_resource(surface);
2991 if (sub_resource->locations & surface_simple_locations)
2993 surface_copy_simple_location(surface, dst_location);
2994 return;
2997 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
2998 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
3000 /* Download the surface to system memory. */
3001 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
3003 struct wined3d_texture *texture = surface->container;
3005 wined3d_texture_bind_and_dirtify(texture, context,
3006 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
3007 surface_download_data(surface, gl_info, dst_location);
3008 ++texture->download_count;
3010 return;
3013 if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3015 read_from_framebuffer(surface, context, dst_location);
3016 return;
3019 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
3020 surface, wined3d_debug_location(sub_resource->locations));
3023 /* Context activation is done by the caller. */
3024 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
3025 struct wined3d_context *context)
3027 struct wined3d_texture *texture = surface->container;
3028 RECT r;
3030 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3031 && wined3d_resource_is_offscreen(&texture->resource))
3033 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
3034 return WINED3DERR_INVALIDCALL;
3037 surface_get_rect(surface, NULL, &r);
3038 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
3039 surface_blt_to_drawable(texture->resource.device, context,
3040 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
3042 return WINED3D_OK;
3045 static HRESULT surface_load_texture(struct wined3d_surface *surface,
3046 struct wined3d_context *context, BOOL srgb)
3048 unsigned int width, height, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
3049 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3050 const struct wined3d_gl_info *gl_info = context->gl_info;
3051 struct wined3d_texture *texture = surface->container;
3052 struct wined3d_device *device = texture->resource.device;
3053 const struct wined3d_color_key_conversion *conversion;
3054 struct wined3d_texture_sub_resource *sub_resource;
3055 struct wined3d_bo_address data;
3056 struct wined3d_format format;
3057 POINT dst_point = {0, 0};
3058 BYTE *mem = NULL;
3059 RECT src_rect;
3061 sub_resource = surface_get_sub_resource(surface);
3062 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
3063 && wined3d_resource_is_offscreen(&texture->resource)
3064 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
3066 surface_load_fb_texture(surface, srgb, context);
3068 return WINED3D_OK;
3071 width = wined3d_texture_get_level_width(texture, surface->texture_level);
3072 height = wined3d_texture_get_level_height(texture, surface->texture_level);
3073 SetRect(&src_rect, 0, 0, width, height);
3075 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
3076 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
3077 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3078 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3079 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3081 if (srgb)
3082 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
3083 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
3084 else
3085 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
3086 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
3088 return WINED3D_OK;
3091 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
3092 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
3093 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3094 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3095 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3097 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
3098 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
3099 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
3101 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
3102 &src_rect, surface, dst_location, &src_rect);
3104 return WINED3D_OK;
3107 /* Upload from system memory */
3109 if (srgb)
3111 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
3112 == WINED3D_LOCATION_TEXTURE_RGB)
3114 /* Performance warning... */
3115 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
3116 surface_load_location(surface, context, surface->resource.map_binding);
3119 else
3121 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
3122 == WINED3D_LOCATION_TEXTURE_SRGB)
3124 /* Performance warning... */
3125 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
3126 surface_load_location(surface, context, surface->resource.map_binding);
3130 if (!(sub_resource->locations & surface_simple_locations))
3132 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
3133 /* Lets hope we get it from somewhere... */
3134 surface_load_location(surface, context, WINED3D_LOCATION_SYSMEM);
3137 wined3d_texture_prepare_texture(texture, context, srgb);
3138 wined3d_texture_bind_and_dirtify(texture, context, srgb);
3139 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
3141 format = *texture->resource.format;
3142 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
3143 format = *wined3d_get_format(gl_info, conversion->dst_format);
3145 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
3146 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
3147 * getting called. */
3148 if ((format.convert || conversion) && texture->sub_resources[sub_resource_idx].buffer_object)
3150 TRACE("Removing the pbo attached to surface %p.\n", surface);
3152 if (surface->flags & SFLAG_DIBSECTION)
3153 surface->resource.map_binding = WINED3D_LOCATION_DIB;
3154 else
3155 surface->resource.map_binding = WINED3D_LOCATION_SYSMEM;
3157 surface_load_location(surface, context, surface->resource.map_binding);
3158 wined3d_texture_remove_buffer_object(texture, sub_resource_idx, gl_info);
3161 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
3162 if (format.convert)
3164 /* This code is entered for texture formats which need a fixup. */
3165 format.byte_count = format.conv_byte_count;
3166 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
3168 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3170 ERR("Out of memory (%u).\n", dst_slice_pitch);
3171 context_release(context);
3172 return E_OUTOFMEMORY;
3174 format.convert(data.addr, mem, src_row_pitch, src_slice_pitch,
3175 dst_row_pitch, dst_slice_pitch, width, height, 1);
3176 src_row_pitch = dst_row_pitch;
3177 data.addr = mem;
3179 else if (conversion)
3181 /* This code is only entered for color keying fixups */
3182 struct wined3d_palette *palette = NULL;
3184 wined3d_format_calculate_pitch(&format, device->surface_alignment,
3185 width, height, &dst_row_pitch, &dst_slice_pitch);
3187 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3189 ERR("Out of memory (%u).\n", dst_slice_pitch);
3190 context_release(context);
3191 return E_OUTOFMEMORY;
3193 if (texture->swapchain && texture->swapchain->palette)
3194 palette = texture->swapchain->palette;
3195 conversion->convert(data.addr, src_row_pitch, mem, dst_row_pitch,
3196 width, height, palette, &texture->async.gl_color_key);
3197 src_row_pitch = dst_row_pitch;
3198 data.addr = mem;
3201 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
3202 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
3204 HeapFree(GetProcessHeap(), 0, mem);
3206 return WINED3D_OK;
3209 /* Context activation is done by the caller. */
3210 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
3211 DWORD dst_location)
3213 const RECT rect = {0, 0, surface->resource.width, surface->resource.height};
3214 DWORD locations = surface_get_sub_resource(surface)->locations;
3215 DWORD src_location;
3217 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
3218 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
3219 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
3220 src_location = WINED3D_LOCATION_RB_RESOLVED;
3221 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
3222 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
3223 else /* surface_blt_fbo will load the source location if necessary. */
3224 src_location = WINED3D_LOCATION_TEXTURE_RGB;
3226 surface_blt_fbo(surface->container->resource.device, context, WINED3D_TEXF_POINT,
3227 surface, src_location, &rect, surface, dst_location, &rect);
3230 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
3231 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
3233 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3234 struct wined3d_texture *texture = surface->container;
3235 struct wined3d_texture_sub_resource *sub_resource;
3236 HRESULT hr;
3238 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
3240 sub_resource = &texture->sub_resources[sub_resource_idx];
3241 if (sub_resource->locations & location && (!(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3242 || (surface->ds_current_size.cx == surface->resource.width
3243 && surface->ds_current_size.cy == surface->resource.height)))
3245 TRACE("Location (%#x) is already up to date.\n", location);
3246 return WINED3D_OK;
3249 if (WARN_ON(d3d))
3251 DWORD required_access = resource_access_from_location(location);
3252 if ((texture->resource.access_flags & required_access) != required_access)
3253 WARN("Operation requires %#x access, but surface only has %#x.\n",
3254 required_access, texture->resource.access_flags);
3257 if (sub_resource->locations & WINED3D_LOCATION_DISCARDED)
3259 TRACE("Surface previously discarded, nothing to do.\n");
3260 wined3d_surface_prepare(surface, context, location);
3261 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3262 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3263 goto done;
3266 if (!sub_resource->locations)
3268 ERR("Surface %p does not have any up to date location.\n", surface);
3269 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3270 return surface_load_location(surface, context, location);
3273 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3275 if ((location == WINED3D_LOCATION_TEXTURE_RGB && sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3276 || (location == WINED3D_LOCATION_DRAWABLE && sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB))
3278 surface_load_ds_location(surface, context, location);
3279 goto done;
3282 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
3283 wined3d_debug_location(sub_resource->locations), wined3d_debug_location(location));
3284 return WINED3DERR_INVALIDCALL;
3287 switch (location)
3289 case WINED3D_LOCATION_DIB:
3290 case WINED3D_LOCATION_USER_MEMORY:
3291 case WINED3D_LOCATION_SYSMEM:
3292 case WINED3D_LOCATION_BUFFER:
3293 surface_load_sysmem(surface, context, location);
3294 break;
3296 case WINED3D_LOCATION_DRAWABLE:
3297 if (FAILED(hr = surface_load_drawable(surface, context)))
3298 return hr;
3299 break;
3301 case WINED3D_LOCATION_RB_RESOLVED:
3302 case WINED3D_LOCATION_RB_MULTISAMPLE:
3303 surface_load_renderbuffer(surface, context, location);
3304 break;
3306 case WINED3D_LOCATION_TEXTURE_RGB:
3307 case WINED3D_LOCATION_TEXTURE_SRGB:
3308 if (FAILED(hr = surface_load_texture(surface, context,
3309 location == WINED3D_LOCATION_TEXTURE_SRGB)))
3310 return hr;
3311 break;
3313 default:
3314 ERR("Don't know how to handle location %#x.\n", location);
3315 break;
3318 done:
3319 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3321 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3323 surface->ds_current_size.cx = surface->resource.width;
3324 surface->ds_current_size.cy = surface->resource.height;
3327 if (location != WINED3D_LOCATION_SYSMEM && (sub_resource->locations & WINED3D_LOCATION_SYSMEM))
3328 surface_evict_sysmem(surface);
3330 return WINED3D_OK;
3333 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
3334 /* Context activation is done by the caller. */
3335 static void ffp_blit_free(struct wined3d_device *device) { }
3337 /* Context activation is done by the caller. */
3338 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3339 const struct wined3d_color_key *color_key)
3341 const struct wined3d_gl_info *gl_info = context->gl_info;
3343 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
3344 checkGLcall("glEnable(target)");
3346 return WINED3D_OK;
3349 /* Context activation is done by the caller. */
3350 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
3352 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
3353 checkGLcall("glDisable(GL_TEXTURE_2D)");
3354 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
3356 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
3357 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3359 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
3361 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
3362 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
3366 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
3367 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3368 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3369 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3371 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
3373 TRACE("Source or destination is in system memory.\n");
3374 return FALSE;
3377 switch (blit_op)
3379 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3380 if (d3d_info->shader_color_key)
3382 TRACE("Color keying requires converted textures.\n");
3383 return FALSE;
3385 case WINED3D_BLIT_OP_COLOR_BLIT:
3386 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3387 if (TRACE_ON(d3d))
3389 TRACE("Checking support for fixup:\n");
3390 dump_color_fixup_desc(src_format->color_fixup);
3393 /* We only support identity conversions. */
3394 if (!is_identity_fixup(src_format->color_fixup)
3395 || !is_identity_fixup(dst_format->color_fixup))
3397 TRACE("Fixups are not supported.\n");
3398 return FALSE;
3401 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3403 TRACE("Can only blit to render targets.\n");
3404 return FALSE;
3406 return TRUE;
3408 case WINED3D_BLIT_OP_COLOR_FILL:
3409 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3411 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
3412 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
3413 return FALSE;
3415 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3417 TRACE("Color fill not supported\n");
3418 return FALSE;
3421 /* FIXME: We should reject color fills on formats with fixups,
3422 * but this would break P8 color fills for example. */
3424 return TRUE;
3426 case WINED3D_BLIT_OP_DEPTH_FILL:
3427 return TRUE;
3429 default:
3430 TRACE("Unsupported blit_op=%d\n", blit_op);
3431 return FALSE;
3435 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
3436 const RECT *rect, const struct wined3d_color *color)
3438 const RECT draw_rect = {0, 0, view->width, view->height};
3439 struct wined3d_fb_state fb = {&view, NULL};
3441 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
3443 return WINED3D_OK;
3446 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
3447 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3448 float depth, DWORD stencil)
3450 const RECT draw_rect = {0, 0, view->width, view->height};
3451 struct wined3d_fb_state fb = {NULL, view};
3453 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, clear_flags, NULL, depth, stencil);
3455 return WINED3D_OK;
3458 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3459 struct wined3d_surface *src_surface, const RECT *src_rect,
3460 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3461 const struct wined3d_color_key *color_key)
3463 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3464 struct wined3d_texture *dst_texture = dst_surface->container;
3465 struct wined3d_texture *src_texture = src_surface->container;
3466 struct wined3d_context *context;
3468 /* Blit from offscreen surface to render target */
3469 struct wined3d_color_key old_blt_key = src_texture->async.src_blt_color_key;
3470 DWORD old_color_key_flags = src_texture->async.color_key_flags;
3472 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3474 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
3476 context = context_acquire(device, dst_surface);
3478 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3479 glEnable(GL_ALPHA_TEST);
3481 surface_blt_to_drawable(device, context, filter,
3482 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
3484 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3485 glDisable(GL_ALPHA_TEST);
3487 context_release(context);
3489 /* Restore the color key parameters */
3490 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
3491 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
3493 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_texture->resource.draw_binding);
3494 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_texture->resource.draw_binding);
3497 const struct blit_shader ffp_blit = {
3498 ffp_blit_alloc,
3499 ffp_blit_free,
3500 ffp_blit_set,
3501 ffp_blit_unset,
3502 ffp_blit_supported,
3503 ffp_blit_color_fill,
3504 ffp_blit_depth_fill,
3505 ffp_blit_blit_surface,
3508 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
3510 return WINED3D_OK;
3513 /* Context activation is done by the caller. */
3514 static void cpu_blit_free(struct wined3d_device *device)
3518 /* Context activation is done by the caller. */
3519 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3520 const struct wined3d_color_key *color_key)
3522 return WINED3D_OK;
3525 /* Context activation is done by the caller. */
3526 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
3530 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
3531 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3532 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3533 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3535 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
3537 return TRUE;
3540 return FALSE;
3543 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
3544 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
3545 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
3547 UINT row_block_count;
3548 const BYTE *src_row;
3549 BYTE *dst_row;
3550 UINT x, y;
3552 src_row = src_data;
3553 dst_row = dst_data;
3555 row_block_count = (update_w + format->block_width - 1) / format->block_width;
3557 if (!flags)
3559 for (y = 0; y < update_h; y += format->block_height)
3561 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
3562 src_row += src_pitch;
3563 dst_row += dst_pitch;
3566 return WINED3D_OK;
3569 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
3571 src_row += (((update_h / format->block_height) - 1) * src_pitch);
3573 switch (format->id)
3575 case WINED3DFMT_DXT1:
3576 for (y = 0; y < update_h; y += format->block_height)
3578 struct block
3580 WORD color[2];
3581 BYTE control_row[4];
3584 const struct block *s = (const struct block *)src_row;
3585 struct block *d = (struct block *)dst_row;
3587 for (x = 0; x < row_block_count; ++x)
3589 d[x].color[0] = s[x].color[0];
3590 d[x].color[1] = s[x].color[1];
3591 d[x].control_row[0] = s[x].control_row[3];
3592 d[x].control_row[1] = s[x].control_row[2];
3593 d[x].control_row[2] = s[x].control_row[1];
3594 d[x].control_row[3] = s[x].control_row[0];
3596 src_row -= src_pitch;
3597 dst_row += dst_pitch;
3599 return WINED3D_OK;
3601 case WINED3DFMT_DXT2:
3602 case WINED3DFMT_DXT3:
3603 for (y = 0; y < update_h; y += format->block_height)
3605 struct block
3607 WORD alpha_row[4];
3608 WORD color[2];
3609 BYTE control_row[4];
3612 const struct block *s = (const struct block *)src_row;
3613 struct block *d = (struct block *)dst_row;
3615 for (x = 0; x < row_block_count; ++x)
3617 d[x].alpha_row[0] = s[x].alpha_row[3];
3618 d[x].alpha_row[1] = s[x].alpha_row[2];
3619 d[x].alpha_row[2] = s[x].alpha_row[1];
3620 d[x].alpha_row[3] = s[x].alpha_row[0];
3621 d[x].color[0] = s[x].color[0];
3622 d[x].color[1] = s[x].color[1];
3623 d[x].control_row[0] = s[x].control_row[3];
3624 d[x].control_row[1] = s[x].control_row[2];
3625 d[x].control_row[2] = s[x].control_row[1];
3626 d[x].control_row[3] = s[x].control_row[0];
3628 src_row -= src_pitch;
3629 dst_row += dst_pitch;
3631 return WINED3D_OK;
3633 default:
3634 FIXME("Compressed flip not implemented for format %s.\n",
3635 debug_d3dformat(format->id));
3636 return E_NOTIMPL;
3640 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3641 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
3643 return E_NOTIMPL;
3646 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3647 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3648 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3649 enum wined3d_texture_filter_type filter)
3651 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
3652 const struct wined3d_format *src_format, *dst_format;
3653 struct wined3d_texture *converted_texture = NULL;
3654 unsigned int src_fmt_flags, dst_fmt_flags;
3655 struct wined3d_map_desc dst_map, src_map;
3656 const BYTE *sbase = NULL;
3657 HRESULT hr = WINED3D_OK;
3658 BOOL same_sub_resource;
3659 const BYTE *sbuf;
3660 BYTE *dbuf;
3661 int x, y;
3663 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3664 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3665 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
3666 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3668 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
3670 same_sub_resource = TRUE;
3671 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, NULL, 0);
3672 src_map = dst_map;
3673 src_format = dst_texture->resource.format;
3674 dst_format = src_format;
3675 dst_fmt_flags = dst_texture->resource.format_flags;
3676 src_fmt_flags = dst_fmt_flags;
3678 else
3680 same_sub_resource = FALSE;
3681 dst_format = dst_texture->resource.format;
3682 dst_fmt_flags = dst_texture->resource.format_flags;
3683 if (src_texture)
3685 if (dst_texture->resource.format->id != src_texture->resource.format->id)
3687 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
3689 /* The conv function writes a FIXME */
3690 WARN("Cannot convert source surface format to dest format.\n");
3691 goto release;
3693 src_texture = converted_texture;
3694 src_sub_resource_idx = 0;
3696 wined3d_resource_map(&src_texture->resource, src_sub_resource_idx, &src_map, NULL, WINED3D_MAP_READONLY);
3697 src_format = src_texture->resource.format;
3698 src_fmt_flags = src_texture->resource.format_flags;
3700 else
3702 src_format = dst_format;
3703 src_fmt_flags = dst_fmt_flags;
3706 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, dst_box, 0);
3709 bpp = dst_format->byte_count;
3710 src_height = src_box->bottom - src_box->top;
3711 src_width = src_box->right - src_box->left;
3712 dst_height = dst_box->bottom - dst_box->top;
3713 dst_width = dst_box->right - dst_box->left;
3714 row_byte_count = dst_width * bpp;
3716 if (src_texture)
3717 sbase = (BYTE *)src_map.data
3718 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
3719 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
3720 if (same_sub_resource)
3721 dbuf = (BYTE *)dst_map.data
3722 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
3723 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
3724 else
3725 dbuf = dst_map.data;
3727 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
3729 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
3731 if (same_sub_resource)
3733 FIXME("Only plain blits supported on compressed surfaces.\n");
3734 hr = E_NOTIMPL;
3735 goto release;
3738 if (src_height != dst_height || src_width != dst_width)
3740 WARN("Stretching not supported on compressed surfaces.\n");
3741 hr = WINED3DERR_INVALIDCALL;
3742 goto release;
3745 if (!wined3d_texture_check_block_align(src_texture,
3746 src_sub_resource_idx % src_texture->level_count, src_box))
3748 WARN("Source rectangle not block-aligned.\n");
3749 hr = WINED3DERR_INVALIDCALL;
3750 goto release;
3753 if (!wined3d_texture_check_block_align(dst_texture,
3754 dst_sub_resource_idx % dst_texture->level_count, dst_box))
3756 WARN("Destination rectangle not block-aligned.\n");
3757 hr = WINED3DERR_INVALIDCALL;
3758 goto release;
3761 hr = surface_cpu_blt_compressed(sbase, dbuf,
3762 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
3763 src_format, flags, fx);
3764 goto release;
3767 /* First, all the 'source-less' blits */
3768 if (flags & WINED3D_BLT_COLOR_FILL)
3770 hr = _Blt_ColorFill(dbuf, dst_width, dst_height, bpp, dst_map.row_pitch, fx->fill_color);
3771 flags &= ~WINED3D_BLT_COLOR_FILL;
3774 if (flags & WINED3D_BLT_DEPTH_FILL)
3775 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3777 /* Now the 'with source' blits. */
3778 if (src_texture)
3780 int sx, xinc, sy, yinc;
3782 if (!dst_width || !dst_height) /* Hmm... stupid program? */
3783 goto release;
3785 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3786 && (src_width != dst_width || src_height != dst_height))
3788 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3789 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
3792 xinc = (src_width << 16) / dst_width;
3793 yinc = (src_height << 16) / dst_height;
3795 if (!flags)
3797 /* No effects, we can cheat here. */
3798 if (dst_width == src_width)
3800 if (dst_height == src_height)
3802 /* No stretching in either direction. This needs to be as
3803 * fast as possible. */
3804 sbuf = sbase;
3806 /* Check for overlapping surfaces. */
3807 if (!same_sub_resource || dst_box->top < src_box->top
3808 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
3810 /* No overlap, or dst above src, so copy from top downwards. */
3811 for (y = 0; y < dst_height; ++y)
3813 memcpy(dbuf, sbuf, row_byte_count);
3814 sbuf += src_map.row_pitch;
3815 dbuf += dst_map.row_pitch;
3818 else if (dst_box->top > src_box->top)
3820 /* Copy from bottom upwards. */
3821 sbuf += src_map.row_pitch * dst_height;
3822 dbuf += dst_map.row_pitch * dst_height;
3823 for (y = 0; y < dst_height; ++y)
3825 sbuf -= src_map.row_pitch;
3826 dbuf -= dst_map.row_pitch;
3827 memcpy(dbuf, sbuf, row_byte_count);
3830 else
3832 /* Src and dst overlapping on the same line, use memmove. */
3833 for (y = 0; y < dst_height; ++y)
3835 memmove(dbuf, sbuf, row_byte_count);
3836 sbuf += src_map.row_pitch;
3837 dbuf += dst_map.row_pitch;
3841 else
3843 /* Stretching in y direction only. */
3844 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3846 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3847 memcpy(dbuf, sbuf, row_byte_count);
3848 dbuf += dst_map.row_pitch;
3852 else
3854 /* Stretching in X direction. */
3855 int last_sy = -1;
3856 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3858 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3860 if ((sy >> 16) == (last_sy >> 16))
3862 /* This source row is the same as last source row -
3863 * Copy the already stretched row. */
3864 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
3866 else
3868 #define STRETCH_ROW(type) \
3869 do { \
3870 const type *s = (const type *)sbuf; \
3871 type *d = (type *)dbuf; \
3872 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3873 d[x] = s[sx >> 16]; \
3874 } while(0)
3876 switch(bpp)
3878 case 1:
3879 STRETCH_ROW(BYTE);
3880 break;
3881 case 2:
3882 STRETCH_ROW(WORD);
3883 break;
3884 case 4:
3885 STRETCH_ROW(DWORD);
3886 break;
3887 case 3:
3889 const BYTE *s;
3890 BYTE *d = dbuf;
3891 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3893 DWORD pixel;
3895 s = sbuf + 3 * (sx >> 16);
3896 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3897 d[0] = (pixel ) & 0xff;
3898 d[1] = (pixel >> 8) & 0xff;
3899 d[2] = (pixel >> 16) & 0xff;
3900 d += 3;
3902 break;
3904 default:
3905 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
3906 hr = WINED3DERR_NOTAVAILABLE;
3907 goto error;
3909 #undef STRETCH_ROW
3911 dbuf += dst_map.row_pitch;
3912 last_sy = sy;
3916 else
3918 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3919 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3920 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3921 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3922 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3924 /* The color keying flags are checked for correctness in ddraw */
3925 if (flags & WINED3D_BLT_SRC_CKEY)
3927 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
3928 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3930 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3932 keylow = fx->src_color_key.color_space_low_value;
3933 keyhigh = fx->src_color_key.color_space_high_value;
3936 if (flags & WINED3D_BLT_DST_CKEY)
3938 /* Destination color keys are taken from the source surface! */
3939 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3940 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3942 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3944 destkeylow = fx->dst_color_key.color_space_low_value;
3945 destkeyhigh = fx->dst_color_key.color_space_high_value;
3948 if (bpp == 1)
3950 keymask = 0xff;
3952 else
3954 DWORD masks[3];
3955 get_color_masks(src_format, masks);
3956 keymask = masks[0]
3957 | masks[1]
3958 | masks[2];
3960 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3961 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3964 if (flags & WINED3D_BLT_FX)
3966 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3967 LONG tmpxy;
3968 dTopLeft = dbuf;
3969 dTopRight = dbuf + ((dst_width - 1) * bpp);
3970 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3971 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3973 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3975 /* I don't think we need to do anything about this flag */
3976 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3978 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3980 tmp = dTopRight;
3981 dTopRight = dTopLeft;
3982 dTopLeft = tmp;
3983 tmp = dBottomRight;
3984 dBottomRight = dBottomLeft;
3985 dBottomLeft = tmp;
3986 dstxinc = dstxinc * -1;
3988 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
3990 tmp = dTopLeft;
3991 dTopLeft = dBottomLeft;
3992 dBottomLeft = tmp;
3993 tmp = dTopRight;
3994 dTopRight = dBottomRight;
3995 dBottomRight = tmp;
3996 dstyinc = dstyinc * -1;
3998 if (fx->fx & WINEDDBLTFX_NOTEARING)
4000 /* I don't think we need to do anything about this flag */
4001 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
4003 if (fx->fx & WINEDDBLTFX_ROTATE180)
4005 tmp = dBottomRight;
4006 dBottomRight = dTopLeft;
4007 dTopLeft = tmp;
4008 tmp = dBottomLeft;
4009 dBottomLeft = dTopRight;
4010 dTopRight = tmp;
4011 dstxinc = dstxinc * -1;
4012 dstyinc = dstyinc * -1;
4014 if (fx->fx & WINEDDBLTFX_ROTATE270)
4016 tmp = dTopLeft;
4017 dTopLeft = dBottomLeft;
4018 dBottomLeft = dBottomRight;
4019 dBottomRight = dTopRight;
4020 dTopRight = tmp;
4021 tmpxy = dstxinc;
4022 dstxinc = dstyinc;
4023 dstyinc = tmpxy;
4024 dstxinc = dstxinc * -1;
4026 if (fx->fx & WINEDDBLTFX_ROTATE90)
4028 tmp = dTopLeft;
4029 dTopLeft = dTopRight;
4030 dTopRight = dBottomRight;
4031 dBottomRight = dBottomLeft;
4032 dBottomLeft = tmp;
4033 tmpxy = dstxinc;
4034 dstxinc = dstyinc;
4035 dstyinc = tmpxy;
4036 dstyinc = dstyinc * -1;
4038 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
4040 /* I don't think we need to do anything about this flag */
4041 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
4043 dbuf = dTopLeft;
4044 flags &= ~(WINED3D_BLT_FX);
4047 #define COPY_COLORKEY_FX(type) \
4048 do { \
4049 const type *s; \
4050 type *d = (type *)dbuf, *dx, tmp; \
4051 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
4053 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
4054 dx = d; \
4055 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
4057 tmp = s[sx >> 16]; \
4058 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
4059 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
4061 dx[0] = tmp; \
4063 dx = (type *)(((BYTE *)dx) + dstxinc); \
4065 d = (type *)(((BYTE *)d) + dstyinc); \
4067 } while(0)
4069 switch (bpp)
4071 case 1:
4072 COPY_COLORKEY_FX(BYTE);
4073 break;
4074 case 2:
4075 COPY_COLORKEY_FX(WORD);
4076 break;
4077 case 4:
4078 COPY_COLORKEY_FX(DWORD);
4079 break;
4080 case 3:
4082 const BYTE *s;
4083 BYTE *d = dbuf, *dx;
4084 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
4086 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
4087 dx = d;
4088 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
4090 DWORD pixel, dpixel = 0;
4091 s = sbuf + 3 * (sx>>16);
4092 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
4093 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
4094 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
4095 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
4097 dx[0] = (pixel ) & 0xff;
4098 dx[1] = (pixel >> 8) & 0xff;
4099 dx[2] = (pixel >> 16) & 0xff;
4101 dx += dstxinc;
4103 d += dstyinc;
4105 break;
4107 default:
4108 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
4109 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
4110 hr = WINED3DERR_NOTAVAILABLE;
4111 goto error;
4112 #undef COPY_COLORKEY_FX
4117 error:
4118 if (flags)
4119 FIXME(" Unsupported flags %#x.\n", flags);
4121 release:
4122 wined3d_resource_unmap(&dst_texture->resource, dst_sub_resource_idx);
4123 if (src_texture && !same_sub_resource)
4124 wined3d_resource_unmap(&src_texture->resource, src_sub_resource_idx);
4125 if (converted_texture)
4126 wined3d_texture_decref(converted_texture);
4128 return hr;
4131 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
4132 const RECT *rect, const struct wined3d_color *color)
4134 const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
4135 static const struct wined3d_box src_box;
4136 struct wined3d_blt_fx fx;
4138 fx.fill_color = wined3d_format_convert_from_float(view->format, color);
4139 return surface_cpu_blt(wined3d_texture_from_resource(view->resource), view->sub_resource_idx,
4140 &box, NULL, 0, &src_box, WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
4143 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
4144 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
4145 float depth, DWORD stencil)
4147 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
4148 return WINED3DERR_INVALIDCALL;
4151 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
4152 struct wined3d_surface *src_surface, const RECT *src_rect,
4153 struct wined3d_surface *dst_surface, const RECT *dst_rect,
4154 const struct wined3d_color_key *color_key)
4156 /* FIXME: Remove error returns from surface_blt_cpu. */
4157 ERR("Blit method not implemented by cpu_blit.\n");
4160 const struct blit_shader cpu_blit = {
4161 cpu_blit_alloc,
4162 cpu_blit_free,
4163 cpu_blit_set,
4164 cpu_blit_unset,
4165 cpu_blit_supported,
4166 cpu_blit_color_fill,
4167 cpu_blit_depth_fill,
4168 cpu_blit_blit_surface,
4171 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
4172 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
4173 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
4175 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
4176 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
4177 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
4178 struct wined3d_texture *dst_texture = dst_surface->container;
4179 struct wined3d_device *device = dst_texture->resource.device;
4180 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
4181 struct wined3d_texture *src_texture = NULL;
4182 unsigned int src_sub_resource_idx = 0;
4183 DWORD src_ds_flags, dst_ds_flags;
4184 BOOL scale, convert;
4186 static const DWORD simple_blit = WINED3D_BLT_ASYNC
4187 | WINED3D_BLT_COLOR_FILL
4188 | WINED3D_BLT_SRC_CKEY
4189 | WINED3D_BLT_SRC_CKEY_OVERRIDE
4190 | WINED3D_BLT_WAIT
4191 | WINED3D_BLT_DEPTH_FILL
4192 | WINED3D_BLT_DO_NOT_WAIT
4193 | WINED3D_BLT_ALPHA_TEST;
4195 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4196 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
4197 flags, fx, debug_d3dtexturefiltertype(filter));
4198 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
4200 if (fx)
4202 TRACE("fx %#x.\n", fx->fx);
4203 TRACE("fill_color 0x%08x.\n", fx->fill_color);
4204 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
4205 fx->dst_color_key.color_space_low_value,
4206 fx->dst_color_key.color_space_high_value);
4207 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
4208 fx->src_color_key.color_space_low_value,
4209 fx->src_color_key.color_space_high_value);
4212 if (src_surface)
4214 src_texture = src_surface->container;
4215 src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
4218 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count
4219 || (src_texture && src_texture->sub_resources[src_sub_resource_idx].map_count))
4221 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
4222 return WINEDDERR_SURFACEBUSY;
4225 if (dst_rect->left >= dst_rect->right || dst_rect->top >= dst_rect->bottom
4226 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
4227 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
4228 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
4229 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0)
4231 WARN("The application gave us a bad destination rectangle.\n");
4232 return WINEDDERR_INVALIDRECT;
4235 if (src_texture)
4237 if (src_rect->left >= src_rect->right || src_rect->top >= src_rect->bottom
4238 || src_rect->left > src_surface->resource.width || src_rect->left < 0
4239 || src_rect->top > src_surface->resource.height || src_rect->top < 0
4240 || src_rect->right > src_surface->resource.width || src_rect->right < 0
4241 || src_rect->bottom > src_surface->resource.height || src_rect->bottom < 0)
4243 WARN("The application gave us a bad source rectangle.\n");
4244 return WINEDDERR_INVALIDRECT;
4248 if (!fx || !(fx->fx))
4249 flags &= ~WINED3D_BLT_FX;
4251 if (flags & WINED3D_BLT_WAIT)
4252 flags &= ~WINED3D_BLT_WAIT;
4254 if (flags & WINED3D_BLT_ASYNC)
4256 static unsigned int once;
4258 if (!once++)
4259 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
4260 flags &= ~WINED3D_BLT_ASYNC;
4263 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
4264 if (flags & WINED3D_BLT_DO_NOT_WAIT)
4266 static unsigned int once;
4268 if (!once++)
4269 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
4270 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
4273 if (!device->d3d_initialized)
4275 WARN("D3D not initialized, using fallback.\n");
4276 goto cpu;
4279 /* We want to avoid invalidating the sysmem location for converted
4280 * surfaces, since otherwise we'd have to convert the data back when
4281 * locking them. */
4282 if (dst_texture->flags & WINED3D_TEXTURE_CONVERTED || dst_texture->resource.format->convert
4283 || wined3d_format_get_color_key_conversion(dst_texture, TRUE))
4285 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
4286 goto cpu;
4289 if (flags & ~simple_blit)
4291 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
4292 goto fallback;
4295 if (src_texture)
4296 src_swapchain = src_texture->swapchain;
4297 else
4298 src_swapchain = NULL;
4300 dst_swapchain = dst_texture->swapchain;
4302 /* This isn't strictly needed. FBO blits for example could deal with
4303 * cross-swapchain blits by first downloading the source to a texture
4304 * before switching to the destination context. We just have this here to
4305 * not have to deal with the issue, since cross-swapchain blits should be
4306 * rare. */
4307 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
4309 FIXME("Using fallback for cross-swapchain blit.\n");
4310 goto fallback;
4313 scale = src_texture
4314 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
4315 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
4316 convert = src_texture && src_texture->resource.format->id != dst_texture->resource.format->id;
4318 dst_ds_flags = dst_texture->resource.format_flags
4319 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4320 if (src_texture)
4321 src_ds_flags = src_texture->resource.format_flags
4322 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4323 else
4324 src_ds_flags = 0;
4326 if (src_ds_flags || dst_ds_flags)
4328 if (flags & WINED3D_BLT_DEPTH_FILL)
4330 float depth;
4332 TRACE("Depth fill.\n");
4334 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
4335 return WINED3DERR_INVALIDCALL;
4337 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
4338 return WINED3D_OK;
4340 else
4342 if (src_ds_flags != dst_ds_flags)
4344 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
4345 return WINED3DERR_INVALIDCALL;
4348 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_texture->resource.draw_binding,
4349 src_rect, dst_surface, dst_texture->resource.draw_binding, dst_rect)))
4350 return WINED3D_OK;
4353 else
4355 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
4356 const struct blit_shader *blitter;
4358 dst_sub_resource = surface_get_sub_resource(dst_surface);
4359 src_sub_resource = src_texture ? &src_texture->sub_resources[src_sub_resource_idx] : NULL;
4361 /* In principle this would apply to depth blits as well, but we don't
4362 * implement those in the CPU blitter at the moment. */
4363 if ((dst_sub_resource->locations & dst_surface->resource.map_binding)
4364 && (!src_texture || (src_sub_resource->locations & src_surface->resource.map_binding)))
4366 if (scale)
4367 TRACE("Not doing sysmem blit because of scaling.\n");
4368 else if (convert)
4369 TRACE("Not doing sysmem blit because of format conversion.\n");
4370 else
4371 goto cpu;
4374 if (flags & WINED3D_BLT_COLOR_FILL)
4376 struct wined3d_color color;
4377 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
4379 TRACE("Color fill.\n");
4381 if (!wined3d_format_convert_color_to_float(dst_texture->resource.format,
4382 palette, fx->fill_color, &color))
4383 goto fallback;
4385 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
4386 return WINED3D_OK;
4388 else
4390 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
4391 const struct wined3d_color_key *color_key = NULL;
4393 TRACE("Color blit.\n");
4394 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
4396 color_key = &fx->src_color_key;
4397 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4399 else if (flags & WINED3D_BLT_SRC_CKEY)
4401 color_key = &src_texture->async.src_blt_color_key;
4402 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4404 else if (flags & WINED3D_BLT_ALPHA_TEST)
4406 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
4408 else if ((src_sub_resource->locations & WINED3D_LOCATION_SYSMEM)
4409 && !(dst_sub_resource->locations & WINED3D_LOCATION_SYSMEM))
4411 /* Upload */
4412 if (scale)
4413 TRACE("Not doing upload because of scaling.\n");
4414 else if (convert)
4415 TRACE("Not doing upload because of format conversion.\n");
4416 else
4418 POINT dst_point = {dst_rect->left, dst_rect->top};
4420 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
4422 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
4424 struct wined3d_context *context = context_acquire(device, dst_surface);
4425 surface_load_location(dst_surface, context, dst_texture->resource.draw_binding);
4426 context_release(context);
4428 return WINED3D_OK;
4432 else if (dst_swapchain && dst_swapchain->back_buffers
4433 && dst_texture == dst_swapchain->front_buffer
4434 && src_texture == dst_swapchain->back_buffers[0])
4436 /* Use present for back -> front blits. The idea behind this is
4437 * that present is potentially faster than a blit, in particular
4438 * when FBO blits aren't available. Some ddraw applications like
4439 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4440 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4441 * applications can't blit directly to the frontbuffer. */
4442 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
4444 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4446 /* Set the swap effect to COPY, we don't want the backbuffer
4447 * to become undefined. */
4448 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
4449 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, 0);
4450 dst_swapchain->desc.swap_effect = swap_effect;
4452 return WINED3D_OK;
4455 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
4456 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4457 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
4459 struct wined3d_context *context;
4460 TRACE("Using FBO blit.\n");
4462 context = context_acquire(device, NULL);
4463 surface_blt_fbo(device, context, filter,
4464 src_surface, src_texture->resource.draw_binding, src_rect,
4465 dst_surface, dst_texture->resource.draw_binding, dst_rect);
4466 context_release(context);
4468 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx,
4469 dst_texture->resource.draw_binding);
4470 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx,
4471 ~dst_texture->resource.draw_binding);
4473 return WINED3D_OK;
4476 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
4477 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4478 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format);
4479 if (blitter)
4481 blitter->blit_surface(device, blit_op, filter, src_surface,
4482 src_rect, dst_surface, dst_rect, color_key);
4483 return WINED3D_OK;
4488 fallback:
4489 /* Special cases for render targets. */
4490 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
4491 return WINED3D_OK;
4493 cpu:
4494 return surface_cpu_blt(dst_texture, dst_sub_resource_idx, &dst_box,
4495 src_texture, src_sub_resource_idx, &src_box, flags, fx, filter);
4498 HRESULT wined3d_surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
4499 const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags)
4501 unsigned int sub_resource_idx = layer * container->level_count + level;
4502 struct wined3d_device *device = container->resource.device;
4503 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4504 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format);
4505 BOOL lockable = flags & WINED3D_TEXTURE_CREATE_MAPPABLE;
4506 UINT multisample_quality = desc->multisample_quality;
4507 unsigned int resource_size;
4508 HRESULT hr;
4510 if (container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
4512 unsigned int pow2_width = 1, pow2_height = 1;
4514 /* Find the nearest pow2 match. */
4515 while (pow2_width < desc->width)
4516 pow2_width <<= 1;
4517 while (pow2_height < desc->height)
4518 pow2_height <<= 1;
4520 surface->pow2Width = pow2_width;
4521 surface->pow2Height = pow2_height;
4523 else
4525 surface->pow2Width = desc->width;
4526 surface->pow2Height = desc->height;
4529 /* Quick lockable sanity check.
4530 * TODO: remove this after surfaces, usage and lockability have been debugged properly
4531 * this function is too deep to need to care about things like this.
4532 * Levels need to be checked too, since they all affect what can be done. */
4533 switch (desc->pool)
4535 case WINED3D_POOL_MANAGED:
4536 if (desc->usage & WINED3DUSAGE_DYNAMIC)
4537 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
4538 break;
4540 case WINED3D_POOL_DEFAULT:
4541 if (lockable && !(desc->usage & (WINED3DUSAGE_DYNAMIC
4542 | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4543 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
4544 break;
4546 case WINED3D_POOL_SCRATCH:
4547 case WINED3D_POOL_SYSTEM_MEM:
4548 break;
4550 default:
4551 FIXME("Unknown pool %#x.\n", desc->pool);
4552 break;
4555 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->pool != WINED3D_POOL_DEFAULT)
4556 FIXME("Trying to create a render target that isn't in the default pool.\n");
4558 /* FIXME: Check that the format is supported by the device. */
4560 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, 1);
4561 if (!resource_size)
4562 return WINED3DERR_INVALIDCALL;
4564 if (FAILED(hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE,
4565 format, desc->multisample_type, multisample_quality, desc->usage, desc->pool, desc->width, desc->height,
4566 1, resource_size, NULL, &wined3d_null_parent_ops, &surface_resource_ops)))
4568 WARN("Failed to initialize resource, returning %#x.\n", hr);
4569 return hr;
4572 surface->container = container;
4573 surface->texture_target = target;
4574 surface->texture_level = level;
4575 surface->texture_layer = layer;
4577 list_init(&surface->renderbuffers);
4578 list_init(&surface->overlays);
4580 /* Flags */
4581 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
4582 surface->flags |= SFLAG_DISCARD;
4583 if (lockable || desc->format == WINED3DFMT_D16_LOCKABLE)
4584 surface->resource.access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
4586 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4587 if (container->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4588 container->sub_resources[sub_resource_idx].locations = WINED3D_LOCATION_DISCARDED;
4590 if (wined3d_texture_use_pbo(container, gl_info))
4591 surface->resource.map_binding = WINED3D_LOCATION_BUFFER;
4593 /* Similar to lockable rendertargets above, creating the DIB section
4594 * during surface initialization prevents the sysmem pointer from changing
4595 * after a wined3d_texture_get_dc() call. */
4596 if ((desc->usage & WINED3DUSAGE_OWNDC) || (device->wined3d->flags & WINED3D_NO3D))
4598 if (FAILED(hr = surface_create_dib_section(surface)))
4600 wined3d_surface_cleanup(surface);
4601 return hr;
4603 surface->resource.map_binding = WINED3D_LOCATION_DIB;
4606 if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
4608 wined3d_resource_free_sysmem(&surface->resource);
4609 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_DIB);
4610 wined3d_texture_invalidate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4613 return hr;
4616 /* Context activation is done by the caller. Context may be NULL in
4617 * WINED3D_NO3D mode. */
4618 void wined3d_surface_prepare(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4620 struct wined3d_texture *texture = surface->container;
4622 switch (location)
4624 case WINED3D_LOCATION_SYSMEM:
4625 surface_prepare_system_memory(surface);
4626 break;
4628 case WINED3D_LOCATION_USER_MEMORY:
4629 if (!texture->user_memory)
4630 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
4631 break;
4633 case WINED3D_LOCATION_DIB:
4634 if (!surface->dib.bitmap_data)
4635 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
4636 break;
4638 case WINED3D_LOCATION_BUFFER:
4639 wined3d_texture_prepare_buffer_object(texture,
4640 surface_get_sub_resource_idx(surface), context->gl_info);
4641 break;
4643 case WINED3D_LOCATION_TEXTURE_RGB:
4644 wined3d_texture_prepare_texture(texture, context, FALSE);
4645 break;
4647 case WINED3D_LOCATION_TEXTURE_SRGB:
4648 wined3d_texture_prepare_texture(texture, context, TRUE);
4649 break;
4651 case WINED3D_LOCATION_RB_MULTISAMPLE:
4652 surface_prepare_rb(surface, context->gl_info, TRUE);
4653 break;
4655 case WINED3D_LOCATION_RB_RESOLVED:
4656 surface_prepare_rb(surface, context->gl_info, FALSE);
4657 break;