wined3d: Use the texture dimension helpers in wined3d_surface_blt().
[wine.git] / dlls / wined3d / surface.c
blobb2e508151a66534bb519bc140d37b1d639238e28
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 /* We should only get here on device reset/teardown for implicit
891 * resources. */
892 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
893 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~WINED3D_LOCATION_DISCARDED);
895 else
897 surface_load_location(surface, context, surface->resource.map_binding);
898 wined3d_texture_invalidate_location(texture, sub_resource_idx, ~surface->resource.map_binding);
901 /* Destroy fbo render buffers. This is needed for implicit render targets, for
902 * all application-created targets the application has to release the surface
903 * before calling _Reset
905 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
907 context_gl_resource_released(device, entry->id, TRUE);
908 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
909 list_remove(&entry->entry);
910 HeapFree(GetProcessHeap(), 0, entry);
912 list_init(&surface->renderbuffers);
913 surface->current_renderbuffer = NULL;
915 if (surface->rb_multisample)
917 context_gl_resource_released(device, surface->rb_multisample, TRUE);
918 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
919 surface->rb_multisample = 0;
921 if (surface->rb_resolved)
923 context_gl_resource_released(device, surface->rb_resolved, TRUE);
924 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
925 surface->rb_resolved = 0;
928 context_release(context);
930 resource_unload(resource);
933 static HRESULT surface_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx,
934 struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
936 ERR("Not supported on sub-resources.\n");
937 return WINED3DERR_INVALIDCALL;
940 static HRESULT surface_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx)
942 ERR("Not supported on sub-resources.\n");
943 return WINED3DERR_INVALIDCALL;
946 static const struct wined3d_resource_ops surface_resource_ops =
948 surface_resource_incref,
949 surface_resource_decref,
950 surface_unload,
951 surface_resource_sub_resource_map,
952 surface_resource_sub_resource_unmap,
955 /* This call just downloads data, the caller is responsible for binding the
956 * correct texture. */
957 /* Context activation is done by the caller. */
958 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
959 DWORD dst_location)
961 struct wined3d_texture *texture = surface->container;
962 const struct wined3d_format *format = texture->resource.format;
963 struct wined3d_bo_address data;
965 /* Only support read back of converted P8 surfaces. */
966 if (texture->flags & WINED3D_TEXTURE_CONVERTED && format->id != WINED3DFMT_P8_UINT)
968 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
969 return;
972 wined3d_texture_get_memory(texture, surface_get_sub_resource_idx(surface), &data, dst_location);
974 if (texture->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
976 TRACE("(%p) : Calling glGetCompressedTexImage level %d, format %#x, type %#x, data %p.\n",
977 surface, surface->texture_level, format->glFormat, format->glType, data.addr);
979 if (data.buffer_object)
981 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
982 checkGLcall("glBindBuffer");
983 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target, surface->texture_level, NULL));
984 checkGLcall("glGetCompressedTexImage");
985 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
986 checkGLcall("glBindBuffer");
988 else
990 GL_EXTCALL(glGetCompressedTexImage(surface->texture_target,
991 surface->texture_level, data.addr));
992 checkGLcall("glGetCompressedTexImage");
995 else
997 unsigned int dst_row_pitch, dst_slice_pitch;
998 unsigned int src_row_pitch, src_slice_pitch;
999 GLenum gl_format = format->glFormat;
1000 GLenum gl_type = format->glType;
1001 void *mem;
1003 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1005 wined3d_texture_get_pitch(texture, surface->texture_level, &dst_row_pitch, &dst_slice_pitch);
1006 wined3d_format_calculate_pitch(format, texture->resource.device->surface_alignment,
1007 surface->pow2Width, surface->pow2Height, &src_row_pitch, &src_slice_pitch);
1008 mem = HeapAlloc(GetProcessHeap(), 0, src_slice_pitch);
1010 else
1012 mem = data.addr;
1015 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1016 surface, surface->texture_level, gl_format, gl_type, mem);
1018 if (data.buffer_object)
1020 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1021 checkGLcall("glBindBuffer");
1023 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1024 gl_format, gl_type, NULL);
1025 checkGLcall("glGetTexImage");
1027 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1028 checkGLcall("glBindBuffer");
1030 else
1032 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1033 gl_format, gl_type, mem);
1034 checkGLcall("glGetTexImage");
1037 if (texture->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
1039 const BYTE *src_data;
1040 unsigned int h, y;
1041 BYTE *dst_data;
1043 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1044 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1045 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1047 * We're doing this...
1049 * instead of boxing the texture :
1050 * |<-texture width ->| -->pow2width| /\
1051 * |111111111111111111| | |
1052 * |222 Texture 222222| boxed empty | texture height
1053 * |3333 Data 33333333| | |
1054 * |444444444444444444| | \/
1055 * ----------------------------------- |
1056 * | boxed empty | boxed empty | pow2height
1057 * | | | \/
1058 * -----------------------------------
1061 * we're repacking the data to the expected texture width
1063 * |<-texture width ->| -->pow2width| /\
1064 * |111111111111111111222222222222222| |
1065 * |222333333333333333333444444444444| texture height
1066 * |444444 | |
1067 * | | \/
1068 * | | |
1069 * | empty | pow2height
1070 * | | \/
1071 * -----------------------------------
1073 * == is the same as
1075 * |<-texture width ->| /\
1076 * |111111111111111111|
1077 * |222222222222222222|texture height
1078 * |333333333333333333|
1079 * |444444444444444444| \/
1080 * --------------------
1082 * This also means that any references to surface memory should work with the data as if it were a
1083 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1085 * internally the texture is still stored in a boxed format so any references to textureName will
1086 * get a boxed texture with width pow2width and not a texture of width resource.width. */
1087 src_data = mem;
1088 dst_data = data.addr;
1089 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch, dst_row_pitch);
1090 h = wined3d_texture_get_level_height(texture, surface->texture_level);
1091 for (y = 0; y < h; ++y)
1093 memcpy(dst_data, src_data, dst_row_pitch);
1094 src_data += src_row_pitch;
1095 dst_data += dst_row_pitch;
1098 HeapFree(GetProcessHeap(), 0, mem);
1103 /* This call just uploads data, the caller is responsible for binding the
1104 * correct texture. */
1105 /* Context activation is done by the caller. */
1106 void wined3d_surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1107 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
1108 BOOL srgb, const struct wined3d_const_bo_address *data)
1110 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
1111 struct wined3d_texture *texture = surface->container;
1112 UINT update_w = src_rect->right - src_rect->left;
1113 UINT update_h = src_rect->bottom - src_rect->top;
1115 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1116 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
1117 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
1119 if (texture->sub_resources[sub_resource_idx].map_count)
1121 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1122 texture->flags |= WINED3D_TEXTURE_PIN_SYSMEM;
1125 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_HEIGHT_SCALE)
1127 update_h *= format->height_scale.numerator;
1128 update_h /= format->height_scale.denominator;
1131 if (data->buffer_object)
1133 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, data->buffer_object));
1134 checkGLcall("glBindBuffer");
1137 if (format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_COMPRESSED)
1139 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1, 1);
1140 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
1141 const BYTE *addr = data->addr;
1142 GLenum internal;
1144 addr += (src_rect->top / format->block_height) * src_pitch;
1145 addr += (src_rect->left / format->block_width) * format->block_byte_count;
1147 if (srgb)
1148 internal = format->glGammaInternal;
1149 else if (texture->resource.usage & WINED3DUSAGE_RENDERTARGET
1150 && wined3d_resource_is_offscreen(&texture->resource))
1151 internal = format->rtInternal;
1152 else
1153 internal = format->glInternal;
1155 TRACE("glCompressedTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, "
1156 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
1157 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
1159 if (row_length == src_pitch)
1161 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1162 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
1164 else
1166 UINT row, y;
1168 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1169 * can't use the unpack row length like for glTexSubImage2D. */
1170 for (row = 0, y = dst_point->y; row < row_count; ++row)
1172 GL_EXTCALL(glCompressedTexSubImage2D(surface->texture_target, surface->texture_level,
1173 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
1174 y += format->block_height;
1175 addr += src_pitch;
1178 checkGLcall("glCompressedTexSubImage2D");
1180 else
1182 const BYTE *addr = data->addr;
1184 addr += src_rect->top * src_pitch;
1185 addr += src_rect->left * format->byte_count;
1187 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1188 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
1189 update_w, update_h, format->glFormat, format->glType, addr);
1191 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
1192 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
1193 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
1194 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1195 checkGLcall("glTexSubImage2D");
1198 if (data->buffer_object)
1200 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
1201 checkGLcall("glBindBuffer");
1204 if (wined3d_settings.strict_draw_ordering)
1205 gl_info->gl_ops.gl.p_glFlush();
1207 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1209 struct wined3d_device *device = texture->resource.device;
1210 unsigned int i;
1212 for (i = 0; i < device->context_count; ++i)
1214 context_surface_update(device->contexts[i], surface);
1219 static BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
1221 struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
1223 return wined3d_texture_check_block_align(surface->container, surface->texture_level, &box);
1226 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
1227 struct wined3d_surface *src_surface, const RECT *src_rect)
1229 unsigned int src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
1230 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
1231 struct wined3d_texture *src_texture = src_surface->container;
1232 struct wined3d_texture *dst_texture = dst_surface->container;
1233 unsigned int src_row_pitch, src_slice_pitch;
1234 const struct wined3d_format *src_format;
1235 const struct wined3d_format *dst_format;
1236 unsigned int src_fmt_flags, dst_fmt_flags;
1237 const struct wined3d_gl_info *gl_info;
1238 struct wined3d_context *context;
1239 struct wined3d_bo_address data;
1240 UINT update_w, update_h;
1241 UINT dst_w, dst_h;
1242 RECT r, dst_rect;
1243 POINT p;
1245 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1246 dst_surface, wine_dbgstr_point(dst_point),
1247 src_surface, wine_dbgstr_rect(src_rect));
1249 src_format = src_texture->resource.format;
1250 dst_format = dst_texture->resource.format;
1251 src_fmt_flags = src_texture->resource.format_flags;
1252 dst_fmt_flags = dst_texture->resource.format_flags;
1254 if (src_format->id != dst_format->id)
1256 WARN("Source and destination surfaces should have the same format.\n");
1257 return WINED3DERR_INVALIDCALL;
1260 if (!dst_point)
1262 p.x = 0;
1263 p.y = 0;
1264 dst_point = &p;
1266 else if (dst_point->x < 0 || dst_point->y < 0)
1268 WARN("Invalid destination point.\n");
1269 return WINED3DERR_INVALIDCALL;
1272 if (!src_rect)
1274 SetRect(&r, 0, 0, wined3d_texture_get_level_width(src_texture, src_surface->texture_level),
1275 wined3d_texture_get_level_height(src_texture, src_surface->texture_level));
1276 src_rect = &r;
1278 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
1279 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
1281 WARN("Invalid source rectangle.\n");
1282 return WINED3DERR_INVALIDCALL;
1285 dst_w = wined3d_texture_get_level_width(dst_texture, dst_surface->texture_level);
1286 dst_h = wined3d_texture_get_level_height(dst_texture, dst_surface->texture_level);
1288 update_w = src_rect->right - src_rect->left;
1289 update_h = src_rect->bottom - src_rect->top;
1291 if (update_w > dst_w || dst_point->x > dst_w - update_w
1292 || update_h > dst_h || dst_point->y > dst_h - update_h)
1294 WARN("Destination out of bounds.\n");
1295 return WINED3DERR_INVALIDCALL;
1298 if ((src_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(src_surface, src_rect))
1300 WARN("Source rectangle not block-aligned.\n");
1301 return WINED3DERR_INVALIDCALL;
1304 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
1305 if ((dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align_rect(dst_surface, &dst_rect))
1307 WARN("Destination rectangle not block-aligned.\n");
1308 return WINED3DERR_INVALIDCALL;
1311 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1312 if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_texture, FALSE))
1313 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
1315 context = context_acquire(dst_texture->resource.device, NULL);
1316 gl_info = context->gl_info;
1318 /* Only load the surface for partial updates. For newly allocated texture
1319 * the texture wouldn't be the current location, and we'd upload zeroes
1320 * just to overwrite them again. */
1321 if (update_w == dst_w && update_h == dst_h)
1322 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1323 else
1324 surface_load_location(dst_surface, context, WINED3D_LOCATION_TEXTURE_RGB);
1325 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1327 wined3d_texture_get_memory(src_texture, src_sub_resource_idx, &data,
1328 src_texture->sub_resources[src_sub_resource_idx].locations);
1329 wined3d_texture_get_pitch(src_texture, src_surface->texture_level, &src_row_pitch, &src_slice_pitch);
1331 wined3d_surface_upload_data(dst_surface, gl_info, src_format, src_rect,
1332 src_row_pitch, dst_point, FALSE, wined3d_const_bo_address(&data));
1334 context_release(context);
1336 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
1337 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
1339 return WINED3D_OK;
1342 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1343 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1344 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1345 /* Context activation is done by the caller. */
1346 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
1348 const struct wined3d_gl_info *gl_info = &surface->container->resource.device->adapter->gl_info;
1349 struct wined3d_renderbuffer_entry *entry;
1350 GLuint renderbuffer = 0;
1351 unsigned int src_width, src_height;
1352 unsigned int width, height;
1354 if (rt && rt->container->resource.format->id != WINED3DFMT_NULL)
1356 width = rt->pow2Width;
1357 height = rt->pow2Height;
1359 else
1361 width = surface->pow2Width;
1362 height = surface->pow2Height;
1365 src_width = surface->pow2Width;
1366 src_height = surface->pow2Height;
1368 /* A depth stencil smaller than the render target is not valid */
1369 if (width > src_width || height > src_height) return;
1371 /* Remove any renderbuffer set if the sizes match */
1372 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1373 || (width == src_width && height == src_height))
1375 surface->current_renderbuffer = NULL;
1376 return;
1379 /* Look if we've already got a renderbuffer of the correct dimensions */
1380 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1382 if (entry->width == width && entry->height == height)
1384 renderbuffer = entry->id;
1385 surface->current_renderbuffer = entry;
1386 break;
1390 if (!renderbuffer)
1392 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1393 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1394 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1395 surface->container->resource.format->glInternal, width, height);
1397 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
1398 entry->width = width;
1399 entry->height = height;
1400 entry->id = renderbuffer;
1401 list_add_head(&surface->renderbuffers, &entry->entry);
1403 surface->current_renderbuffer = entry;
1406 checkGLcall("set_compatible_renderbuffer");
1409 /* See also float_16_to_32() in wined3d_private.h */
1410 static inline unsigned short float_32_to_16(const float *in)
1412 int exp = 0;
1413 float tmp = fabsf(*in);
1414 unsigned int mantissa;
1415 unsigned short ret;
1417 /* Deal with special numbers */
1418 if (*in == 0.0f)
1419 return 0x0000;
1420 if (isnan(*in))
1421 return 0x7c01;
1422 if (isinf(*in))
1423 return (*in < 0.0f ? 0xfc00 : 0x7c00);
1425 if (tmp < (float)(1u << 10))
1429 tmp = tmp * 2.0f;
1430 exp--;
1431 } while (tmp < (float)(1u << 10));
1433 else if (tmp >= (float)(1u << 11))
1437 tmp /= 2.0f;
1438 exp++;
1439 } while (tmp >= (float)(1u << 11));
1442 mantissa = (unsigned int)tmp;
1443 if (tmp - mantissa >= 0.5f)
1444 ++mantissa; /* Round to nearest, away from zero. */
1446 exp += 10; /* Normalize the mantissa. */
1447 exp += 15; /* Exponent is encoded with excess 15. */
1449 if (exp > 30) /* too big */
1451 ret = 0x7c00; /* INF */
1453 else if (exp <= 0)
1455 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1456 while (exp <= 0)
1458 mantissa = mantissa >> 1;
1459 ++exp;
1461 ret = mantissa & 0x3ff;
1463 else
1465 ret = (exp << 10) | (mantissa & 0x3ff);
1468 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
1469 return ret;
1472 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
1473 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1475 unsigned short *dst_s;
1476 const float *src_f;
1477 unsigned int x, y;
1479 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1481 for (y = 0; y < h; ++y)
1483 src_f = (const float *)(src + y * pitch_in);
1484 dst_s = (unsigned short *) (dst + y * pitch_out);
1485 for (x = 0; x < w; ++x)
1487 dst_s[x] = float_32_to_16(src_f + x);
1492 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
1493 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1495 static const unsigned char convert_5to8[] =
1497 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1498 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1499 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1500 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1502 static const unsigned char convert_6to8[] =
1504 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1505 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1506 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1507 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1508 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1509 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1510 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1511 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1513 unsigned int x, y;
1515 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1517 for (y = 0; y < h; ++y)
1519 const WORD *src_line = (const WORD *)(src + y * pitch_in);
1520 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1521 for (x = 0; x < w; ++x)
1523 WORD pixel = src_line[x];
1524 dst_line[x] = 0xff000000u
1525 | convert_5to8[(pixel & 0xf800u) >> 11] << 16
1526 | convert_6to8[(pixel & 0x07e0u) >> 5] << 8
1527 | convert_5to8[(pixel & 0x001fu)];
1532 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1533 * in both cases we're just setting the X / Alpha channel to 0xff. */
1534 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
1535 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1537 unsigned int x, y;
1539 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1541 for (y = 0; y < h; ++y)
1543 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
1544 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1546 for (x = 0; x < w; ++x)
1548 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
1553 static inline BYTE cliptobyte(int x)
1555 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
1558 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
1559 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1561 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1562 unsigned int x, y;
1564 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
1566 for (y = 0; y < h; ++y)
1568 const BYTE *src_line = src + y * pitch_in;
1569 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
1570 for (x = 0; x < w; ++x)
1572 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1573 * C = Y - 16; D = U - 128; E = V - 128;
1574 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1575 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1576 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1577 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1578 * U and V are shared between the pixels. */
1579 if (!(x & 1)) /* For every even pixel, read new U and V. */
1581 d = (int) src_line[1] - 128;
1582 e = (int) src_line[3] - 128;
1583 r2 = 409 * e + 128;
1584 g2 = - 100 * d - 208 * e + 128;
1585 b2 = 516 * d + 128;
1587 c2 = 298 * ((int) src_line[0] - 16);
1588 dst_line[x] = 0xff000000
1589 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
1590 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
1591 | cliptobyte((c2 + b2) >> 8); /* blue */
1592 /* Scale RGB values to 0..255 range,
1593 * then clip them if still not in range (may be negative),
1594 * then shift them within DWORD if necessary. */
1595 src_line += 2;
1600 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
1601 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
1603 unsigned int x, y;
1604 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
1606 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
1608 for (y = 0; y < h; ++y)
1610 const BYTE *src_line = src + y * pitch_in;
1611 WORD *dst_line = (WORD *)(dst + y * pitch_out);
1612 for (x = 0; x < w; ++x)
1614 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1615 * C = Y - 16; D = U - 128; E = V - 128;
1616 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1617 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1618 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1619 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1620 * U and V are shared between the pixels. */
1621 if (!(x & 1)) /* For every even pixel, read new U and V. */
1623 d = (int) src_line[1] - 128;
1624 e = (int) src_line[3] - 128;
1625 r2 = 409 * e + 128;
1626 g2 = - 100 * d - 208 * e + 128;
1627 b2 = 516 * d + 128;
1629 c2 = 298 * ((int) src_line[0] - 16);
1630 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
1631 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
1632 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
1633 /* Scale RGB values to 0..255 range,
1634 * then clip them if still not in range (may be negative),
1635 * then shift them within DWORD if necessary. */
1636 src_line += 2;
1641 struct d3dfmt_converter_desc
1643 enum wined3d_format_id from, to;
1644 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
1647 static const struct d3dfmt_converter_desc converters[] =
1649 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
1650 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
1651 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1652 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
1653 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
1654 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
1657 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
1658 enum wined3d_format_id to)
1660 unsigned int i;
1662 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
1664 if (converters[i].from == from && converters[i].to == to)
1665 return &converters[i];
1668 return NULL;
1671 static struct wined3d_texture *surface_convert_format(struct wined3d_texture *src_texture,
1672 unsigned int sub_resource_idx, const struct wined3d_format *dst_format)
1674 const struct wined3d_format *src_format = src_texture->resource.format;
1675 struct wined3d_device *device = src_texture->resource.device;
1676 const struct d3dfmt_converter_desc *conv = NULL;
1677 struct wined3d_texture *dst_texture;
1678 struct wined3d_resource_desc desc;
1679 struct wined3d_map_desc src_map;
1681 if (!(conv = find_converter(src_format->id, dst_format->id)) && (!device->d3d_initialized
1682 || !is_identity_fixup(src_format->color_fixup) || src_format->convert
1683 || !is_identity_fixup(dst_format->color_fixup) || dst_format->convert))
1685 FIXME("Cannot find a conversion function from format %s to %s.\n",
1686 debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
1687 return NULL;
1690 /* FIXME: Multisampled conversion? */
1691 wined3d_resource_get_desc(src_texture->sub_resources[sub_resource_idx].resource, &desc);
1692 desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1693 desc.format = dst_format->id;
1694 desc.usage = 0;
1695 desc.pool = WINED3D_POOL_SCRATCH;
1696 if (FAILED(wined3d_texture_create(device, &desc, 1,
1697 WINED3D_TEXTURE_CREATE_MAPPABLE | WINED3D_TEXTURE_CREATE_DISCARD,
1698 NULL, NULL, &wined3d_null_parent_ops, &dst_texture)))
1700 ERR("Failed to create a destination texture for conversion.\n");
1701 return NULL;
1704 memset(&src_map, 0, sizeof(src_map));
1705 if (FAILED(wined3d_resource_map(&src_texture->resource, sub_resource_idx,
1706 &src_map, NULL, WINED3D_MAP_READONLY)))
1708 ERR("Failed to map the source texture.\n");
1709 wined3d_texture_decref(dst_texture);
1710 return NULL;
1712 if (conv)
1714 struct wined3d_map_desc dst_map;
1716 memset(&dst_map, 0, sizeof(dst_map));
1717 if (FAILED(wined3d_resource_map(&dst_texture->resource, 0, &dst_map, NULL, 0)))
1719 ERR("Failed to map the destination texture.\n");
1720 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1721 wined3d_texture_decref(dst_texture);
1722 return NULL;
1725 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch, desc.width, desc.height);
1727 wined3d_resource_unmap(&dst_texture->resource, 0);
1729 else
1731 struct wined3d_bo_address data = {0, src_map.data};
1732 RECT src_rect = {0, 0, desc.width, desc.height};
1733 const struct wined3d_gl_info *gl_info;
1734 struct wined3d_context *context;
1735 POINT dst_point = {0, 0};
1737 TRACE("Using upload conversion.\n");
1738 context = context_acquire(device, NULL);
1739 gl_info = context->gl_info;
1741 wined3d_texture_prepare_texture(dst_texture, context, FALSE);
1742 wined3d_texture_bind_and_dirtify(dst_texture, context, FALSE);
1743 wined3d_surface_upload_data(dst_texture->sub_resources[0].u.surface, gl_info, src_format,
1744 &src_rect, src_map.row_pitch, &dst_point, FALSE, wined3d_const_bo_address(&data));
1746 context_release(context);
1748 wined3d_texture_validate_location(dst_texture, 0, WINED3D_LOCATION_TEXTURE_RGB);
1749 wined3d_texture_invalidate_location(dst_texture, 0, ~WINED3D_LOCATION_TEXTURE_RGB);
1751 wined3d_resource_unmap(&src_texture->resource, sub_resource_idx);
1753 return dst_texture;
1756 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
1757 unsigned int bpp, UINT pitch, DWORD color)
1759 BYTE *first;
1760 unsigned int x, y;
1762 /* Do first row */
1764 #define COLORFILL_ROW(type) \
1765 do { \
1766 type *d = (type *)buf; \
1767 for (x = 0; x < width; ++x) \
1768 d[x] = (type)color; \
1769 } while(0)
1771 switch (bpp)
1773 case 1:
1774 COLORFILL_ROW(BYTE);
1775 break;
1777 case 2:
1778 COLORFILL_ROW(WORD);
1779 break;
1781 case 3:
1783 BYTE *d = buf;
1784 for (x = 0; x < width; ++x, d += 3)
1786 d[0] = (color ) & 0xff;
1787 d[1] = (color >> 8) & 0xff;
1788 d[2] = (color >> 16) & 0xff;
1790 break;
1792 case 4:
1793 COLORFILL_ROW(DWORD);
1794 break;
1796 default:
1797 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
1798 return WINED3DERR_NOTAVAILABLE;
1801 #undef COLORFILL_ROW
1803 /* Now copy first row. */
1804 first = buf;
1805 for (y = 1; y < height; ++y)
1807 buf += pitch;
1808 memcpy(buf, first, width * bpp);
1811 return WINED3D_OK;
1814 static void read_from_framebuffer(struct wined3d_surface *surface,
1815 struct wined3d_context *old_ctx, DWORD dst_location)
1817 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
1818 struct wined3d_texture *texture = surface->container;
1819 struct wined3d_device *device = texture->resource.device;
1820 const struct wined3d_gl_info *gl_info;
1821 struct wined3d_context *context = old_ctx;
1822 struct wined3d_surface *restore_rt = NULL;
1823 unsigned int row_pitch, slice_pitch;
1824 unsigned int width, height;
1825 BYTE *mem;
1826 BYTE *row, *top, *bottom;
1827 int i;
1828 BOOL srcIsUpsideDown;
1829 struct wined3d_bo_address data;
1831 wined3d_texture_get_memory(texture, sub_resource_idx, &data, dst_location);
1833 restore_rt = context_get_rt_surface(old_ctx);
1834 if (restore_rt != surface)
1835 context = context_acquire(device, surface);
1836 else
1837 restore_rt = NULL;
1839 context_apply_blit_state(context, device);
1840 gl_info = context->gl_info;
1842 /* Select the correct read buffer, and give some debug output.
1843 * There is no need to keep track of the current read buffer or reset it, every part of the code
1844 * that reads sets the read buffer as desired.
1846 if (wined3d_resource_is_offscreen(&texture->resource))
1848 /* Mapping the primary render target which is not on a swapchain.
1849 * Read from the back buffer. */
1850 TRACE("Mapping offscreen render target.\n");
1851 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1852 srcIsUpsideDown = TRUE;
1854 else
1856 /* Onscreen surfaces are always part of a swapchain */
1857 GLenum buffer = wined3d_texture_get_gl_buffer(texture);
1858 TRACE("Mapping %#x buffer.\n", buffer);
1859 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1860 checkGLcall("glReadBuffer");
1861 srcIsUpsideDown = FALSE;
1864 if (data.buffer_object)
1866 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, data.buffer_object));
1867 checkGLcall("glBindBuffer");
1870 wined3d_texture_get_pitch(texture, surface->texture_level, &row_pitch, &slice_pitch);
1872 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1873 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, row_pitch / texture->resource.format->byte_count);
1874 checkGLcall("glPixelStorei");
1876 width = wined3d_texture_get_level_width(texture, surface->texture_level);
1877 height = wined3d_texture_get_level_height(texture, surface->texture_level);
1878 gl_info->gl_ops.gl.p_glReadPixels(0, 0, width, height,
1879 texture->resource.format->glFormat,
1880 texture->resource.format->glType, data.addr);
1881 checkGLcall("glReadPixels");
1883 /* Reset previous pixel store pack state */
1884 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1885 checkGLcall("glPixelStorei");
1887 if (!srcIsUpsideDown)
1889 /* glReadPixels returns the image upside down, and there is no way to
1890 * prevent this. Flip the lines in software. */
1892 if (!(row = HeapAlloc(GetProcessHeap(), 0, row_pitch)))
1893 goto error;
1895 if (data.buffer_object)
1897 mem = GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE));
1898 checkGLcall("glMapBuffer");
1900 else
1901 mem = data.addr;
1903 top = mem;
1904 bottom = mem + row_pitch * (height - 1);
1905 for (i = 0; i < height / 2; i++)
1907 memcpy(row, top, row_pitch);
1908 memcpy(top, bottom, row_pitch);
1909 memcpy(bottom, row, row_pitch);
1910 top += row_pitch;
1911 bottom -= row_pitch;
1913 HeapFree(GetProcessHeap(), 0, row);
1915 if (data.buffer_object)
1916 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
1919 error:
1920 if (data.buffer_object)
1922 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
1923 checkGLcall("glBindBuffer");
1926 if (restore_rt)
1927 context_restore(context, restore_rt);
1930 /* Read the framebuffer contents into a texture. Note that this function
1931 * doesn't do any kind of flipping. Using this on an onscreen surface will
1932 * result in a flipped D3D texture.
1934 * Context activation is done by the caller. This function may temporarily
1935 * switch to a different context and restore the original one before return. */
1936 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb, struct wined3d_context *old_ctx)
1938 struct wined3d_texture *texture = surface->container;
1939 struct wined3d_device *device = texture->resource.device;
1940 const struct wined3d_gl_info *gl_info;
1941 struct wined3d_context *context = old_ctx;
1942 struct wined3d_surface *restore_rt = NULL;
1944 restore_rt = context_get_rt_surface(old_ctx);
1945 if (restore_rt != surface)
1946 context = context_acquire(device, surface);
1947 else
1948 restore_rt = NULL;
1950 gl_info = context->gl_info;
1951 device_invalidate_state(device, STATE_FRAMEBUFFER);
1953 wined3d_texture_prepare_texture(texture, context, srgb);
1954 wined3d_texture_bind_and_dirtify(texture, context, srgb);
1956 TRACE("Reading back offscreen render target %p.\n", surface);
1958 if (wined3d_resource_is_offscreen(&texture->resource))
1959 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
1960 else
1961 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture));
1962 checkGLcall("glReadBuffer");
1964 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
1965 0, 0, 0, 0, wined3d_texture_get_level_width(texture, surface->texture_level),
1966 wined3d_texture_get_level_height(texture, surface->texture_level));
1967 checkGLcall("glCopyTexSubImage2D");
1969 if (restore_rt)
1970 context_restore(context, restore_rt);
1973 static void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
1975 struct wined3d_texture *texture = surface->container;
1976 const struct wined3d_format *format = texture->resource.format;
1978 if (multisample)
1980 DWORD samples;
1982 if (surface->rb_multisample)
1983 return;
1985 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
1986 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
1987 * to GL_NV_framebuffer_multisample_coverage.
1989 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
1990 * but it does not have an equivalent OpenGL extension. */
1992 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
1993 * as the count of advertised multisample types for the surface format. */
1994 if (texture->resource.multisample_type == WINED3D_MULTISAMPLE_NON_MASKABLE)
1996 unsigned int i, count = 0;
1998 for (i = 0; i < sizeof(format->multisample_types) * 8; ++i)
2000 if (format->multisample_types & 1u << i)
2002 if (texture->resource.multisample_quality == count++)
2003 break;
2006 samples = i + 1;
2008 else
2010 samples = texture->resource.multisample_type;
2013 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
2014 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
2015 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
2016 format->glInternal, surface->pow2Width, surface->pow2Height);
2017 checkGLcall("glRenderbufferStorageMultisample()");
2018 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
2020 else
2022 if (surface->rb_resolved)
2023 return;
2025 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
2026 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
2027 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, format->glInternal,
2028 surface->pow2Width, surface->pow2Height);
2029 checkGLcall("glRenderbufferStorage()");
2030 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
2034 /* Does a direct frame buffer -> texture copy. Stretching is done with single
2035 * pixel copy calls. */
2036 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2037 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2039 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2040 struct wined3d_texture *src_texture = src_surface->container;
2041 struct wined3d_texture *dst_texture = dst_surface->container;
2042 struct wined3d_device *device = dst_texture->resource.device;
2043 const struct wined3d_gl_info *gl_info;
2044 float xrel, yrel;
2045 struct wined3d_context *context;
2046 BOOL upsidedown = FALSE;
2047 RECT dst_rect = *dst_rect_in;
2048 unsigned int src_height;
2050 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2051 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2053 if(dst_rect.top > dst_rect.bottom) {
2054 UINT tmp = dst_rect.bottom;
2055 dst_rect.bottom = dst_rect.top;
2056 dst_rect.top = tmp;
2057 upsidedown = TRUE;
2060 context = context_acquire(device, src_surface);
2061 gl_info = context->gl_info;
2062 context_apply_blit_state(context, device);
2063 wined3d_texture_load(dst_texture, context, FALSE);
2065 /* Bind the target texture */
2066 context_bind_texture(context, dst_texture->target, dst_texture->texture_rgb.name);
2067 if (wined3d_resource_is_offscreen(&src_texture->resource))
2069 TRACE("Reading from an offscreen target\n");
2070 upsidedown = !upsidedown;
2071 gl_info->gl_ops.gl.p_glReadBuffer(context_get_offscreen_gl_buffer(context));
2073 else
2075 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2077 checkGLcall("glReadBuffer");
2079 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
2080 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
2082 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2084 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2086 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2087 ERR("Texture filtering not supported in direct blit.\n");
2089 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
2090 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2092 ERR("Texture filtering not supported in direct blit\n");
2095 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2096 if (upsidedown
2097 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2098 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
2100 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
2101 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2102 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
2103 src_rect->left, src_height - src_rect->bottom,
2104 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2106 else
2108 LONG row;
2109 UINT yoffset = src_height - src_rect->top + dst_rect.top - 1;
2110 /* I have to process this row by row to swap the image,
2111 * otherwise it would be upside down, so stretching in y direction
2112 * doesn't cost extra time
2114 * However, stretching in x direction can be avoided if not necessary
2116 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
2117 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
2119 /* Well, that stuff works, but it's very slow.
2120 * find a better way instead
2122 LONG col;
2124 for (col = dst_rect.left; col < dst_rect.right; ++col)
2126 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2127 dst_rect.left + col /* x offset */, row /* y offset */,
2128 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
2131 else
2133 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
2134 dst_rect.left /* x offset */, row /* y offset */,
2135 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
2139 checkGLcall("glCopyTexSubImage2D");
2141 context_release(context);
2143 /* The texture is now most up to date - If the surface is a render target
2144 * and has a drawable, this path is never entered. */
2145 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2146 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2149 /* Uses the hardware to stretch and flip the image */
2150 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
2151 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
2153 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
2154 struct wined3d_texture *src_texture = src_surface->container;
2155 struct wined3d_texture *dst_texture = dst_surface->container;
2156 struct wined3d_device *device = dst_texture->resource.device;
2157 GLuint src, backup = 0;
2158 float left, right, top, bottom; /* Texture coordinates */
2159 const struct wined3d_gl_info *gl_info;
2160 unsigned int src_width, src_height;
2161 struct wined3d_context *context;
2162 GLenum drawBuffer = GL_BACK;
2163 GLenum offscreen_buffer;
2164 GLenum texture_target;
2165 BOOL noBackBufferBackup;
2166 BOOL src_offscreen;
2167 BOOL upsidedown = FALSE;
2168 RECT dst_rect = *dst_rect_in;
2170 TRACE("Using hwstretch blit\n");
2171 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2172 context = context_acquire(device, src_surface);
2173 gl_info = context->gl_info;
2174 context_apply_blit_state(context, device);
2175 wined3d_texture_load(dst_texture, context, FALSE);
2177 offscreen_buffer = context_get_offscreen_gl_buffer(context);
2178 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
2179 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2181 src_offscreen = wined3d_resource_is_offscreen(&src_texture->resource);
2182 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
2183 if (!noBackBufferBackup && !src_texture->texture_rgb.name)
2185 /* Get it a description */
2186 wined3d_texture_load(src_texture, context, FALSE);
2189 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2190 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2192 if (context->aux_buffers >= 2)
2194 /* Got more than one aux buffer? Use the 2nd aux buffer */
2195 drawBuffer = GL_AUX1;
2197 else if ((!src_offscreen || offscreen_buffer == GL_BACK) && context->aux_buffers >= 1)
2199 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2200 drawBuffer = GL_AUX0;
2203 if (noBackBufferBackup)
2205 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
2206 checkGLcall("glGenTextures");
2207 context_bind_texture(context, GL_TEXTURE_2D, backup);
2208 texture_target = GL_TEXTURE_2D;
2210 else
2212 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2213 * we are reading from the back buffer, the backup can be used as source texture
2215 texture_target = src_surface->texture_target;
2216 context_bind_texture(context, texture_target, src_texture->texture_rgb.name);
2217 gl_info->gl_ops.gl.p_glEnable(texture_target);
2218 checkGLcall("glEnable(texture_target)");
2220 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2221 surface_get_sub_resource(src_surface)->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
2224 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2225 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2227 if(dst_rect.top > dst_rect.bottom) {
2228 UINT tmp = dst_rect.bottom;
2229 dst_rect.bottom = dst_rect.top;
2230 dst_rect.top = tmp;
2231 upsidedown = TRUE;
2234 if (src_offscreen)
2236 TRACE("Reading from an offscreen target\n");
2237 upsidedown = !upsidedown;
2238 gl_info->gl_ops.gl.p_glReadBuffer(offscreen_buffer);
2240 else
2242 gl_info->gl_ops.gl.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture));
2245 /* TODO: Only back up the part that will be overwritten */
2246 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, src_width, src_height);
2248 checkGLcall("glCopyTexSubImage2D");
2250 /* No issue with overriding these - the sampler is dirty due to blit usage */
2251 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, wined3d_gl_mag_filter(filter));
2252 checkGLcall("glTexParameteri");
2253 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
2254 wined3d_gl_min_mip_filter(filter, WINED3D_TEXF_NONE));
2255 checkGLcall("glTexParameteri");
2257 if (!src_texture->swapchain || src_texture == src_texture->swapchain->back_buffers[0])
2259 src = backup ? backup : src_texture->texture_rgb.name;
2261 else
2263 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
2264 checkGLcall("glReadBuffer(GL_FRONT)");
2266 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
2267 checkGLcall("glGenTextures(1, &src)");
2268 context_bind_texture(context, GL_TEXTURE_2D, src);
2270 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
2271 * out for power of 2 sizes
2273 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
2274 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2275 checkGLcall("glTexImage2D");
2276 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, src_width, src_height);
2278 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2279 checkGLcall("glTexParameteri");
2280 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2281 checkGLcall("glTexParameteri");
2283 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
2284 checkGLcall("glReadBuffer(GL_BACK)");
2286 if (texture_target != GL_TEXTURE_2D)
2288 gl_info->gl_ops.gl.p_glDisable(texture_target);
2289 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2290 texture_target = GL_TEXTURE_2D;
2293 checkGLcall("glEnd and previous");
2295 left = src_rect->left;
2296 right = src_rect->right;
2298 if (!upsidedown)
2300 top = src_height - src_rect->top;
2301 bottom = src_height - src_rect->bottom;
2303 else
2305 top = src_height - src_rect->bottom;
2306 bottom = src_height - src_rect->top;
2309 if (src_texture->flags & WINED3D_TEXTURE_NORMALIZED_COORDS)
2311 left /= src_surface->pow2Width;
2312 right /= src_surface->pow2Width;
2313 top /= src_surface->pow2Height;
2314 bottom /= src_surface->pow2Height;
2317 /* draw the source texture stretched and upside down. The correct surface is bound already */
2318 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2319 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2321 context_set_draw_buffer(context, drawBuffer);
2322 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
2324 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2325 /* bottom left */
2326 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
2327 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2329 /* top left */
2330 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
2331 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
2333 /* top right */
2334 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
2335 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2337 /* bottom right */
2338 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
2339 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
2340 gl_info->gl_ops.gl.p_glEnd();
2341 checkGLcall("glEnd and previous");
2343 if (texture_target != dst_surface->texture_target)
2345 gl_info->gl_ops.gl.p_glDisable(texture_target);
2346 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
2347 texture_target = dst_surface->texture_target;
2350 /* Now read the stretched and upside down image into the destination texture */
2351 context_bind_texture(context, texture_target, dst_texture->texture_rgb.name);
2352 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
2354 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
2355 0, 0, /* We blitted the image to the origin */
2356 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
2357 checkGLcall("glCopyTexSubImage2D");
2359 if (drawBuffer == GL_BACK)
2361 /* Write the back buffer backup back. */
2362 if (backup)
2364 if (texture_target != GL_TEXTURE_2D)
2366 gl_info->gl_ops.gl.p_glDisable(texture_target);
2367 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
2368 texture_target = GL_TEXTURE_2D;
2370 context_bind_texture(context, GL_TEXTURE_2D, backup);
2372 else
2374 if (texture_target != src_surface->texture_target)
2376 gl_info->gl_ops.gl.p_glDisable(texture_target);
2377 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
2378 texture_target = src_surface->texture_target;
2380 context_bind_texture(context, src_surface->texture_target, src_texture->texture_rgb.name);
2383 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
2384 /* top left */
2385 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
2386 gl_info->gl_ops.gl.p_glVertex2i(0, src_height);
2388 /* bottom left */
2389 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)src_height / (float)src_surface->pow2Height);
2390 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
2392 /* bottom right */
2393 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_surface->pow2Width,
2394 (float)src_height / (float)src_surface->pow2Height);
2395 gl_info->gl_ops.gl.p_glVertex2i(src_width, 0);
2397 /* top right */
2398 gl_info->gl_ops.gl.p_glTexCoord2f((float)src_width / (float)src_surface->pow2Width, 0.0f);
2399 gl_info->gl_ops.gl.p_glVertex2i(src_width, src_height);
2400 gl_info->gl_ops.gl.p_glEnd();
2402 gl_info->gl_ops.gl.p_glDisable(texture_target);
2403 checkGLcall("glDisable(texture_target)");
2405 /* Cleanup */
2406 if (src != src_texture->texture_rgb.name && src != backup)
2408 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
2409 checkGLcall("glDeleteTextures(1, &src)");
2411 if (backup)
2413 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
2414 checkGLcall("glDeleteTextures(1, &backup)");
2417 if (wined3d_settings.strict_draw_ordering)
2418 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2420 context_release(context);
2422 /* The texture is now most up to date - If the surface is a render target
2423 * and has a drawable, this path is never entered. */
2424 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB);
2425 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~WINED3D_LOCATION_TEXTURE_RGB);
2428 /* Front buffer coordinates are always full screen coordinates, but our GL
2429 * drawable is limited to the window's client area. The sysmem and texture
2430 * copies do have the full screen size. Note that GL has a bottom-left
2431 * origin, while D3D has a top-left origin. */
2432 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
2434 struct wined3d_texture *texture = surface->container;
2435 UINT drawable_height;
2437 if (texture->swapchain && texture == texture->swapchain->front_buffer)
2439 POINT offset = {0, 0};
2440 RECT windowsize;
2442 ScreenToClient(window, &offset);
2443 OffsetRect(rect, offset.x, offset.y);
2445 GetClientRect(window, &windowsize);
2446 drawable_height = windowsize.bottom - windowsize.top;
2448 else
2450 drawable_height = wined3d_texture_get_level_height(texture, surface->texture_level);
2453 rect->top = drawable_height - rect->top;
2454 rect->bottom = drawable_height - rect->bottom;
2457 /* Context activation is done by the caller. */
2458 static void surface_blt_to_drawable(const struct wined3d_device *device,
2459 struct wined3d_context *old_ctx,
2460 enum wined3d_texture_filter_type filter, BOOL alpha_test,
2461 struct wined3d_surface *src_surface, const RECT *src_rect_in,
2462 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
2464 struct wined3d_texture *src_texture = src_surface->container;
2465 struct wined3d_texture *dst_texture = dst_surface->container;
2466 const struct wined3d_gl_info *gl_info;
2467 struct wined3d_context *context = old_ctx;
2468 struct wined3d_surface *restore_rt = NULL;
2469 RECT src_rect, dst_rect;
2471 src_rect = *src_rect_in;
2472 dst_rect = *dst_rect_in;
2474 restore_rt = context_get_rt_surface(old_ctx);
2475 if (restore_rt != dst_surface)
2476 context = context_acquire(device, dst_surface);
2477 else
2478 restore_rt = NULL;
2480 gl_info = context->gl_info;
2482 /* Make sure the surface is up-to-date. This should probably use
2483 * surface_load_location() and worry about the destination surface too,
2484 * unless we're overwriting it completely. */
2485 wined3d_texture_load(src_texture, context, FALSE);
2487 /* Activate the destination context, set it up for blitting */
2488 context_apply_blit_state(context, device);
2490 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
2491 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
2493 device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
2495 if (alpha_test)
2497 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
2498 checkGLcall("glEnable(GL_ALPHA_TEST)");
2500 /* For P8 surfaces, the alpha component contains the palette index.
2501 * Which means that the colorkey is one of the palette entries. In
2502 * other cases pixels that should be masked away have alpha set to 0. */
2503 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT)
2504 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
2505 (float)src_texture->async.src_blt_color_key.color_space_low_value / 255.0f);
2506 else
2507 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
2508 checkGLcall("glAlphaFunc");
2510 else
2512 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2513 checkGLcall("glDisable(GL_ALPHA_TEST)");
2516 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
2518 if (alpha_test)
2520 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2521 checkGLcall("glDisable(GL_ALPHA_TEST)");
2524 /* Leave the opengl state valid for blitting */
2525 device->blitter->unset_shader(context->gl_info);
2527 if (wined3d_settings.strict_draw_ordering
2528 || (dst_texture->swapchain && dst_texture->swapchain->front_buffer == dst_texture))
2529 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2531 if (restore_rt)
2532 context_restore(context, restore_rt);
2535 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
2537 struct wined3d_resource *resource = &s->container->resource;
2538 struct wined3d_device *device = resource->device;
2539 struct wined3d_rendertarget_view_desc view_desc;
2540 struct wined3d_rendertarget_view *view;
2541 const struct blit_shader *blitter;
2542 HRESULT hr;
2544 if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
2545 WINED3D_BLIT_OP_COLOR_FILL, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
2547 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2548 return WINED3DERR_INVALIDCALL;
2551 view_desc.format_id = resource->format->id;
2552 view_desc.u.texture.level_idx = s->texture_level;
2553 view_desc.u.texture.layer_idx = s->texture_layer;
2554 view_desc.u.texture.layer_count = 1;
2555 if (FAILED(hr = wined3d_rendertarget_view_create(&view_desc,
2556 resource, NULL, &wined3d_null_parent_ops, &view)))
2558 ERR("Failed to create rendertarget view, hr %#x.\n", hr);
2559 return hr;
2562 hr = blitter->color_fill(device, view, rect, color);
2563 wined3d_rendertarget_view_decref(view);
2565 return hr;
2568 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
2569 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
2570 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
2572 struct wined3d_texture *dst_texture = dst_surface->container;
2573 struct wined3d_device *device = dst_texture->resource.device;
2574 const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
2575 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
2576 struct wined3d_texture *src_texture;
2578 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2579 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2580 flags, fx, debug_d3dtexturefiltertype(filter));
2582 /* Get the swapchain. One of the surfaces has to be a primary surface */
2583 if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2585 WARN("Destination is in sysmem, rejecting gl blt\n");
2586 return WINED3DERR_INVALIDCALL;
2589 dst_swapchain = dst_texture->swapchain;
2591 if (src_surface)
2593 src_texture = src_surface->container;
2594 if (src_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
2596 WARN("Src is in sysmem, rejecting gl blt\n");
2597 return WINED3DERR_INVALIDCALL;
2600 src_swapchain = src_texture->swapchain;
2602 else
2604 src_texture = NULL;
2605 src_swapchain = NULL;
2608 /* Early sort out of cases where no render target is used */
2609 if (!dst_swapchain && !src_swapchain && src_surface != rt && dst_surface != rt)
2611 TRACE("No surface is render target, not using hardware blit.\n");
2612 return WINED3DERR_INVALIDCALL;
2615 /* No destination color keying supported */
2616 if (flags & (WINED3D_BLT_DST_CKEY | WINED3D_BLT_DST_CKEY_OVERRIDE))
2618 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2619 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2620 return WINED3DERR_INVALIDCALL;
2623 if (dst_swapchain && dst_swapchain == src_swapchain)
2625 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2626 return WINED3DERR_INVALIDCALL;
2629 if (dst_swapchain && src_swapchain)
2631 FIXME("Implement hardware blit between two different swapchains\n");
2632 return WINED3DERR_INVALIDCALL;
2635 if (dst_swapchain)
2637 /* Handled with regular texture -> swapchain blit */
2638 if (src_surface == rt)
2639 TRACE("Blit from active render target to a swapchain\n");
2641 else if (src_swapchain && dst_surface == rt)
2643 FIXME("Implement blit from a swapchain to the active render target\n");
2644 return WINED3DERR_INVALIDCALL;
2647 if ((src_swapchain || src_surface == rt) && !dst_swapchain)
2649 unsigned int src_width, src_height;
2650 /* Blit from render target to texture */
2651 BOOL stretchx;
2653 /* P8 read back is not implemented */
2654 if (src_texture->resource.format->id == WINED3DFMT_P8_UINT
2655 || dst_texture->resource.format->id == WINED3DFMT_P8_UINT)
2657 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2658 return WINED3DERR_INVALIDCALL;
2661 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_SRC_CKEY_OVERRIDE))
2663 TRACE("Color keying not supported by frame buffer to texture blit\n");
2664 return WINED3DERR_INVALIDCALL;
2665 /* Destination color key is checked above */
2668 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
2669 stretchx = TRUE;
2670 else
2671 stretchx = FALSE;
2673 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2674 * flip the image nor scale it.
2676 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2677 * -> If the app wants an image width an unscaled width, copy it line per line
2678 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2679 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2680 * back buffer. This is slower than reading line per line, thus not used for flipping
2681 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2682 * pixel by pixel. */
2683 src_width = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
2684 src_height = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
2685 if (!stretchx || dst_rect->right - dst_rect->left > src_width
2686 || dst_rect->bottom - dst_rect->top > src_height)
2688 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2689 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
2691 else
2693 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2694 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
2697 surface_evict_sysmem(dst_surface);
2699 return WINED3D_OK;
2702 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2703 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2704 return WINED3DERR_INVALIDCALL;
2707 /* Context activation is done by the caller. */
2708 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
2709 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
2711 struct wined3d_device *device = surface->container->resource.device;
2712 const struct wined3d_gl_info *gl_info = context->gl_info;
2713 GLint compare_mode = GL_NONE;
2714 struct blt_info info;
2715 GLint old_binding = 0;
2716 RECT rect;
2718 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
2720 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
2721 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
2722 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
2723 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
2724 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
2725 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
2726 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
2727 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
2728 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
2729 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
2730 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
2732 SetRect(&rect, 0, h, w, 0);
2733 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
2734 context_active_texture(context, context->gl_info, 0);
2735 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
2736 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
2737 if (gl_info->supported[ARB_SHADOW])
2739 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
2740 if (compare_mode != GL_NONE)
2741 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
2744 device->shader_backend->shader_select_depth_blt(device->shader_priv,
2745 gl_info, info.tex_type, &surface->ds_current_size);
2747 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
2748 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
2749 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
2750 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
2751 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
2752 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
2753 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
2754 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
2755 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
2756 gl_info->gl_ops.gl.p_glEnd();
2758 if (compare_mode != GL_NONE)
2759 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
2760 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
2762 gl_info->gl_ops.gl.p_glPopAttrib();
2764 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
2767 void surface_modify_ds_location(struct wined3d_surface *surface,
2768 DWORD location, UINT w, UINT h)
2770 struct wined3d_texture_sub_resource *sub_resource;
2772 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
2774 sub_resource = surface_get_sub_resource(surface);
2775 if (((sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
2776 || (!(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB)
2777 && (location & WINED3D_LOCATION_TEXTURE_RGB)))
2778 wined3d_texture_set_dirty(surface->container);
2780 surface->ds_current_size.cx = w;
2781 surface->ds_current_size.cy = h;
2782 sub_resource->locations = location;
2785 /* Context activation is done by the caller. */
2786 static void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
2788 struct wined3d_texture *texture = surface->container;
2789 struct wined3d_device *device = texture->resource.device;
2790 const struct wined3d_gl_info *gl_info = context->gl_info;
2791 GLsizei w, h;
2793 TRACE("surface %p, context %p, new location %#x.\n", surface, context, location);
2795 /* TODO: Make this work for modes other than FBO */
2796 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
2798 if (!(surface_get_sub_resource(surface)->locations & location))
2800 w = surface->ds_current_size.cx;
2801 h = surface->ds_current_size.cy;
2802 surface->ds_current_size.cx = 0;
2803 surface->ds_current_size.cy = 0;
2805 else
2807 w = wined3d_texture_get_level_width(surface->container, surface->texture_level);
2808 h = wined3d_texture_get_level_height(surface->container, surface->texture_level);
2811 if (surface->current_renderbuffer)
2813 FIXME("Not supported with fixed up depth stencil.\n");
2814 return;
2817 wined3d_surface_prepare(surface, context, location);
2819 if (location == WINED3D_LOCATION_TEXTURE_RGB)
2821 GLint old_binding = 0;
2822 GLenum bind_target;
2824 /* The render target is allowed to be smaller than the depth/stencil
2825 * buffer, so the onscreen depth/stencil buffer is potentially smaller
2826 * than the offscreen surface. Don't overwrite the offscreen surface
2827 * with undefined data. */
2828 w = min(w, context->swapchain->desc.backbuffer_width);
2829 h = min(h, context->swapchain->desc.backbuffer_height);
2831 TRACE("Copying onscreen depth buffer to depth texture.\n");
2833 if (!device->depth_blt_texture)
2834 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
2836 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2837 * directly on the FBO texture. That's because we need to flip. */
2838 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2839 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2840 NULL, WINED3D_LOCATION_DRAWABLE);
2841 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2843 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
2844 bind_target = GL_TEXTURE_RECTANGLE_ARB;
2846 else
2848 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
2849 bind_target = GL_TEXTURE_2D;
2851 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
2852 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
2853 * internal format, because the internal format might include stencil
2854 * data. In principle we should copy stencil data as well, but unless
2855 * the driver supports stencil export it's hard to do, and doesn't
2856 * seem to be needed in practice. If the hardware doesn't support
2857 * writing stencil data, the glCopyTexImage2D() call might trigger
2858 * software fallbacks. */
2859 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
2860 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2861 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2862 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2863 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2864 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2865 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
2867 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2868 NULL, surface, WINED3D_LOCATION_TEXTURE_RGB);
2869 context_set_draw_buffer(context, GL_NONE);
2871 /* Do the actual blit */
2872 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
2873 checkGLcall("depth_blt");
2875 context_invalidate_state(context, STATE_FRAMEBUFFER);
2877 if (wined3d_settings.strict_draw_ordering)
2878 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2880 else if (location == WINED3D_LOCATION_DRAWABLE)
2882 TRACE("Copying depth texture to onscreen depth buffer.\n");
2884 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
2885 wined3d_texture_get_sub_resource(context->swapchain->front_buffer, 0)->u.surface,
2886 NULL, WINED3D_LOCATION_DRAWABLE);
2887 surface_depth_blt(surface, context, texture->texture_rgb.name,
2888 0, surface->pow2Height - h, w, h, surface->texture_target);
2889 checkGLcall("depth_blt");
2891 context_invalidate_state(context, STATE_FRAMEBUFFER);
2893 if (wined3d_settings.strict_draw_ordering)
2894 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
2896 else
2898 ERR("Invalid location (%#x) specified.\n", location);
2902 static DWORD resource_access_from_location(DWORD location)
2904 switch (location)
2906 case WINED3D_LOCATION_SYSMEM:
2907 case WINED3D_LOCATION_USER_MEMORY:
2908 case WINED3D_LOCATION_DIB:
2909 case WINED3D_LOCATION_BUFFER:
2910 return WINED3D_RESOURCE_ACCESS_CPU;
2912 case WINED3D_LOCATION_DRAWABLE:
2913 case WINED3D_LOCATION_TEXTURE_SRGB:
2914 case WINED3D_LOCATION_TEXTURE_RGB:
2915 case WINED3D_LOCATION_RB_MULTISAMPLE:
2916 case WINED3D_LOCATION_RB_RESOLVED:
2917 return WINED3D_RESOURCE_ACCESS_GPU;
2919 default:
2920 FIXME("Unhandled location %#x.\n", location);
2921 return 0;
2925 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
2927 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
2928 struct wined3d_texture *texture = surface->container;
2929 struct wined3d_device *device = texture->resource.device;
2930 struct wined3d_context *context;
2931 const struct wined3d_gl_info *gl_info;
2932 struct wined3d_bo_address dst, src;
2933 UINT size = surface->resource.size;
2935 wined3d_texture_get_memory(texture, sub_resource_idx, &dst, location);
2936 wined3d_texture_get_memory(texture, sub_resource_idx, &src,
2937 texture->sub_resources[sub_resource_idx].locations);
2939 if (dst.buffer_object)
2941 context = context_acquire(device, NULL);
2942 gl_info = context->gl_info;
2943 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
2944 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
2945 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
2946 checkGLcall("Upload PBO");
2947 context_release(context);
2948 return;
2950 if (src.buffer_object)
2952 context = context_acquire(device, NULL);
2953 gl_info = context->gl_info;
2954 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
2955 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
2956 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
2957 checkGLcall("Download PBO");
2958 context_release(context);
2959 return;
2961 memcpy(dst.addr, src.addr, size);
2964 /* Context activation is done by the caller. */
2965 static void surface_load_sysmem(struct wined3d_surface *surface,
2966 struct wined3d_context *context, DWORD dst_location)
2968 const struct wined3d_gl_info *gl_info = context->gl_info;
2969 struct wined3d_texture_sub_resource *sub_resource;
2971 wined3d_surface_prepare(surface, context, dst_location);
2973 sub_resource = surface_get_sub_resource(surface);
2974 if (sub_resource->locations & surface_simple_locations)
2976 surface_copy_simple_location(surface, dst_location);
2977 return;
2980 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
2981 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
2983 /* Download the surface to system memory. */
2984 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
2986 struct wined3d_texture *texture = surface->container;
2988 wined3d_texture_bind_and_dirtify(texture, context,
2989 !(sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB));
2990 surface_download_data(surface, gl_info, dst_location);
2991 ++texture->download_count;
2993 return;
2996 if (sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
2998 read_from_framebuffer(surface, context, dst_location);
2999 return;
3002 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
3003 surface, wined3d_debug_location(sub_resource->locations));
3006 /* Context activation is done by the caller. */
3007 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
3008 struct wined3d_context *context)
3010 struct wined3d_texture *texture = surface->container;
3011 RECT r;
3013 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3014 && wined3d_resource_is_offscreen(&texture->resource))
3016 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
3017 return WINED3DERR_INVALIDCALL;
3020 surface_get_rect(surface, NULL, &r);
3021 surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
3022 surface_blt_to_drawable(texture->resource.device, context,
3023 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
3025 return WINED3D_OK;
3028 static HRESULT surface_load_texture(struct wined3d_surface *surface,
3029 struct wined3d_context *context, BOOL srgb)
3031 unsigned int width, height, src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
3032 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3033 const struct wined3d_gl_info *gl_info = context->gl_info;
3034 struct wined3d_texture *texture = surface->container;
3035 struct wined3d_device *device = texture->resource.device;
3036 const struct wined3d_color_key_conversion *conversion;
3037 struct wined3d_texture_sub_resource *sub_resource;
3038 struct wined3d_bo_address data;
3039 struct wined3d_format format;
3040 POINT dst_point = {0, 0};
3041 BYTE *mem = NULL;
3042 RECT src_rect;
3044 sub_resource = surface_get_sub_resource(surface);
3045 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
3046 && wined3d_resource_is_offscreen(&texture->resource)
3047 && (sub_resource->locations & WINED3D_LOCATION_DRAWABLE))
3049 surface_load_fb_texture(surface, srgb, context);
3051 return WINED3D_OK;
3054 width = wined3d_texture_get_level_width(texture, surface->texture_level);
3055 height = wined3d_texture_get_level_height(texture, surface->texture_level);
3056 SetRect(&src_rect, 0, 0, width, height);
3058 if (sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
3059 && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
3060 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3061 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3062 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3064 if (srgb)
3065 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
3066 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
3067 else
3068 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
3069 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
3071 return WINED3D_OK;
3074 if (sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
3075 && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
3076 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
3077 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
3078 NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
3080 DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
3081 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
3082 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
3084 surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, src_location,
3085 &src_rect, surface, dst_location, &src_rect);
3087 return WINED3D_OK;
3090 /* Upload from system memory */
3092 if (srgb)
3094 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
3095 == WINED3D_LOCATION_TEXTURE_RGB)
3097 /* Performance warning... */
3098 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
3099 surface_load_location(surface, context, surface->resource.map_binding);
3102 else
3104 if ((sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
3105 == WINED3D_LOCATION_TEXTURE_SRGB)
3107 /* Performance warning... */
3108 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
3109 surface_load_location(surface, context, surface->resource.map_binding);
3113 if (!(sub_resource->locations & surface_simple_locations))
3115 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
3116 /* Lets hope we get it from somewhere... */
3117 surface_load_location(surface, context, WINED3D_LOCATION_SYSMEM);
3120 wined3d_texture_prepare_texture(texture, context, srgb);
3121 wined3d_texture_bind_and_dirtify(texture, context, srgb);
3122 wined3d_texture_get_pitch(texture, surface->texture_level, &src_row_pitch, &src_slice_pitch);
3124 format = *texture->resource.format;
3125 if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
3126 format = *wined3d_get_format(gl_info, conversion->dst_format);
3128 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
3129 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
3130 * getting called. */
3131 if ((format.convert || conversion) && texture->sub_resources[sub_resource_idx].buffer_object)
3133 TRACE("Removing the pbo attached to surface %p.\n", surface);
3135 if (surface->flags & SFLAG_DIBSECTION)
3136 surface->resource.map_binding = WINED3D_LOCATION_DIB;
3137 else
3138 surface->resource.map_binding = WINED3D_LOCATION_SYSMEM;
3140 surface_load_location(surface, context, surface->resource.map_binding);
3141 wined3d_texture_remove_buffer_object(texture, sub_resource_idx, gl_info);
3144 wined3d_texture_get_memory(texture, sub_resource_idx, &data, sub_resource->locations);
3145 if (format.convert)
3147 /* This code is entered for texture formats which need a fixup. */
3148 format.byte_count = format.conv_byte_count;
3149 wined3d_format_calculate_pitch(&format, 1, width, height, &dst_row_pitch, &dst_slice_pitch);
3151 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3153 ERR("Out of memory (%u).\n", dst_slice_pitch);
3154 context_release(context);
3155 return E_OUTOFMEMORY;
3157 format.convert(data.addr, mem, src_row_pitch, src_slice_pitch,
3158 dst_row_pitch, dst_slice_pitch, width, height, 1);
3159 src_row_pitch = dst_row_pitch;
3160 data.addr = mem;
3162 else if (conversion)
3164 /* This code is only entered for color keying fixups */
3165 struct wined3d_palette *palette = NULL;
3167 wined3d_format_calculate_pitch(&format, device->surface_alignment,
3168 width, height, &dst_row_pitch, &dst_slice_pitch);
3170 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch)))
3172 ERR("Out of memory (%u).\n", dst_slice_pitch);
3173 context_release(context);
3174 return E_OUTOFMEMORY;
3176 if (texture->swapchain && texture->swapchain->palette)
3177 palette = texture->swapchain->palette;
3178 conversion->convert(data.addr, src_row_pitch, mem, dst_row_pitch,
3179 width, height, palette, &texture->async.gl_color_key);
3180 src_row_pitch = dst_row_pitch;
3181 data.addr = mem;
3184 wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
3185 src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
3187 HeapFree(GetProcessHeap(), 0, mem);
3189 return WINED3D_OK;
3192 /* Context activation is done by the caller. */
3193 static void surface_load_renderbuffer(struct wined3d_surface *surface, struct wined3d_context *context,
3194 DWORD dst_location)
3196 struct wined3d_texture *texture = surface->container;
3197 const RECT rect = {0, 0,
3198 wined3d_texture_get_level_width(texture, surface->texture_level),
3199 wined3d_texture_get_level_height(texture, surface->texture_level)};
3200 DWORD locations = surface_get_sub_resource(surface)->locations;
3201 DWORD src_location;
3203 if (locations & WINED3D_LOCATION_RB_MULTISAMPLE)
3204 src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
3205 else if (locations & WINED3D_LOCATION_RB_RESOLVED)
3206 src_location = WINED3D_LOCATION_RB_RESOLVED;
3207 else if (locations & WINED3D_LOCATION_TEXTURE_SRGB)
3208 src_location = WINED3D_LOCATION_TEXTURE_SRGB;
3209 else /* surface_blt_fbo will load the source location if necessary. */
3210 src_location = WINED3D_LOCATION_TEXTURE_RGB;
3212 surface_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT,
3213 surface, src_location, &rect, surface, dst_location, &rect);
3216 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
3217 HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
3219 unsigned int sub_resource_idx = surface_get_sub_resource_idx(surface);
3220 struct wined3d_texture *texture = surface->container;
3221 struct wined3d_texture_sub_resource *sub_resource;
3222 unsigned int surface_w, surface_h;
3223 HRESULT hr;
3225 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
3227 surface_w = wined3d_texture_get_level_width(texture, surface->texture_level);
3228 surface_h = wined3d_texture_get_level_height(texture, surface->texture_level);
3230 sub_resource = &texture->sub_resources[sub_resource_idx];
3231 if (sub_resource->locations & location && (!(texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3232 || (surface->ds_current_size.cx == surface_w && surface->ds_current_size.cy == surface_h)))
3234 TRACE("Location (%#x) is already up to date.\n", location);
3235 return WINED3D_OK;
3238 if (WARN_ON(d3d))
3240 DWORD required_access = resource_access_from_location(location);
3241 if ((texture->resource.access_flags & required_access) != required_access)
3242 WARN("Operation requires %#x access, but surface only has %#x.\n",
3243 required_access, texture->resource.access_flags);
3246 if (sub_resource->locations & WINED3D_LOCATION_DISCARDED)
3248 TRACE("Surface previously discarded, nothing to do.\n");
3249 wined3d_surface_prepare(surface, context, location);
3250 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3251 wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3252 goto done;
3255 if (!sub_resource->locations)
3257 ERR("Surface %p does not have any up to date location.\n", surface);
3258 wined3d_texture_validate_location(texture, sub_resource_idx, WINED3D_LOCATION_DISCARDED);
3259 return surface_load_location(surface, context, location);
3262 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3264 if ((location == WINED3D_LOCATION_TEXTURE_RGB && sub_resource->locations & WINED3D_LOCATION_DRAWABLE)
3265 || (location == WINED3D_LOCATION_DRAWABLE && sub_resource->locations & WINED3D_LOCATION_TEXTURE_RGB))
3267 surface_load_ds_location(surface, context, location);
3268 goto done;
3271 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
3272 wined3d_debug_location(sub_resource->locations), wined3d_debug_location(location));
3273 return WINED3DERR_INVALIDCALL;
3276 switch (location)
3278 case WINED3D_LOCATION_DIB:
3279 case WINED3D_LOCATION_USER_MEMORY:
3280 case WINED3D_LOCATION_SYSMEM:
3281 case WINED3D_LOCATION_BUFFER:
3282 surface_load_sysmem(surface, context, location);
3283 break;
3285 case WINED3D_LOCATION_DRAWABLE:
3286 if (FAILED(hr = surface_load_drawable(surface, context)))
3287 return hr;
3288 break;
3290 case WINED3D_LOCATION_RB_RESOLVED:
3291 case WINED3D_LOCATION_RB_MULTISAMPLE:
3292 surface_load_renderbuffer(surface, context, location);
3293 break;
3295 case WINED3D_LOCATION_TEXTURE_RGB:
3296 case WINED3D_LOCATION_TEXTURE_SRGB:
3297 if (FAILED(hr = surface_load_texture(surface, context,
3298 location == WINED3D_LOCATION_TEXTURE_SRGB)))
3299 return hr;
3300 break;
3302 default:
3303 ERR("Don't know how to handle location %#x.\n", location);
3304 break;
3307 done:
3308 wined3d_texture_validate_location(texture, sub_resource_idx, location);
3310 if (texture->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
3312 surface->ds_current_size.cx = surface_w;
3313 surface->ds_current_size.cy = surface_h;
3316 if (location != WINED3D_LOCATION_SYSMEM && (sub_resource->locations & WINED3D_LOCATION_SYSMEM))
3317 surface_evict_sysmem(surface);
3319 return WINED3D_OK;
3322 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
3323 /* Context activation is done by the caller. */
3324 static void ffp_blit_free(struct wined3d_device *device) { }
3326 /* Context activation is done by the caller. */
3327 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3328 const struct wined3d_color_key *color_key)
3330 const struct wined3d_gl_info *gl_info = context->gl_info;
3332 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
3333 checkGLcall("glEnable(target)");
3335 return WINED3D_OK;
3338 /* Context activation is done by the caller. */
3339 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
3341 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
3342 checkGLcall("glDisable(GL_TEXTURE_2D)");
3343 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
3345 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
3346 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3348 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
3350 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
3351 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
3355 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
3356 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3357 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3358 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3360 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
3362 TRACE("Source or destination is in system memory.\n");
3363 return FALSE;
3366 switch (blit_op)
3368 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
3369 if (d3d_info->shader_color_key)
3371 TRACE("Color keying requires converted textures.\n");
3372 return FALSE;
3374 case WINED3D_BLIT_OP_COLOR_BLIT:
3375 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
3376 if (TRACE_ON(d3d))
3378 TRACE("Checking support for fixup:\n");
3379 dump_color_fixup_desc(src_format->color_fixup);
3382 /* We only support identity conversions. */
3383 if (!is_identity_fixup(src_format->color_fixup)
3384 || !is_identity_fixup(dst_format->color_fixup))
3386 TRACE("Fixups are not supported.\n");
3387 return FALSE;
3390 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3392 TRACE("Can only blit to render targets.\n");
3393 return FALSE;
3395 return TRUE;
3397 case WINED3D_BLIT_OP_COLOR_FILL:
3398 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
3400 if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
3401 || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
3402 return FALSE;
3404 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
3406 TRACE("Color fill not supported\n");
3407 return FALSE;
3410 /* FIXME: We should reject color fills on formats with fixups,
3411 * but this would break P8 color fills for example. */
3413 return TRUE;
3415 case WINED3D_BLIT_OP_DEPTH_FILL:
3416 return TRUE;
3418 default:
3419 TRACE("Unsupported blit_op=%d\n", blit_op);
3420 return FALSE;
3424 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
3425 const RECT *rect, const struct wined3d_color *color)
3427 const RECT draw_rect = {0, 0, view->width, view->height};
3428 struct wined3d_fb_state fb = {&view, NULL};
3430 device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
3432 return WINED3D_OK;
3435 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
3436 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
3437 float depth, DWORD stencil)
3439 const RECT draw_rect = {0, 0, view->width, view->height};
3440 struct wined3d_fb_state fb = {NULL, view};
3442 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, clear_flags, NULL, depth, stencil);
3444 return WINED3D_OK;
3447 static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
3448 struct wined3d_surface *src_surface, const RECT *src_rect,
3449 struct wined3d_surface *dst_surface, const RECT *dst_rect,
3450 const struct wined3d_color_key *color_key)
3452 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
3453 struct wined3d_texture *dst_texture = dst_surface->container;
3454 struct wined3d_texture *src_texture = src_surface->container;
3455 struct wined3d_context *context;
3457 /* Blit from offscreen surface to render target */
3458 struct wined3d_color_key old_blt_key = src_texture->async.src_blt_color_key;
3459 DWORD old_color_key_flags = src_texture->async.color_key_flags;
3461 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
3463 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT, color_key);
3465 context = context_acquire(device, dst_surface);
3467 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3468 glEnable(GL_ALPHA_TEST);
3470 surface_blt_to_drawable(device, context, filter,
3471 !!color_key, src_surface, src_rect, dst_surface, dst_rect);
3473 if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
3474 glDisable(GL_ALPHA_TEST);
3476 context_release(context);
3478 /* Restore the color key parameters */
3479 wined3d_texture_set_color_key(src_texture, WINED3D_CKEY_SRC_BLT,
3480 (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
3482 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_texture->resource.draw_binding);
3483 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_texture->resource.draw_binding);
3486 const struct blit_shader ffp_blit = {
3487 ffp_blit_alloc,
3488 ffp_blit_free,
3489 ffp_blit_set,
3490 ffp_blit_unset,
3491 ffp_blit_supported,
3492 ffp_blit_color_fill,
3493 ffp_blit_depth_fill,
3494 ffp_blit_blit_surface,
3497 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
3499 return WINED3D_OK;
3502 /* Context activation is done by the caller. */
3503 static void cpu_blit_free(struct wined3d_device *device)
3507 /* Context activation is done by the caller. */
3508 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
3509 const struct wined3d_color_key *color_key)
3511 return WINED3D_OK;
3514 /* Context activation is done by the caller. */
3515 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
3519 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
3520 const struct wined3d_d3d_info *d3d_info, enum wined3d_blit_op blit_op,
3521 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
3522 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
3524 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
3526 return TRUE;
3529 return FALSE;
3532 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
3533 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
3534 const struct wined3d_format *format, DWORD flags, const struct wined3d_blt_fx *fx)
3536 UINT row_block_count;
3537 const BYTE *src_row;
3538 BYTE *dst_row;
3539 UINT x, y;
3541 src_row = src_data;
3542 dst_row = dst_data;
3544 row_block_count = (update_w + format->block_width - 1) / format->block_width;
3546 if (!flags)
3548 for (y = 0; y < update_h; y += format->block_height)
3550 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
3551 src_row += src_pitch;
3552 dst_row += dst_pitch;
3555 return WINED3D_OK;
3558 if (flags == WINED3D_BLT_FX && fx->fx == WINEDDBLTFX_MIRRORUPDOWN)
3560 src_row += (((update_h / format->block_height) - 1) * src_pitch);
3562 switch (format->id)
3564 case WINED3DFMT_DXT1:
3565 for (y = 0; y < update_h; y += format->block_height)
3567 struct block
3569 WORD color[2];
3570 BYTE control_row[4];
3573 const struct block *s = (const struct block *)src_row;
3574 struct block *d = (struct block *)dst_row;
3576 for (x = 0; x < row_block_count; ++x)
3578 d[x].color[0] = s[x].color[0];
3579 d[x].color[1] = s[x].color[1];
3580 d[x].control_row[0] = s[x].control_row[3];
3581 d[x].control_row[1] = s[x].control_row[2];
3582 d[x].control_row[2] = s[x].control_row[1];
3583 d[x].control_row[3] = s[x].control_row[0];
3585 src_row -= src_pitch;
3586 dst_row += dst_pitch;
3588 return WINED3D_OK;
3590 case WINED3DFMT_DXT2:
3591 case WINED3DFMT_DXT3:
3592 for (y = 0; y < update_h; y += format->block_height)
3594 struct block
3596 WORD alpha_row[4];
3597 WORD color[2];
3598 BYTE control_row[4];
3601 const struct block *s = (const struct block *)src_row;
3602 struct block *d = (struct block *)dst_row;
3604 for (x = 0; x < row_block_count; ++x)
3606 d[x].alpha_row[0] = s[x].alpha_row[3];
3607 d[x].alpha_row[1] = s[x].alpha_row[2];
3608 d[x].alpha_row[2] = s[x].alpha_row[1];
3609 d[x].alpha_row[3] = s[x].alpha_row[0];
3610 d[x].color[0] = s[x].color[0];
3611 d[x].color[1] = s[x].color[1];
3612 d[x].control_row[0] = s[x].control_row[3];
3613 d[x].control_row[1] = s[x].control_row[2];
3614 d[x].control_row[2] = s[x].control_row[1];
3615 d[x].control_row[3] = s[x].control_row[0];
3617 src_row -= src_pitch;
3618 dst_row += dst_pitch;
3620 return WINED3D_OK;
3622 default:
3623 FIXME("Compressed flip not implemented for format %s.\n",
3624 debug_d3dformat(format->id));
3625 return E_NOTIMPL;
3629 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3630 debug_d3dformat(format->id), flags, flags & WINED3D_BLT_FX ? fx->fx : 0);
3632 return E_NOTIMPL;
3635 static HRESULT surface_cpu_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
3636 const struct wined3d_box *dst_box, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
3637 const struct wined3d_box *src_box, DWORD flags, const struct wined3d_blt_fx *fx,
3638 enum wined3d_texture_filter_type filter)
3640 unsigned int bpp, src_height, src_width, dst_height, dst_width, row_byte_count;
3641 const struct wined3d_format *src_format, *dst_format;
3642 struct wined3d_texture *converted_texture = NULL;
3643 unsigned int src_fmt_flags, dst_fmt_flags;
3644 struct wined3d_map_desc dst_map, src_map;
3645 const BYTE *sbase = NULL;
3646 HRESULT hr = WINED3D_OK;
3647 BOOL same_sub_resource;
3648 const BYTE *sbuf;
3649 BYTE *dbuf;
3650 int x, y;
3652 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3653 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3654 dst_texture, dst_sub_resource_idx, debug_box(dst_box), src_texture,
3655 src_sub_resource_idx, debug_box(src_box), flags, fx, debug_d3dtexturefiltertype(filter));
3657 if (src_texture == dst_texture && src_sub_resource_idx == dst_sub_resource_idx)
3659 same_sub_resource = TRUE;
3660 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, NULL, 0);
3661 src_map = dst_map;
3662 src_format = dst_texture->resource.format;
3663 dst_format = src_format;
3664 dst_fmt_flags = dst_texture->resource.format_flags;
3665 src_fmt_flags = dst_fmt_flags;
3667 else
3669 same_sub_resource = FALSE;
3670 dst_format = dst_texture->resource.format;
3671 dst_fmt_flags = dst_texture->resource.format_flags;
3672 if (src_texture)
3674 if (dst_texture->resource.format->id != src_texture->resource.format->id)
3676 if (!(converted_texture = surface_convert_format(src_texture, src_sub_resource_idx, dst_format)))
3678 /* The conv function writes a FIXME */
3679 WARN("Cannot convert source surface format to dest format.\n");
3680 goto release;
3682 src_texture = converted_texture;
3683 src_sub_resource_idx = 0;
3685 wined3d_resource_map(&src_texture->resource, src_sub_resource_idx, &src_map, NULL, WINED3D_MAP_READONLY);
3686 src_format = src_texture->resource.format;
3687 src_fmt_flags = src_texture->resource.format_flags;
3689 else
3691 src_format = dst_format;
3692 src_fmt_flags = dst_fmt_flags;
3695 wined3d_resource_map(&dst_texture->resource, dst_sub_resource_idx, &dst_map, dst_box, 0);
3698 bpp = dst_format->byte_count;
3699 src_height = src_box->bottom - src_box->top;
3700 src_width = src_box->right - src_box->left;
3701 dst_height = dst_box->bottom - dst_box->top;
3702 dst_width = dst_box->right - dst_box->left;
3703 row_byte_count = dst_width * bpp;
3705 if (src_texture)
3706 sbase = (BYTE *)src_map.data
3707 + ((src_box->top / src_format->block_height) * src_map.row_pitch)
3708 + ((src_box->left / src_format->block_width) * src_format->block_byte_count);
3709 if (same_sub_resource)
3710 dbuf = (BYTE *)dst_map.data
3711 + ((dst_box->top / dst_format->block_height) * dst_map.row_pitch)
3712 + ((dst_box->left / dst_format->block_width) * dst_format->block_byte_count);
3713 else
3714 dbuf = dst_map.data;
3716 if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
3718 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
3720 if (same_sub_resource)
3722 FIXME("Only plain blits supported on compressed surfaces.\n");
3723 hr = E_NOTIMPL;
3724 goto release;
3727 if (src_height != dst_height || src_width != dst_width)
3729 WARN("Stretching not supported on compressed surfaces.\n");
3730 hr = WINED3DERR_INVALIDCALL;
3731 goto release;
3734 if (!wined3d_texture_check_block_align(src_texture,
3735 src_sub_resource_idx % src_texture->level_count, src_box))
3737 WARN("Source rectangle not block-aligned.\n");
3738 hr = WINED3DERR_INVALIDCALL;
3739 goto release;
3742 if (!wined3d_texture_check_block_align(dst_texture,
3743 dst_sub_resource_idx % dst_texture->level_count, dst_box))
3745 WARN("Destination rectangle not block-aligned.\n");
3746 hr = WINED3DERR_INVALIDCALL;
3747 goto release;
3750 hr = surface_cpu_blt_compressed(sbase, dbuf,
3751 src_map.row_pitch, dst_map.row_pitch, dst_width, dst_height,
3752 src_format, flags, fx);
3753 goto release;
3756 /* First, all the 'source-less' blits */
3757 if (flags & WINED3D_BLT_COLOR_FILL)
3759 hr = _Blt_ColorFill(dbuf, dst_width, dst_height, bpp, dst_map.row_pitch, fx->fill_color);
3760 flags &= ~WINED3D_BLT_COLOR_FILL;
3763 if (flags & WINED3D_BLT_DEPTH_FILL)
3764 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3766 /* Now the 'with source' blits. */
3767 if (src_texture)
3769 int sx, xinc, sy, yinc;
3771 if (!dst_width || !dst_height) /* Hmm... stupid program? */
3772 goto release;
3774 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
3775 && (src_width != dst_width || src_height != dst_height))
3777 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3778 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
3781 xinc = (src_width << 16) / dst_width;
3782 yinc = (src_height << 16) / dst_height;
3784 if (!flags)
3786 /* No effects, we can cheat here. */
3787 if (dst_width == src_width)
3789 if (dst_height == src_height)
3791 /* No stretching in either direction. This needs to be as
3792 * fast as possible. */
3793 sbuf = sbase;
3795 /* Check for overlapping surfaces. */
3796 if (!same_sub_resource || dst_box->top < src_box->top
3797 || dst_box->right <= src_box->left || src_box->right <= dst_box->left)
3799 /* No overlap, or dst above src, so copy from top downwards. */
3800 for (y = 0; y < dst_height; ++y)
3802 memcpy(dbuf, sbuf, row_byte_count);
3803 sbuf += src_map.row_pitch;
3804 dbuf += dst_map.row_pitch;
3807 else if (dst_box->top > src_box->top)
3809 /* Copy from bottom upwards. */
3810 sbuf += src_map.row_pitch * dst_height;
3811 dbuf += dst_map.row_pitch * dst_height;
3812 for (y = 0; y < dst_height; ++y)
3814 sbuf -= src_map.row_pitch;
3815 dbuf -= dst_map.row_pitch;
3816 memcpy(dbuf, sbuf, row_byte_count);
3819 else
3821 /* Src and dst overlapping on the same line, use memmove. */
3822 for (y = 0; y < dst_height; ++y)
3824 memmove(dbuf, sbuf, row_byte_count);
3825 sbuf += src_map.row_pitch;
3826 dbuf += dst_map.row_pitch;
3830 else
3832 /* Stretching in y direction only. */
3833 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3835 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3836 memcpy(dbuf, sbuf, row_byte_count);
3837 dbuf += dst_map.row_pitch;
3841 else
3843 /* Stretching in X direction. */
3844 int last_sy = -1;
3845 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
3847 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
3849 if ((sy >> 16) == (last_sy >> 16))
3851 /* This source row is the same as last source row -
3852 * Copy the already stretched row. */
3853 memcpy(dbuf, dbuf - dst_map.row_pitch, row_byte_count);
3855 else
3857 #define STRETCH_ROW(type) \
3858 do { \
3859 const type *s = (const type *)sbuf; \
3860 type *d = (type *)dbuf; \
3861 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3862 d[x] = s[sx >> 16]; \
3863 } while(0)
3865 switch(bpp)
3867 case 1:
3868 STRETCH_ROW(BYTE);
3869 break;
3870 case 2:
3871 STRETCH_ROW(WORD);
3872 break;
3873 case 4:
3874 STRETCH_ROW(DWORD);
3875 break;
3876 case 3:
3878 const BYTE *s;
3879 BYTE *d = dbuf;
3880 for (x = sx = 0; x < dst_width; x++, sx+= xinc)
3882 DWORD pixel;
3884 s = sbuf + 3 * (sx >> 16);
3885 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3886 d[0] = (pixel ) & 0xff;
3887 d[1] = (pixel >> 8) & 0xff;
3888 d[2] = (pixel >> 16) & 0xff;
3889 d += 3;
3891 break;
3893 default:
3894 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
3895 hr = WINED3DERR_NOTAVAILABLE;
3896 goto error;
3898 #undef STRETCH_ROW
3900 dbuf += dst_map.row_pitch;
3901 last_sy = sy;
3905 else
3907 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
3908 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
3909 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
3910 if (flags & (WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3911 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE))
3913 /* The color keying flags are checked for correctness in ddraw */
3914 if (flags & WINED3D_BLT_SRC_CKEY)
3916 keylow = src_texture->async.src_blt_color_key.color_space_low_value;
3917 keyhigh = src_texture->async.src_blt_color_key.color_space_high_value;
3919 else if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
3921 keylow = fx->src_color_key.color_space_low_value;
3922 keyhigh = fx->src_color_key.color_space_high_value;
3925 if (flags & WINED3D_BLT_DST_CKEY)
3927 /* Destination color keys are taken from the source surface! */
3928 destkeylow = src_texture->async.dst_blt_color_key.color_space_low_value;
3929 destkeyhigh = src_texture->async.dst_blt_color_key.color_space_high_value;
3931 else if (flags & WINED3D_BLT_DST_CKEY_OVERRIDE)
3933 destkeylow = fx->dst_color_key.color_space_low_value;
3934 destkeyhigh = fx->dst_color_key.color_space_high_value;
3937 if (bpp == 1)
3939 keymask = 0xff;
3941 else
3943 DWORD masks[3];
3944 get_color_masks(src_format, masks);
3945 keymask = masks[0]
3946 | masks[1]
3947 | masks[2];
3949 flags &= ~(WINED3D_BLT_SRC_CKEY | WINED3D_BLT_DST_CKEY
3950 | WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_DST_CKEY_OVERRIDE);
3953 if (flags & WINED3D_BLT_FX)
3955 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
3956 LONG tmpxy;
3957 dTopLeft = dbuf;
3958 dTopRight = dbuf + ((dst_width - 1) * bpp);
3959 dBottomLeft = dTopLeft + ((dst_height - 1) * dst_map.row_pitch);
3960 dBottomRight = dBottomLeft + ((dst_width - 1) * bpp);
3962 if (fx->fx & WINEDDBLTFX_ARITHSTRETCHY)
3964 /* I don't think we need to do anything about this flag */
3965 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3967 if (fx->fx & WINEDDBLTFX_MIRRORLEFTRIGHT)
3969 tmp = dTopRight;
3970 dTopRight = dTopLeft;
3971 dTopLeft = tmp;
3972 tmp = dBottomRight;
3973 dBottomRight = dBottomLeft;
3974 dBottomLeft = tmp;
3975 dstxinc = dstxinc * -1;
3977 if (fx->fx & WINEDDBLTFX_MIRRORUPDOWN)
3979 tmp = dTopLeft;
3980 dTopLeft = dBottomLeft;
3981 dBottomLeft = tmp;
3982 tmp = dTopRight;
3983 dTopRight = dBottomRight;
3984 dBottomRight = tmp;
3985 dstyinc = dstyinc * -1;
3987 if (fx->fx & WINEDDBLTFX_NOTEARING)
3989 /* I don't think we need to do anything about this flag */
3990 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
3992 if (fx->fx & WINEDDBLTFX_ROTATE180)
3994 tmp = dBottomRight;
3995 dBottomRight = dTopLeft;
3996 dTopLeft = tmp;
3997 tmp = dBottomLeft;
3998 dBottomLeft = dTopRight;
3999 dTopRight = tmp;
4000 dstxinc = dstxinc * -1;
4001 dstyinc = dstyinc * -1;
4003 if (fx->fx & WINEDDBLTFX_ROTATE270)
4005 tmp = dTopLeft;
4006 dTopLeft = dBottomLeft;
4007 dBottomLeft = dBottomRight;
4008 dBottomRight = dTopRight;
4009 dTopRight = tmp;
4010 tmpxy = dstxinc;
4011 dstxinc = dstyinc;
4012 dstyinc = tmpxy;
4013 dstxinc = dstxinc * -1;
4015 if (fx->fx & WINEDDBLTFX_ROTATE90)
4017 tmp = dTopLeft;
4018 dTopLeft = dTopRight;
4019 dTopRight = dBottomRight;
4020 dBottomRight = dBottomLeft;
4021 dBottomLeft = tmp;
4022 tmpxy = dstxinc;
4023 dstxinc = dstyinc;
4024 dstyinc = tmpxy;
4025 dstyinc = dstyinc * -1;
4027 if (fx->fx & WINEDDBLTFX_ZBUFFERBASEDEST)
4029 /* I don't think we need to do anything about this flag */
4030 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
4032 dbuf = dTopLeft;
4033 flags &= ~(WINED3D_BLT_FX);
4036 #define COPY_COLORKEY_FX(type) \
4037 do { \
4038 const type *s; \
4039 type *d = (type *)dbuf, *dx, tmp; \
4040 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
4042 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
4043 dx = d; \
4044 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
4046 tmp = s[sx >> 16]; \
4047 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
4048 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
4050 dx[0] = tmp; \
4052 dx = (type *)(((BYTE *)dx) + dstxinc); \
4054 d = (type *)(((BYTE *)d) + dstyinc); \
4056 } while(0)
4058 switch (bpp)
4060 case 1:
4061 COPY_COLORKEY_FX(BYTE);
4062 break;
4063 case 2:
4064 COPY_COLORKEY_FX(WORD);
4065 break;
4066 case 4:
4067 COPY_COLORKEY_FX(DWORD);
4068 break;
4069 case 3:
4071 const BYTE *s;
4072 BYTE *d = dbuf, *dx;
4073 for (y = sy = 0; y < dst_height; ++y, sy += yinc)
4075 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
4076 dx = d;
4077 for (x = sx = 0; x < dst_width; ++x, sx+= xinc)
4079 DWORD pixel, dpixel = 0;
4080 s = sbuf + 3 * (sx>>16);
4081 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
4082 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
4083 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
4084 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
4086 dx[0] = (pixel ) & 0xff;
4087 dx[1] = (pixel >> 8) & 0xff;
4088 dx[2] = (pixel >> 16) & 0xff;
4090 dx += dstxinc;
4092 d += dstyinc;
4094 break;
4096 default:
4097 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
4098 (flags & WINED3D_BLT_SRC_CKEY) ? "Source" : "Destination", bpp * 8);
4099 hr = WINED3DERR_NOTAVAILABLE;
4100 goto error;
4101 #undef COPY_COLORKEY_FX
4106 error:
4107 if (flags)
4108 FIXME(" Unsupported flags %#x.\n", flags);
4110 release:
4111 wined3d_resource_unmap(&dst_texture->resource, dst_sub_resource_idx);
4112 if (src_texture && !same_sub_resource)
4113 wined3d_resource_unmap(&src_texture->resource, src_sub_resource_idx);
4114 if (converted_texture)
4115 wined3d_texture_decref(converted_texture);
4117 return hr;
4120 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
4121 const RECT *rect, const struct wined3d_color *color)
4123 const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
4124 static const struct wined3d_box src_box;
4125 struct wined3d_blt_fx fx;
4127 fx.fill_color = wined3d_format_convert_from_float(view->format, color);
4128 return surface_cpu_blt(wined3d_texture_from_resource(view->resource), view->sub_resource_idx,
4129 &box, NULL, 0, &src_box, WINED3D_BLT_COLOR_FILL, &fx, WINED3D_TEXF_POINT);
4132 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
4133 struct wined3d_rendertarget_view *view, const RECT *rect, DWORD clear_flags,
4134 float depth, DWORD stencil)
4136 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
4137 return WINED3DERR_INVALIDCALL;
4140 static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, DWORD filter,
4141 struct wined3d_surface *src_surface, const RECT *src_rect,
4142 struct wined3d_surface *dst_surface, const RECT *dst_rect,
4143 const struct wined3d_color_key *color_key)
4145 /* FIXME: Remove error returns from surface_blt_cpu. */
4146 ERR("Blit method not implemented by cpu_blit.\n");
4149 const struct blit_shader cpu_blit = {
4150 cpu_blit_alloc,
4151 cpu_blit_free,
4152 cpu_blit_set,
4153 cpu_blit_unset,
4154 cpu_blit_supported,
4155 cpu_blit_color_fill,
4156 cpu_blit_depth_fill,
4157 cpu_blit_blit_surface,
4160 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
4161 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
4162 const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
4164 struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
4165 struct wined3d_box src_box = {src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1};
4166 unsigned int dst_sub_resource_idx = surface_get_sub_resource_idx(dst_surface);
4167 struct wined3d_texture *dst_texture = dst_surface->container;
4168 struct wined3d_device *device = dst_texture->resource.device;
4169 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
4170 struct wined3d_texture *src_texture = NULL;
4171 unsigned int dst_w, dst_h, src_w, src_h;
4172 unsigned int src_sub_resource_idx = 0;
4173 DWORD src_ds_flags, dst_ds_flags;
4174 BOOL scale, convert;
4176 static const DWORD simple_blit = WINED3D_BLT_ASYNC
4177 | WINED3D_BLT_COLOR_FILL
4178 | WINED3D_BLT_SRC_CKEY
4179 | WINED3D_BLT_SRC_CKEY_OVERRIDE
4180 | WINED3D_BLT_WAIT
4181 | WINED3D_BLT_DEPTH_FILL
4182 | WINED3D_BLT_DO_NOT_WAIT
4183 | WINED3D_BLT_ALPHA_TEST;
4185 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4186 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
4187 flags, fx, debug_d3dtexturefiltertype(filter));
4188 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture->resource.usage));
4190 if (fx)
4192 TRACE("fx %#x.\n", fx->fx);
4193 TRACE("fill_color 0x%08x.\n", fx->fill_color);
4194 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
4195 fx->dst_color_key.color_space_low_value,
4196 fx->dst_color_key.color_space_high_value);
4197 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
4198 fx->src_color_key.color_space_low_value,
4199 fx->src_color_key.color_space_high_value);
4202 if (src_surface)
4204 src_texture = src_surface->container;
4205 src_sub_resource_idx = surface_get_sub_resource_idx(src_surface);
4208 if (dst_texture->sub_resources[dst_sub_resource_idx].map_count
4209 || (src_texture && src_texture->sub_resources[src_sub_resource_idx].map_count))
4211 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
4212 return WINEDDERR_SURFACEBUSY;
4215 dst_w = wined3d_texture_get_level_width(dst_texture, dst_surface->texture_level);
4216 dst_h = wined3d_texture_get_level_height(dst_texture, dst_surface->texture_level);
4217 if (dst_rect->left >= dst_rect->right || dst_rect->top >= dst_rect->bottom
4218 || dst_rect->left > dst_w || dst_rect->left < 0
4219 || dst_rect->top > dst_h || dst_rect->top < 0
4220 || dst_rect->right > dst_w || dst_rect->right < 0
4221 || dst_rect->bottom > dst_h || dst_rect->bottom < 0)
4223 WARN("The application gave us a bad destination rectangle.\n");
4224 return WINEDDERR_INVALIDRECT;
4227 if (src_texture)
4229 src_w = wined3d_texture_get_level_width(src_texture, src_surface->texture_level);
4230 src_h = wined3d_texture_get_level_height(src_texture, src_surface->texture_level);
4231 if (src_rect->left >= src_rect->right || src_rect->top >= src_rect->bottom
4232 || src_rect->left > src_w || src_rect->left < 0
4233 || src_rect->top > src_h || src_rect->top < 0
4234 || src_rect->right > src_w || src_rect->right < 0
4235 || src_rect->bottom > src_h || src_rect->bottom < 0)
4237 WARN("The application gave us a bad source rectangle.\n");
4238 return WINEDDERR_INVALIDRECT;
4242 if (!fx || !(fx->fx))
4243 flags &= ~WINED3D_BLT_FX;
4245 if (flags & WINED3D_BLT_WAIT)
4246 flags &= ~WINED3D_BLT_WAIT;
4248 if (flags & WINED3D_BLT_ASYNC)
4250 static unsigned int once;
4252 if (!once++)
4253 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
4254 flags &= ~WINED3D_BLT_ASYNC;
4257 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
4258 if (flags & WINED3D_BLT_DO_NOT_WAIT)
4260 static unsigned int once;
4262 if (!once++)
4263 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
4264 flags &= ~WINED3D_BLT_DO_NOT_WAIT;
4267 if (!device->d3d_initialized)
4269 WARN("D3D not initialized, using fallback.\n");
4270 goto cpu;
4273 /* We want to avoid invalidating the sysmem location for converted
4274 * surfaces, since otherwise we'd have to convert the data back when
4275 * locking them. */
4276 if (dst_texture->flags & WINED3D_TEXTURE_CONVERTED || dst_texture->resource.format->convert
4277 || wined3d_format_get_color_key_conversion(dst_texture, TRUE))
4279 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
4280 goto cpu;
4283 if (flags & ~simple_blit)
4285 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
4286 goto fallback;
4289 if (src_texture)
4290 src_swapchain = src_texture->swapchain;
4291 else
4292 src_swapchain = NULL;
4294 dst_swapchain = dst_texture->swapchain;
4296 /* This isn't strictly needed. FBO blits for example could deal with
4297 * cross-swapchain blits by first downloading the source to a texture
4298 * before switching to the destination context. We just have this here to
4299 * not have to deal with the issue, since cross-swapchain blits should be
4300 * rare. */
4301 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
4303 FIXME("Using fallback for cross-swapchain blit.\n");
4304 goto fallback;
4307 scale = src_texture
4308 && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
4309 || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
4310 convert = src_texture && src_texture->resource.format->id != dst_texture->resource.format->id;
4312 dst_ds_flags = dst_texture->resource.format_flags
4313 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4314 if (src_texture)
4315 src_ds_flags = src_texture->resource.format_flags
4316 & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
4317 else
4318 src_ds_flags = 0;
4320 if (src_ds_flags || dst_ds_flags)
4322 if (flags & WINED3D_BLT_DEPTH_FILL)
4324 float depth;
4326 TRACE("Depth fill.\n");
4328 if (!surface_convert_depth_to_float(dst_surface, fx->fill_color, &depth))
4329 return WINED3DERR_INVALIDCALL;
4331 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
4332 return WINED3D_OK;
4334 else
4336 if (src_ds_flags != dst_ds_flags)
4338 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
4339 return WINED3DERR_INVALIDCALL;
4342 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_texture->resource.draw_binding,
4343 src_rect, dst_surface, dst_texture->resource.draw_binding, dst_rect)))
4344 return WINED3D_OK;
4347 else
4349 struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
4350 const struct blit_shader *blitter;
4352 dst_sub_resource = surface_get_sub_resource(dst_surface);
4353 src_sub_resource = src_texture ? &src_texture->sub_resources[src_sub_resource_idx] : NULL;
4355 /* In principle this would apply to depth blits as well, but we don't
4356 * implement those in the CPU blitter at the moment. */
4357 if ((dst_sub_resource->locations & dst_surface->resource.map_binding)
4358 && (!src_texture || (src_sub_resource->locations & src_surface->resource.map_binding)))
4360 if (scale)
4361 TRACE("Not doing sysmem blit because of scaling.\n");
4362 else if (convert)
4363 TRACE("Not doing sysmem blit because of format conversion.\n");
4364 else
4365 goto cpu;
4368 if (flags & WINED3D_BLT_COLOR_FILL)
4370 struct wined3d_color color;
4371 const struct wined3d_palette *palette = dst_swapchain ? dst_swapchain->palette : NULL;
4373 TRACE("Color fill.\n");
4375 if (!wined3d_format_convert_color_to_float(dst_texture->resource.format,
4376 palette, fx->fill_color, &color))
4377 goto fallback;
4379 if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
4380 return WINED3D_OK;
4382 else
4384 enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
4385 const struct wined3d_color_key *color_key = NULL;
4387 TRACE("Color blit.\n");
4388 if (flags & WINED3D_BLT_SRC_CKEY_OVERRIDE)
4390 color_key = &fx->src_color_key;
4391 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4393 else if (flags & WINED3D_BLT_SRC_CKEY)
4395 color_key = &src_texture->async.src_blt_color_key;
4396 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
4398 else if (flags & WINED3D_BLT_ALPHA_TEST)
4400 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
4402 else if ((src_sub_resource->locations & WINED3D_LOCATION_SYSMEM)
4403 && !(dst_sub_resource->locations & WINED3D_LOCATION_SYSMEM))
4405 /* Upload */
4406 if (scale)
4407 TRACE("Not doing upload because of scaling.\n");
4408 else if (convert)
4409 TRACE("Not doing upload because of format conversion.\n");
4410 else
4412 POINT dst_point = {dst_rect->left, dst_rect->top};
4414 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
4416 if (!wined3d_resource_is_offscreen(&dst_texture->resource))
4418 struct wined3d_context *context = context_acquire(device, dst_surface);
4419 surface_load_location(dst_surface, context, dst_texture->resource.draw_binding);
4420 context_release(context);
4422 return WINED3D_OK;
4426 else if (dst_swapchain && dst_swapchain->back_buffers
4427 && dst_texture == dst_swapchain->front_buffer
4428 && src_texture == dst_swapchain->back_buffers[0])
4430 /* Use present for back -> front blits. The idea behind this is
4431 * that present is potentially faster than a blit, in particular
4432 * when FBO blits aren't available. Some ddraw applications like
4433 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4434 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4435 * applications can't blit directly to the frontbuffer. */
4436 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
4438 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4440 /* Set the swap effect to COPY, we don't want the backbuffer
4441 * to become undefined. */
4442 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
4443 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, 0);
4444 dst_swapchain->desc.swap_effect = swap_effect;
4446 return WINED3D_OK;
4449 if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
4450 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4451 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format))
4453 struct wined3d_context *context;
4454 TRACE("Using FBO blit.\n");
4456 context = context_acquire(device, NULL);
4457 surface_blt_fbo(device, context, filter,
4458 src_surface, src_texture->resource.draw_binding, src_rect,
4459 dst_surface, dst_texture->resource.draw_binding, dst_rect);
4460 context_release(context);
4462 wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx,
4463 dst_texture->resource.draw_binding);
4464 wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx,
4465 ~dst_texture->resource.draw_binding);
4467 return WINED3D_OK;
4470 blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
4471 src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
4472 dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format);
4473 if (blitter)
4475 blitter->blit_surface(device, blit_op, filter, src_surface,
4476 src_rect, dst_surface, dst_rect, color_key);
4477 return WINED3D_OK;
4482 fallback:
4483 /* Special cases for render targets. */
4484 if (SUCCEEDED(surface_blt_special(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter)))
4485 return WINED3D_OK;
4487 cpu:
4488 return surface_cpu_blt(dst_texture, dst_sub_resource_idx, &dst_box,
4489 src_texture, src_sub_resource_idx, &src_box, flags, fx, filter);
4492 HRESULT wined3d_surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
4493 const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags)
4495 unsigned int sub_resource_idx = layer * container->level_count + level;
4496 struct wined3d_device *device = container->resource.device;
4497 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4498 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format);
4499 BOOL lockable = flags & WINED3D_TEXTURE_CREATE_MAPPABLE;
4500 UINT multisample_quality = desc->multisample_quality;
4501 unsigned int resource_size;
4502 HRESULT hr;
4504 if (container->flags & WINED3D_TEXTURE_COND_NP2_EMULATED)
4506 unsigned int pow2_width = 1, pow2_height = 1;
4508 /* Find the nearest pow2 match. */
4509 while (pow2_width < desc->width)
4510 pow2_width <<= 1;
4511 while (pow2_height < desc->height)
4512 pow2_height <<= 1;
4514 surface->pow2Width = pow2_width;
4515 surface->pow2Height = pow2_height;
4517 else
4519 surface->pow2Width = desc->width;
4520 surface->pow2Height = desc->height;
4523 /* Quick lockable sanity check.
4524 * TODO: remove this after surfaces, usage and lockability have been debugged properly
4525 * this function is too deep to need to care about things like this.
4526 * Levels need to be checked too, since they all affect what can be done. */
4527 switch (desc->pool)
4529 case WINED3D_POOL_MANAGED:
4530 if (desc->usage & WINED3DUSAGE_DYNAMIC)
4531 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
4532 break;
4534 case WINED3D_POOL_DEFAULT:
4535 if (lockable && !(desc->usage & (WINED3DUSAGE_DYNAMIC
4536 | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4537 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
4538 break;
4540 case WINED3D_POOL_SCRATCH:
4541 case WINED3D_POOL_SYSTEM_MEM:
4542 break;
4544 default:
4545 FIXME("Unknown pool %#x.\n", desc->pool);
4546 break;
4549 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->pool != WINED3D_POOL_DEFAULT)
4550 FIXME("Trying to create a render target that isn't in the default pool.\n");
4552 /* FIXME: Check that the format is supported by the device. */
4554 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, 1);
4555 if (!resource_size)
4556 return WINED3DERR_INVALIDCALL;
4558 if (FAILED(hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE,
4559 format, desc->multisample_type, multisample_quality, desc->usage, desc->pool, desc->width, desc->height,
4560 1, resource_size, NULL, &wined3d_null_parent_ops, &surface_resource_ops)))
4562 WARN("Failed to initialize resource, returning %#x.\n", hr);
4563 return hr;
4566 surface->container = container;
4567 surface->texture_target = target;
4568 surface->texture_level = level;
4569 surface->texture_layer = layer;
4571 list_init(&surface->renderbuffers);
4572 list_init(&surface->overlays);
4574 /* Flags */
4575 if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
4576 surface->flags |= SFLAG_DISCARD;
4577 if (lockable || desc->format == WINED3DFMT_D16_LOCKABLE)
4578 surface->resource.access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
4580 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4581 if (container->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4582 container->sub_resources[sub_resource_idx].locations = WINED3D_LOCATION_DISCARDED;
4584 if (wined3d_texture_use_pbo(container, gl_info))
4585 surface->resource.map_binding = WINED3D_LOCATION_BUFFER;
4587 /* Similar to lockable rendertargets above, creating the DIB section
4588 * during surface initialization prevents the sysmem pointer from changing
4589 * after a wined3d_texture_get_dc() call. */
4590 if ((desc->usage & WINED3DUSAGE_OWNDC) || (device->wined3d->flags & WINED3D_NO3D))
4592 if (FAILED(hr = surface_create_dib_section(surface)))
4594 wined3d_surface_cleanup(surface);
4595 return hr;
4597 surface->resource.map_binding = WINED3D_LOCATION_DIB;
4600 if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
4602 wined3d_resource_free_sysmem(&surface->resource);
4603 wined3d_texture_validate_location(container, sub_resource_idx, WINED3D_LOCATION_DIB);
4604 wined3d_texture_invalidate_location(container, sub_resource_idx, WINED3D_LOCATION_SYSMEM);
4607 return hr;
4610 /* Context activation is done by the caller. Context may be NULL in
4611 * WINED3D_NO3D mode. */
4612 void wined3d_surface_prepare(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4614 struct wined3d_texture *texture = surface->container;
4616 switch (location)
4618 case WINED3D_LOCATION_SYSMEM:
4619 surface_prepare_system_memory(surface);
4620 break;
4622 case WINED3D_LOCATION_USER_MEMORY:
4623 if (!texture->user_memory)
4624 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
4625 break;
4627 case WINED3D_LOCATION_DIB:
4628 if (!surface->dib.bitmap_data)
4629 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
4630 break;
4632 case WINED3D_LOCATION_BUFFER:
4633 wined3d_texture_prepare_buffer_object(texture,
4634 surface_get_sub_resource_idx(surface), context->gl_info);
4635 break;
4637 case WINED3D_LOCATION_TEXTURE_RGB:
4638 wined3d_texture_prepare_texture(texture, context, FALSE);
4639 break;
4641 case WINED3D_LOCATION_TEXTURE_SRGB:
4642 wined3d_texture_prepare_texture(texture, context, TRUE);
4643 break;
4645 case WINED3D_LOCATION_RB_MULTISAMPLE:
4646 surface_prepare_rb(surface, context->gl_info, TRUE);
4647 break;
4649 case WINED3D_LOCATION_RB_RESOLVED:
4650 surface_prepare_rb(surface, context->gl_info, FALSE);
4651 break;