vbscript: Added support for title and type arguments of MsgBox.
[wine.git] / dlls / wined3d / surface.c
blobd384d789327c4cff8ba5b81d13c04df7e88649e1
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_surface);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d);
37 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
39 static const DWORD surface_simple_locations =
40 WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_USER_MEMORY
41 | WINED3D_LOCATION_DIB | WINED3D_LOCATION_BUFFER;
43 static void surface_cleanup(struct wined3d_surface *surface)
45 struct wined3d_surface *overlay, *cur;
47 TRACE("surface %p.\n", surface);
49 if (surface->pbo || surface->rb_multisample
50 || surface->rb_resolved || !list_empty(&surface->renderbuffers))
52 struct wined3d_renderbuffer_entry *entry, *entry2;
53 const struct wined3d_gl_info *gl_info;
54 struct wined3d_context *context;
56 context = context_acquire(surface->resource.device, NULL);
57 gl_info = context->gl_info;
59 if (surface->pbo)
61 TRACE("Deleting PBO %u.\n", surface->pbo);
62 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
65 if (surface->rb_multisample)
67 TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
68 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
71 if (surface->rb_resolved)
73 TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved);
74 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
77 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
79 TRACE("Deleting renderbuffer %u.\n", entry->id);
80 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
81 HeapFree(GetProcessHeap(), 0, entry);
84 context_release(context);
87 if (surface->flags & SFLAG_DIBSECTION)
89 DeleteDC(surface->hDC);
90 DeleteObject(surface->dib.DIBsection);
91 surface->dib.bitmap_data = NULL;
94 if (surface->overlay_dest)
95 list_remove(&surface->overlay_entry);
97 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry)
99 list_remove(&overlay->overlay_entry);
100 overlay->overlay_dest = NULL;
103 resource_cleanup(&surface->resource);
106 void surface_update_draw_binding(struct wined3d_surface *surface)
108 if (!surface_is_offscreen(surface) || wined3d_settings.offscreen_rendering_mode != ORM_FBO)
109 surface->draw_binding = WINED3D_LOCATION_DRAWABLE;
110 else if (surface->resource.multisample_type)
111 surface->draw_binding = WINED3D_LOCATION_RB_MULTISAMPLE;
112 else
113 surface->draw_binding = WINED3D_LOCATION_TEXTURE_RGB;
116 void surface_set_swapchain(struct wined3d_surface *surface, struct wined3d_swapchain *swapchain)
118 TRACE("surface %p, swapchain %p.\n", surface, swapchain);
120 if (swapchain)
122 surface->get_drawable_size = get_drawable_size_swapchain;
124 else
126 switch (wined3d_settings.offscreen_rendering_mode)
128 case ORM_FBO:
129 surface->get_drawable_size = get_drawable_size_fbo;
130 break;
132 case ORM_BACKBUFFER:
133 surface->get_drawable_size = get_drawable_size_backbuffer;
134 break;
136 default:
137 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
138 return;
142 surface->swapchain = swapchain;
143 surface_update_draw_binding(surface);
146 void surface_set_container(struct wined3d_surface *surface, struct wined3d_texture *container)
148 TRACE("surface %p, container %p.\n", surface, container);
150 if (!surface->swapchain)
152 switch (wined3d_settings.offscreen_rendering_mode)
154 case ORM_FBO:
155 surface->get_drawable_size = get_drawable_size_fbo;
156 break;
158 case ORM_BACKBUFFER:
159 surface->get_drawable_size = get_drawable_size_backbuffer;
160 break;
162 default:
163 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
164 return;
168 surface->container = container;
169 surface_update_draw_binding(surface);
172 struct blt_info
174 GLenum binding;
175 GLenum bind_target;
176 enum tex_types tex_type;
177 GLfloat coords[4][3];
180 struct float_rect
182 float l;
183 float t;
184 float r;
185 float b;
188 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
190 f->l = ((r->left * 2.0f) / w) - 1.0f;
191 f->t = ((r->top * 2.0f) / h) - 1.0f;
192 f->r = ((r->right * 2.0f) / w) - 1.0f;
193 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
196 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
198 GLfloat (*coords)[3] = info->coords;
199 struct float_rect f;
201 switch (target)
203 default:
204 FIXME("Unsupported texture target %#x\n", target);
205 /* Fall back to GL_TEXTURE_2D */
206 case GL_TEXTURE_2D:
207 info->binding = GL_TEXTURE_BINDING_2D;
208 info->bind_target = GL_TEXTURE_2D;
209 info->tex_type = tex_2d;
210 coords[0][0] = (float)rect->left / w;
211 coords[0][1] = (float)rect->top / h;
212 coords[0][2] = 0.0f;
214 coords[1][0] = (float)rect->right / w;
215 coords[1][1] = (float)rect->top / h;
216 coords[1][2] = 0.0f;
218 coords[2][0] = (float)rect->left / w;
219 coords[2][1] = (float)rect->bottom / h;
220 coords[2][2] = 0.0f;
222 coords[3][0] = (float)rect->right / w;
223 coords[3][1] = (float)rect->bottom / h;
224 coords[3][2] = 0.0f;
225 break;
227 case GL_TEXTURE_RECTANGLE_ARB:
228 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
229 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
230 info->tex_type = tex_rect;
231 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
232 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
233 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
234 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
235 break;
237 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
238 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
239 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
240 info->tex_type = tex_cube;
241 cube_coords_float(rect, w, h, &f);
243 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
244 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
245 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
246 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
247 break;
249 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
250 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
251 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
252 info->tex_type = tex_cube;
253 cube_coords_float(rect, w, h, &f);
255 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
256 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
257 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
258 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
259 break;
261 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
262 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
263 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
264 info->tex_type = tex_cube;
265 cube_coords_float(rect, w, h, &f);
267 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
268 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
269 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
270 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
271 break;
273 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
274 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
275 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
276 info->tex_type = tex_cube;
277 cube_coords_float(rect, w, h, &f);
279 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
280 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
281 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
282 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
283 break;
285 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
286 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
287 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
288 info->tex_type = tex_cube;
289 cube_coords_float(rect, w, h, &f);
291 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
292 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
293 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
294 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
295 break;
297 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
298 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
299 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
300 info->tex_type = tex_cube;
301 cube_coords_float(rect, w, h, &f);
303 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
304 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
305 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
306 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
307 break;
311 static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
313 if (rect_in)
314 *rect_out = *rect_in;
315 else
317 rect_out->left = 0;
318 rect_out->top = 0;
319 rect_out->right = surface->resource.width;
320 rect_out->bottom = surface->resource.height;
324 /* Context activation is done by the caller. */
325 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
326 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
328 const struct wined3d_gl_info *gl_info = context->gl_info;
329 struct wined3d_texture *texture = src_surface->container;
330 struct blt_info info;
332 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
334 gl_info->gl_ops.gl.p_glEnable(info.bind_target);
335 checkGLcall("glEnable(bind_target)");
337 context_bind_texture(context, info.bind_target, texture->texture_rgb.name);
339 /* Filtering for StretchRect */
340 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
341 wined3d_gl_mag_filter(magLookup, filter));
342 checkGLcall("glTexParameteri");
343 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
344 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
345 checkGLcall("glTexParameteri");
346 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
347 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
348 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
349 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
350 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
351 checkGLcall("glTexEnvi");
353 /* Draw a quad */
354 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
355 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
356 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->top);
358 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
359 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->top);
361 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
362 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->bottom);
364 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
365 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->bottom);
366 gl_info->gl_ops.gl.p_glEnd();
368 /* Unbind the texture */
369 context_bind_texture(context, info.bind_target, 0);
371 /* We changed the filtering settings on the texture. Inform the
372 * container about this to get the filters reset properly next draw. */
373 texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT;
374 texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT;
375 texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE;
376 texture->texture_rgb.states[WINED3DTEXSTA_SRGBTEXTURE] = FALSE;
379 /* Works correctly only for <= 4 bpp formats. */
380 static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
382 masks[0] = ((1 << format->red_size) - 1) << format->red_offset;
383 masks[1] = ((1 << format->green_size) - 1) << format->green_offset;
384 masks[2] = ((1 << format->blue_size) - 1) << format->blue_offset;
387 static HRESULT surface_create_dib_section(struct wined3d_surface *surface)
389 const struct wined3d_format *format = surface->resource.format;
390 SYSTEM_INFO sysInfo;
391 BITMAPINFO *b_info;
392 int extraline = 0;
393 DWORD *masks;
395 TRACE("surface %p.\n", surface);
397 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
399 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
400 return WINED3DERR_INVALIDCALL;
403 switch (format->byte_count)
405 case 2:
406 case 4:
407 /* Allocate extra space to store the RGB bit masks. */
408 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
409 break;
411 case 3:
412 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
413 break;
415 default:
416 /* Allocate extra space for a palette. */
417 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
418 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
419 break;
422 if (!b_info)
423 return E_OUTOFMEMORY;
425 /* Some applications access the surface in via DWORDs, and do not take
426 * the necessary care at the end of the surface. So we need at least
427 * 4 extra bytes at the end of the surface. Check against the page size,
428 * if the last page used for the surface has at least 4 spare bytes we're
429 * safe, otherwise add an extra line to the DIB section. */
430 GetSystemInfo(&sysInfo);
431 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
433 extraline = 1;
434 TRACE("Adding an extra line to the DIB section.\n");
437 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
438 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
439 b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count;
440 b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
441 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
442 * wined3d_surface_get_pitch(surface);
443 b_info->bmiHeader.biPlanes = 1;
444 b_info->bmiHeader.biBitCount = format->byte_count * 8;
446 b_info->bmiHeader.biXPelsPerMeter = 0;
447 b_info->bmiHeader.biYPelsPerMeter = 0;
448 b_info->bmiHeader.biClrUsed = 0;
449 b_info->bmiHeader.biClrImportant = 0;
451 /* Get the bit masks */
452 masks = (DWORD *)b_info->bmiColors;
453 switch (surface->resource.format->id)
455 case WINED3DFMT_B8G8R8_UNORM:
456 b_info->bmiHeader.biCompression = BI_RGB;
457 break;
459 case WINED3DFMT_B5G5R5X1_UNORM:
460 case WINED3DFMT_B5G5R5A1_UNORM:
461 case WINED3DFMT_B4G4R4A4_UNORM:
462 case WINED3DFMT_B4G4R4X4_UNORM:
463 case WINED3DFMT_B2G3R3_UNORM:
464 case WINED3DFMT_B2G3R3A8_UNORM:
465 case WINED3DFMT_R10G10B10A2_UNORM:
466 case WINED3DFMT_R8G8B8A8_UNORM:
467 case WINED3DFMT_R8G8B8X8_UNORM:
468 case WINED3DFMT_B10G10R10A2_UNORM:
469 case WINED3DFMT_B5G6R5_UNORM:
470 case WINED3DFMT_R16G16B16A16_UNORM:
471 b_info->bmiHeader.biCompression = BI_BITFIELDS;
472 get_color_masks(format, masks);
473 break;
475 default:
476 /* Don't know palette */
477 b_info->bmiHeader.biCompression = BI_RGB;
478 break;
481 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
482 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
483 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
484 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
486 if (!surface->dib.DIBsection)
488 ERR("Failed to create DIB section.\n");
489 HeapFree(GetProcessHeap(), 0, b_info);
490 return HRESULT_FROM_WIN32(GetLastError());
493 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
494 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
496 HeapFree(GetProcessHeap(), 0, b_info);
498 /* Now allocate a DC. */
499 surface->hDC = CreateCompatibleDC(0);
500 SelectObject(surface->hDC, surface->dib.DIBsection);
502 surface->flags |= SFLAG_DIBSECTION;
504 return WINED3D_OK;
507 static void surface_get_memory(const struct wined3d_surface *surface, struct wined3d_bo_address *data,
508 DWORD location)
510 if (location & WINED3D_LOCATION_BUFFER)
512 data->addr = NULL;
513 data->buffer_object = surface->pbo;
514 return;
516 if (location & WINED3D_LOCATION_USER_MEMORY)
518 data->addr = surface->user_memory;
519 data->buffer_object = 0;
520 return;
522 if (location & WINED3D_LOCATION_DIB)
524 data->addr = surface->dib.bitmap_data;
525 data->buffer_object = 0;
526 return;
528 if (location & WINED3D_LOCATION_SYSMEM)
530 data->addr = surface->resource.heap_memory;
531 data->buffer_object = 0;
532 return;
535 ERR("Unexpected locations %s.\n", wined3d_debug_location(location));
536 data->addr = NULL;
537 data->buffer_object = 0;
540 static void surface_prepare_buffer(struct wined3d_surface *surface)
542 struct wined3d_context *context;
543 GLenum error;
544 const struct wined3d_gl_info *gl_info;
546 if (surface->pbo)
547 return;
549 context = context_acquire(surface->resource.device, NULL);
550 gl_info = context->gl_info;
552 GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
553 error = gl_info->gl_ops.gl.p_glGetError();
554 if (!surface->pbo || error != GL_NO_ERROR)
555 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
557 TRACE("Binding PBO %u.\n", surface->pbo);
559 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
560 checkGLcall("glBindBufferARB");
562 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
563 NULL, GL_STREAM_DRAW_ARB));
564 checkGLcall("glBufferDataARB");
566 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
567 checkGLcall("glBindBufferARB");
569 context_release(context);
572 static void surface_prepare_system_memory(struct wined3d_surface *surface)
574 TRACE("surface %p.\n", surface);
576 if (surface->resource.heap_memory)
577 return;
579 /* Whatever surface we have, make sure that there is memory allocated
580 * for the downloaded copy, or a PBO to map. */
581 if (!wined3d_resource_allocate_sysmem(&surface->resource))
582 ERR("Failed to allocate system memory.\n");
584 if (surface->locations & WINED3D_LOCATION_SYSMEM)
585 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
588 void surface_prepare_map_memory(struct wined3d_surface *surface)
590 switch (surface->map_binding)
592 case WINED3D_LOCATION_SYSMEM:
593 surface_prepare_system_memory(surface);
594 break;
596 case WINED3D_LOCATION_USER_MEMORY:
597 if (!surface->user_memory)
598 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
599 break;
601 case WINED3D_LOCATION_DIB:
602 if (!surface->dib.bitmap_data)
603 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
604 break;
606 case WINED3D_LOCATION_BUFFER:
607 surface_prepare_buffer(surface);
608 break;
610 default:
611 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->map_binding));
615 static void surface_evict_sysmem(struct wined3d_surface *surface)
617 if (surface->resource.map_count || surface->flags & SFLAG_DONOTFREE)
618 return;
620 wined3d_resource_free_sysmem(&surface->resource);
621 surface_invalidate_location(surface, WINED3D_LOCATION_SYSMEM);
624 static void surface_force_reload(struct wined3d_surface *surface)
626 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
629 static void surface_release_client_storage(struct wined3d_surface *surface)
631 struct wined3d_context *context = context_acquire(surface->resource.device, NULL);
632 const struct wined3d_gl_info *gl_info = context->gl_info;
634 if (surface->container->texture_rgb.name)
636 wined3d_texture_bind_and_dirtify(surface->container, context, FALSE);
637 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
638 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
640 if (surface->container->texture_srgb.name)
642 wined3d_texture_bind_and_dirtify(surface->container, context, TRUE);
643 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
644 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
647 context_release(context);
649 surface_invalidate_location(surface, WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB);
650 surface_force_reload(surface);
653 static BOOL surface_use_pbo(const struct wined3d_surface *surface)
655 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
657 return surface->resource.pool == WINED3D_POOL_DEFAULT
658 && surface->resource.access_flags & WINED3D_RESOURCE_ACCESS_CPU
659 && gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]
660 && !surface->resource.format->convert
661 && !(surface->flags & (SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM));
664 static HRESULT surface_private_setup(struct wined3d_surface *surface)
666 /* TODO: Check against the maximum texture sizes supported by the video card. */
667 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
668 unsigned int pow2Width, pow2Height;
670 TRACE("surface %p.\n", surface);
672 /* Non-power2 support */
673 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT]
674 || gl_info->supported[ARB_TEXTURE_RECTANGLE])
676 pow2Width = surface->resource.width;
677 pow2Height = surface->resource.height;
679 else
681 /* Find the nearest pow2 match */
682 pow2Width = pow2Height = 1;
683 while (pow2Width < surface->resource.width)
684 pow2Width <<= 1;
685 while (pow2Height < surface->resource.height)
686 pow2Height <<= 1;
688 surface->pow2Width = pow2Width;
689 surface->pow2Height = pow2Height;
691 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
693 /* TODO: Add support for non power two compressed textures. */
694 if (surface->resource.format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_HEIGHT_SCALE))
696 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
697 surface, surface->resource.width, surface->resource.height);
698 return WINED3DERR_NOTAVAILABLE;
702 if (pow2Width != surface->resource.width
703 || pow2Height != surface->resource.height)
705 surface->flags |= SFLAG_NONPOW2;
708 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
709 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
711 /* One of three options:
712 * 1: Do the same as we do with NPOT and scale the texture, (any
713 * texture ops would require the texture to be scaled which is
714 * potentially slow)
715 * 2: Set the texture to the maximum size (bad idea).
716 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
717 * 4: Create the surface, but allow it to be used only for DirectDraw
718 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
719 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
720 * the render target. */
721 if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED)
723 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
724 return WINED3DERR_NOTAVAILABLE;
727 /* We should never use this surface in combination with OpenGL! */
728 TRACE("Creating an oversized surface: %ux%u.\n",
729 surface->pow2Width, surface->pow2Height);
732 switch (wined3d_settings.offscreen_rendering_mode)
734 case ORM_FBO:
735 surface->get_drawable_size = get_drawable_size_fbo;
736 break;
738 case ORM_BACKBUFFER:
739 surface->get_drawable_size = get_drawable_size_backbuffer;
740 break;
742 default:
743 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
744 return WINED3DERR_INVALIDCALL;
747 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
748 surface->locations = WINED3D_LOCATION_DISCARDED;
750 if (surface_use_pbo(surface))
751 surface->map_binding = WINED3D_LOCATION_BUFFER;
753 return WINED3D_OK;
756 static void surface_unmap(struct wined3d_surface *surface)
758 struct wined3d_device *device = surface->resource.device;
759 const struct wined3d_gl_info *gl_info;
760 struct wined3d_context *context;
762 TRACE("surface %p.\n", surface);
764 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
766 switch (surface->map_binding)
768 case WINED3D_LOCATION_SYSMEM:
769 case WINED3D_LOCATION_USER_MEMORY:
770 case WINED3D_LOCATION_DIB:
771 break;
773 case WINED3D_LOCATION_BUFFER:
774 context = context_acquire(device, NULL);
775 gl_info = context->gl_info;
777 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
778 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
779 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
780 checkGLcall("glUnmapBufferARB");
781 context_release(context);
782 break;
784 default:
785 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->map_binding));
788 if (surface->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB))
790 TRACE("Not dirtified, nothing to do.\n");
791 return;
794 if (surface->swapchain && surface->swapchain->front_buffer == surface)
795 surface_load_location(surface, surface->draw_binding);
796 else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
797 FIXME("Depth / stencil buffer locking is not implemented.\n");
800 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
802 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
803 return FALSE;
804 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
805 return FALSE;
806 return TRUE;
809 static void surface_depth_blt_fbo(const struct wined3d_device *device,
810 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
811 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
813 const struct wined3d_gl_info *gl_info;
814 struct wined3d_context *context;
815 DWORD src_mask, dst_mask;
816 GLbitfield gl_mask;
818 TRACE("device %p\n", device);
819 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
820 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect));
821 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
822 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
824 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
825 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
827 if (src_mask != dst_mask)
829 ERR("Incompatible formats %s and %s.\n",
830 debug_d3dformat(src_surface->resource.format->id),
831 debug_d3dformat(dst_surface->resource.format->id));
832 return;
835 if (!src_mask)
837 ERR("Not a depth / stencil format: %s.\n",
838 debug_d3dformat(src_surface->resource.format->id));
839 return;
842 gl_mask = 0;
843 if (src_mask & WINED3DFMT_FLAG_DEPTH)
844 gl_mask |= GL_DEPTH_BUFFER_BIT;
845 if (src_mask & WINED3DFMT_FLAG_STENCIL)
846 gl_mask |= GL_STENCIL_BUFFER_BIT;
848 /* Make sure the locations are up-to-date. Loading the destination
849 * surface isn't required if the entire surface is overwritten. */
850 surface_load_location(src_surface, src_location);
851 if (!surface_is_full_rect(dst_surface, dst_rect))
852 surface_load_location(dst_surface, dst_location);
854 context = context_acquire(device, NULL);
855 if (!context->valid)
857 context_release(context);
858 WARN("Invalid context, skipping blit.\n");
859 return;
862 gl_info = context->gl_info;
864 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, src_location);
865 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
867 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, dst_location);
868 context_set_draw_buffer(context, GL_NONE);
869 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
870 context_invalidate_state(context, STATE_FRAMEBUFFER);
872 if (gl_mask & GL_DEPTH_BUFFER_BIT)
874 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
875 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
877 if (gl_mask & GL_STENCIL_BUFFER_BIT)
879 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
881 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
882 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
884 gl_info->gl_ops.gl.p_glStencilMask(~0U);
885 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
888 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
889 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
891 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
892 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
893 checkGLcall("glBlitFramebuffer()");
895 if (wined3d_settings.strict_draw_ordering)
896 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
898 context_release(context);
901 /* Blit between surface locations. Onscreen on different swapchains is not supported.
902 * Depth / stencil is not supported. */
903 static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_texture_filter_type filter,
904 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
905 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
907 const struct wined3d_gl_info *gl_info;
908 struct wined3d_context *context;
909 RECT src_rect, dst_rect;
910 GLenum gl_filter;
911 GLenum buffer;
913 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
914 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
915 src_surface, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect_in));
916 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
917 dst_surface, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect_in));
919 src_rect = *src_rect_in;
920 dst_rect = *dst_rect_in;
922 switch (filter)
924 case WINED3D_TEXF_LINEAR:
925 gl_filter = GL_LINEAR;
926 break;
928 default:
929 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
930 case WINED3D_TEXF_NONE:
931 case WINED3D_TEXF_POINT:
932 gl_filter = GL_NEAREST;
933 break;
936 /* Resolve the source surface first if needed. */
937 if (src_location == WINED3D_LOCATION_RB_MULTISAMPLE
938 && (src_surface->resource.format->id != dst_surface->resource.format->id
939 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
940 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
941 src_location = WINED3D_LOCATION_RB_RESOLVED;
943 /* Make sure the locations are up-to-date. Loading the destination
944 * surface isn't required if the entire surface is overwritten. (And is
945 * in fact harmful if we're being called by surface_load_location() with
946 * the purpose of loading the destination surface.) */
947 surface_load_location(src_surface, src_location);
948 if (!surface_is_full_rect(dst_surface, &dst_rect))
949 surface_load_location(dst_surface, dst_location);
951 if (src_location == WINED3D_LOCATION_DRAWABLE) context = context_acquire(device, src_surface);
952 else if (dst_location == WINED3D_LOCATION_DRAWABLE) context = context_acquire(device, dst_surface);
953 else context = context_acquire(device, NULL);
955 if (!context->valid)
957 context_release(context);
958 WARN("Invalid context, skipping blit.\n");
959 return;
962 gl_info = context->gl_info;
964 if (src_location == WINED3D_LOCATION_DRAWABLE)
966 TRACE("Source surface %p is onscreen.\n", src_surface);
967 buffer = surface_get_gl_buffer(src_surface);
968 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
970 else
972 TRACE("Source surface %p is offscreen.\n", src_surface);
973 buffer = GL_COLOR_ATTACHMENT0;
976 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
977 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
978 checkGLcall("glReadBuffer()");
979 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
981 if (dst_location == WINED3D_LOCATION_DRAWABLE)
983 TRACE("Destination surface %p is onscreen.\n", dst_surface);
984 buffer = surface_get_gl_buffer(dst_surface);
985 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
987 else
989 TRACE("Destination surface %p is offscreen.\n", dst_surface);
990 buffer = GL_COLOR_ATTACHMENT0;
993 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
994 context_set_draw_buffer(context, buffer);
995 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
996 context_invalidate_state(context, STATE_FRAMEBUFFER);
998 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
999 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
1000 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
1001 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
1002 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
1004 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1005 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1007 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
1008 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
1009 checkGLcall("glBlitFramebuffer()");
1011 if (wined3d_settings.strict_draw_ordering
1012 || (dst_location == WINED3D_LOCATION_DRAWABLE
1013 && dst_surface->swapchain->front_buffer == dst_surface))
1014 gl_info->gl_ops.gl.p_glFlush();
1016 context_release(context);
1019 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
1020 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
1021 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
1023 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1024 return FALSE;
1026 /* Source and/or destination need to be on the GL side */
1027 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
1028 return FALSE;
1030 switch (blit_op)
1032 case WINED3D_BLIT_OP_COLOR_BLIT:
1033 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
1034 return FALSE;
1035 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
1036 return FALSE;
1037 break;
1039 case WINED3D_BLIT_OP_DEPTH_BLIT:
1040 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1041 return FALSE;
1042 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1043 return FALSE;
1044 break;
1046 default:
1047 return FALSE;
1050 if (!(src_format->id == dst_format->id
1051 || (is_identity_fixup(src_format->color_fixup)
1052 && is_identity_fixup(dst_format->color_fixup))))
1053 return FALSE;
1055 return TRUE;
1058 static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface,
1059 DWORD color, struct wined3d_color *float_color)
1061 const struct wined3d_format *format = surface->resource.format;
1062 const struct wined3d_palette *palette;
1064 switch (format->id)
1066 case WINED3DFMT_P8_UINT:
1067 palette = surface->swapchain ? surface->swapchain->palette : NULL;
1069 if (palette)
1071 float_color->r = palette->colors[color].rgbRed / 255.0f;
1072 float_color->g = palette->colors[color].rgbGreen / 255.0f;
1073 float_color->b = palette->colors[color].rgbBlue / 255.0f;
1075 else
1077 float_color->r = 0.0f;
1078 float_color->g = 0.0f;
1079 float_color->b = 0.0f;
1081 float_color->a = color / 255.0f;
1082 break;
1084 case WINED3DFMT_B5G6R5_UNORM:
1085 float_color->r = ((color >> 11) & 0x1f) / 31.0f;
1086 float_color->g = ((color >> 5) & 0x3f) / 63.0f;
1087 float_color->b = (color & 0x1f) / 31.0f;
1088 float_color->a = 1.0f;
1089 break;
1091 case WINED3DFMT_B8G8R8_UNORM:
1092 case WINED3DFMT_B8G8R8X8_UNORM:
1093 float_color->r = D3DCOLOR_R(color);
1094 float_color->g = D3DCOLOR_G(color);
1095 float_color->b = D3DCOLOR_B(color);
1096 float_color->a = 1.0f;
1097 break;
1099 case WINED3DFMT_B8G8R8A8_UNORM:
1100 float_color->r = D3DCOLOR_R(color);
1101 float_color->g = D3DCOLOR_G(color);
1102 float_color->b = D3DCOLOR_B(color);
1103 float_color->a = D3DCOLOR_A(color);
1104 break;
1106 default:
1107 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1108 return FALSE;
1111 return TRUE;
1114 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
1116 const struct wined3d_format *format = surface->resource.format;
1118 switch (format->id)
1120 case WINED3DFMT_S1_UINT_D15_UNORM:
1121 *float_depth = depth / (float)0x00007fff;
1122 break;
1124 case WINED3DFMT_D16_UNORM:
1125 *float_depth = depth / (float)0x0000ffff;
1126 break;
1128 case WINED3DFMT_D24_UNORM_S8_UINT:
1129 case WINED3DFMT_X8D24_UNORM:
1130 *float_depth = depth / (float)0x00ffffff;
1131 break;
1133 case WINED3DFMT_D32_UNORM:
1134 *float_depth = depth / (float)0xffffffff;
1135 break;
1137 default:
1138 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1139 return FALSE;
1142 return TRUE;
1145 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
1147 const struct wined3d_resource *resource = &surface->resource;
1148 struct wined3d_device *device = resource->device;
1149 const struct blit_shader *blitter;
1151 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
1152 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
1153 if (!blitter)
1155 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1156 return WINED3DERR_INVALIDCALL;
1159 return blitter->depth_fill(device, surface, rect, depth);
1162 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
1163 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect)
1165 struct wined3d_device *device = src_surface->resource.device;
1167 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
1168 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1169 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1170 return WINED3DERR_INVALIDCALL;
1172 surface_depth_blt_fbo(device, src_surface, src_location, src_rect, dst_surface, dst_location, dst_rect);
1174 surface_modify_ds_location(dst_surface, dst_location,
1175 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
1177 return WINED3D_OK;
1180 HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *surface,
1181 struct wined3d_surface *render_target)
1183 TRACE("surface %p, render_target %p.\n", surface, render_target);
1185 /* TODO: Check surface sizes, pools, etc. */
1187 if (render_target->resource.multisample_type)
1188 return WINED3DERR_INVALIDCALL;
1190 return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT);
1193 /* Context activation is done by the caller. */
1194 static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
1196 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
1197 checkGLcall("glDeleteBuffersARB(1, &surface->pbo)");
1199 surface->pbo = 0;
1200 surface_invalidate_location(surface, WINED3D_LOCATION_BUFFER);
1203 static void surface_unload(struct wined3d_resource *resource)
1205 struct wined3d_surface *surface = surface_from_resource(resource);
1206 struct wined3d_renderbuffer_entry *entry, *entry2;
1207 struct wined3d_device *device = resource->device;
1208 const struct wined3d_gl_info *gl_info;
1209 struct wined3d_context *context;
1211 TRACE("surface %p.\n", surface);
1213 if (resource->pool == WINED3D_POOL_DEFAULT)
1215 /* Default pool resources are supposed to be destroyed before Reset is called.
1216 * Implicit resources stay however. So this means we have an implicit render target
1217 * or depth stencil. The content may be destroyed, but we still have to tear down
1218 * opengl resources, so we cannot leave early.
1220 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1221 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1222 * or the depth stencil into an FBO the texture or render buffer will be removed
1223 * and all flags get lost */
1224 surface_prepare_system_memory(surface);
1225 memset(surface->resource.heap_memory, 0, surface->resource.size);
1226 surface_validate_location(surface, WINED3D_LOCATION_SYSMEM);
1227 surface_invalidate_location(surface, ~WINED3D_LOCATION_SYSMEM);
1229 /* We also get here when the ddraw swapchain is destroyed, for example
1230 * for a mode switch. In this case this surface won't necessarily be
1231 * an implicit surface. We have to mark it lost so that the
1232 * application can restore it after the mode switch. */
1233 surface->flags |= SFLAG_LOST;
1235 else
1237 surface_prepare_map_memory(surface);
1238 surface_load_location(surface, surface->map_binding);
1239 surface_invalidate_location(surface, ~surface->map_binding);
1241 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1243 context = context_acquire(device, NULL);
1244 gl_info = context->gl_info;
1246 /* Destroy PBOs, but load them into real sysmem before */
1247 if (surface->pbo)
1248 surface_remove_pbo(surface, gl_info);
1250 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1251 * all application-created targets the application has to release the surface
1252 * before calling _Reset
1254 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1256 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1257 list_remove(&entry->entry);
1258 HeapFree(GetProcessHeap(), 0, entry);
1260 list_init(&surface->renderbuffers);
1261 surface->current_renderbuffer = NULL;
1263 if (surface->rb_multisample)
1265 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
1266 surface->rb_multisample = 0;
1268 if (surface->rb_resolved)
1270 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
1271 surface->rb_resolved = 0;
1274 context_release(context);
1276 resource_unload(resource);
1279 static const struct wined3d_resource_ops surface_resource_ops =
1281 surface_unload,
1284 static const struct wined3d_surface_ops surface_ops =
1286 surface_private_setup,
1287 surface_unmap,
1290 /*****************************************************************************
1291 * Initializes the GDI surface, aka creates the DIB section we render to
1292 * The DIB section creation is done by calling GetDC, which will create the
1293 * section and releasing the dc to allow the app to use it. The dib section
1294 * will stay until the surface is released
1296 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1297 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1298 * avoid confusion in the shared surface code.
1300 * Returns:
1301 * WINED3D_OK on success
1302 * The return values of called methods on failure
1304 *****************************************************************************/
1305 static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface)
1307 HRESULT hr;
1309 TRACE("surface %p.\n", surface);
1311 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
1313 ERR("Overlays not yet supported by GDI surfaces.\n");
1314 return WINED3DERR_INVALIDCALL;
1317 /* Sysmem textures have memory already allocated - release it,
1318 * this avoids an unnecessary memcpy. */
1319 hr = surface_create_dib_section(surface);
1320 if (FAILED(hr))
1321 return hr;
1322 surface->map_binding = WINED3D_LOCATION_DIB;
1324 /* We don't mind the nonpow2 stuff in GDI. */
1325 surface->pow2Width = surface->resource.width;
1326 surface->pow2Height = surface->resource.height;
1328 return WINED3D_OK;
1331 static void gdi_surface_unmap(struct wined3d_surface *surface)
1333 TRACE("surface %p.\n", surface);
1335 /* Tell the swapchain to update the screen. */
1336 if (surface->swapchain && surface == surface->swapchain->front_buffer)
1337 x11_copy_to_screen(surface->swapchain, &surface->lockedRect);
1339 memset(&surface->lockedRect, 0, sizeof(RECT));
1342 static const struct wined3d_surface_ops gdi_surface_ops =
1344 gdi_surface_private_setup,
1345 gdi_surface_unmap,
1348 /* This call just downloads data, the caller is responsible for binding the
1349 * correct texture. */
1350 /* Context activation is done by the caller. */
1351 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1352 DWORD dst_location)
1354 const struct wined3d_format *format = surface->resource.format;
1355 struct wined3d_bo_address data;
1357 /* Only support read back of converted P8 surfaces. */
1358 if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
1360 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
1361 return;
1364 surface_get_memory(surface, &data, dst_location);
1366 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
1368 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1369 surface, surface->texture_level, format->glFormat, format->glType, data.addr);
1371 if (data.buffer_object)
1373 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, data.buffer_object));
1374 checkGLcall("glBindBufferARB");
1375 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
1376 checkGLcall("glGetCompressedTexImageARB");
1377 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1378 checkGLcall("glBindBufferARB");
1380 else
1382 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
1383 surface->texture_level, data.addr));
1384 checkGLcall("glGetCompressedTexImageARB");
1387 else
1389 void *mem;
1390 GLenum gl_format = format->glFormat;
1391 GLenum gl_type = format->glType;
1392 int src_pitch = 0;
1393 int dst_pitch = 0;
1395 if (surface->flags & SFLAG_NONPOW2)
1397 unsigned char alignment = surface->resource.device->surface_alignment;
1398 src_pitch = format->byte_count * surface->pow2Width;
1399 dst_pitch = wined3d_surface_get_pitch(surface);
1400 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
1401 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
1403 else
1405 mem = data.addr;
1408 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1409 surface, surface->texture_level, gl_format, gl_type, mem);
1411 if (data.buffer_object)
1413 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, data.buffer_object));
1414 checkGLcall("glBindBufferARB");
1416 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1417 gl_format, gl_type, NULL);
1418 checkGLcall("glGetTexImage");
1420 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1421 checkGLcall("glBindBufferARB");
1423 else
1425 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
1426 gl_format, gl_type, mem);
1427 checkGLcall("glGetTexImage");
1430 if (surface->flags & SFLAG_NONPOW2)
1432 const BYTE *src_data;
1433 BYTE *dst_data;
1434 UINT y;
1436 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1437 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1438 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1440 * We're doing this...
1442 * instead of boxing the texture :
1443 * |<-texture width ->| -->pow2width| /\
1444 * |111111111111111111| | |
1445 * |222 Texture 222222| boxed empty | texture height
1446 * |3333 Data 33333333| | |
1447 * |444444444444444444| | \/
1448 * ----------------------------------- |
1449 * | boxed empty | boxed empty | pow2height
1450 * | | | \/
1451 * -----------------------------------
1454 * we're repacking the data to the expected texture width
1456 * |<-texture width ->| -->pow2width| /\
1457 * |111111111111111111222222222222222| |
1458 * |222333333333333333333444444444444| texture height
1459 * |444444 | |
1460 * | | \/
1461 * | | |
1462 * | empty | pow2height
1463 * | | \/
1464 * -----------------------------------
1466 * == is the same as
1468 * |<-texture width ->| /\
1469 * |111111111111111111|
1470 * |222222222222222222|texture height
1471 * |333333333333333333|
1472 * |444444444444444444| \/
1473 * --------------------
1475 * This also means that any references to surface memory should work with the data as if it were a
1476 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1478 * internally the texture is still stored in a boxed format so any references to textureName will
1479 * get a boxed texture with width pow2width and not a texture of width resource.width.
1481 * Performance should not be an issue, because applications normally do not lock the surfaces when
1482 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
1483 * and doesn't have to be re-read. */
1484 src_data = mem;
1485 dst_data = data.addr;
1486 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
1487 for (y = 0; y < surface->resource.height; ++y)
1489 memcpy(dst_data, src_data, dst_pitch);
1490 src_data += src_pitch;
1491 dst_data += dst_pitch;
1494 HeapFree(GetProcessHeap(), 0, mem);
1499 /* This call just uploads data, the caller is responsible for binding the
1500 * correct texture. */
1501 /* Context activation is done by the caller. */
1502 static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1503 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
1504 BOOL srgb, const struct wined3d_bo_address *data)
1506 UINT update_w = src_rect->right - src_rect->left;
1507 UINT update_h = src_rect->bottom - src_rect->top;
1509 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1510 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
1511 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
1513 if (surface->resource.map_count)
1515 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
1516 surface->flags |= SFLAG_PIN_SYSMEM;
1519 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
1521 update_h *= format->height_scale.numerator;
1522 update_h /= format->height_scale.denominator;
1525 if (data->buffer_object)
1527 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
1528 checkGLcall("glBindBufferARB");
1531 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
1533 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1, 1);
1534 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
1535 const BYTE *addr = data->addr;
1536 GLenum internal;
1538 addr += (src_rect->top / format->block_height) * src_pitch;
1539 addr += (src_rect->left / format->block_width) * format->block_byte_count;
1541 if (srgb)
1542 internal = format->glGammaInternal;
1543 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
1544 internal = format->rtInternal;
1545 else
1546 internal = format->glInternal;
1548 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
1549 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
1550 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
1552 if (row_length == src_pitch)
1554 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
1555 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
1557 else
1559 UINT row, y;
1561 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
1562 * can't use the unpack row length like below. */
1563 for (row = 0, y = dst_point->y; row < row_count; ++row)
1565 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
1566 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
1567 y += format->block_height;
1568 addr += src_pitch;
1571 checkGLcall("glCompressedTexSubImage2DARB");
1573 else
1575 const BYTE *addr = data->addr;
1577 addr += src_rect->top * src_pitch;
1578 addr += src_rect->left * format->byte_count;
1580 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1581 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
1582 update_w, update_h, format->glFormat, format->glType, addr);
1584 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
1585 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
1586 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
1587 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1588 checkGLcall("glTexSubImage2D");
1591 if (data->buffer_object)
1593 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1594 checkGLcall("glBindBufferARB");
1597 if (wined3d_settings.strict_draw_ordering)
1598 gl_info->gl_ops.gl.p_glFlush();
1600 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1602 struct wined3d_device *device = surface->resource.device;
1603 unsigned int i;
1605 for (i = 0; i < device->context_count; ++i)
1607 context_surface_update(device->contexts[i], surface);
1612 static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
1613 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
1615 BOOL colorkey_active = need_alpha_ck && (surface->container->color_key_flags & WINEDDSD_CKSRCBLT);
1616 const struct wined3d_device *device = surface->resource.device;
1617 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1618 BOOL blit_supported = FALSE;
1620 /* Copy the default values from the surface. Below we might perform fixups */
1621 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
1622 *format = *surface->resource.format;
1623 *conversion_type = WINED3D_CT_NONE;
1625 /* Ok, now look if we have to do any conversion */
1626 switch (surface->resource.format->id)
1628 case WINED3DFMT_P8_UINT:
1629 /* Below the call to blit_supported is disabled for Wine 1.2
1630 * because the function isn't operating correctly yet. At the
1631 * moment 8-bit blits are handled in software and if certain GL
1632 * extensions are around, surface conversion is performed at
1633 * upload time. The blit_supported call recognizes it as a
1634 * destination fixup. This type of upload 'fixup' and 8-bit to
1635 * 8-bit blits need to be handled by the blit_shader.
1636 * TODO: get rid of this #if 0. */
1637 #if 0
1638 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1639 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
1640 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
1641 #endif
1642 blit_supported = gl_info->supported[ARB_FRAGMENT_PROGRAM];
1644 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
1645 * texturing. Further also use conversion in case of color keying.
1646 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
1647 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
1648 * conflicts with this.
1650 if (!((blit_supported && surface->swapchain && surface == surface->swapchain->front_buffer))
1651 || colorkey_active || !use_texturing)
1653 format->glFormat = GL_RGBA;
1654 format->glInternal = GL_RGBA;
1655 format->glType = GL_UNSIGNED_BYTE;
1656 format->conv_byte_count = 4;
1657 *conversion_type = WINED3D_CT_PALETTED;
1659 break;
1661 case WINED3DFMT_B2G3R3_UNORM:
1662 /* **********************
1663 GL_UNSIGNED_BYTE_3_3_2
1664 ********************** */
1665 if (colorkey_active) {
1666 /* This texture format will never be used.. So do not care about color keying
1667 up until the point in time it will be needed :-) */
1668 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1670 break;
1672 case WINED3DFMT_B5G6R5_UNORM:
1673 if (colorkey_active)
1675 *conversion_type = WINED3D_CT_CK_565;
1676 format->glFormat = GL_RGBA;
1677 format->glInternal = GL_RGB5_A1;
1678 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
1679 format->conv_byte_count = 2;
1681 break;
1683 case WINED3DFMT_B5G5R5X1_UNORM:
1684 if (colorkey_active)
1686 *conversion_type = WINED3D_CT_CK_5551;
1687 format->glFormat = GL_BGRA;
1688 format->glInternal = GL_RGB5_A1;
1689 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
1690 format->conv_byte_count = 2;
1692 break;
1694 case WINED3DFMT_B8G8R8_UNORM:
1695 if (colorkey_active)
1697 *conversion_type = WINED3D_CT_CK_RGB24;
1698 format->glFormat = GL_RGBA;
1699 format->glInternal = GL_RGBA8;
1700 format->glType = GL_UNSIGNED_INT_8_8_8_8;
1701 format->conv_byte_count = 4;
1703 break;
1705 case WINED3DFMT_B8G8R8X8_UNORM:
1706 if (colorkey_active)
1708 *conversion_type = WINED3D_CT_RGB32_888;
1709 format->glFormat = GL_RGBA;
1710 format->glInternal = GL_RGBA8;
1711 format->glType = GL_UNSIGNED_INT_8_8_8_8;
1712 format->conv_byte_count = 4;
1714 break;
1716 case WINED3DFMT_B8G8R8A8_UNORM:
1717 if (colorkey_active)
1719 *conversion_type = WINED3D_CT_CK_ARGB32;
1720 format->conv_byte_count = 4;
1722 break;
1724 default:
1725 break;
1728 if (*conversion_type != WINED3D_CT_NONE)
1730 format->rtInternal = format->glInternal;
1731 format->glGammaInternal = format->glInternal;
1734 return WINED3D_OK;
1737 static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
1739 UINT width_mask, height_mask;
1741 if (!rect->left && !rect->top
1742 && rect->right == surface->resource.width
1743 && rect->bottom == surface->resource.height)
1744 return TRUE;
1746 /* This assumes power of two block sizes, but NPOT block sizes would be
1747 * silly anyway. */
1748 width_mask = surface->resource.format->block_width - 1;
1749 height_mask = surface->resource.format->block_height - 1;
1751 if (!(rect->left & width_mask) && !(rect->top & height_mask)
1752 && !(rect->right & width_mask) && !(rect->bottom & height_mask))
1753 return TRUE;
1755 return FALSE;
1758 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
1759 struct wined3d_surface *src_surface, const RECT *src_rect)
1761 const struct wined3d_format *src_format;
1762 const struct wined3d_format *dst_format;
1763 const struct wined3d_gl_info *gl_info;
1764 enum wined3d_conversion_type convert;
1765 struct wined3d_context *context;
1766 struct wined3d_bo_address data;
1767 struct wined3d_format format;
1768 UINT update_w, update_h;
1769 UINT dst_w, dst_h;
1770 RECT r, dst_rect;
1771 UINT src_pitch;
1772 POINT p;
1774 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1775 dst_surface, wine_dbgstr_point(dst_point),
1776 src_surface, wine_dbgstr_rect(src_rect));
1778 src_format = src_surface->resource.format;
1779 dst_format = dst_surface->resource.format;
1781 if (src_format->id != dst_format->id)
1783 WARN("Source and destination surfaces should have the same format.\n");
1784 return WINED3DERR_INVALIDCALL;
1787 if (!dst_point)
1789 p.x = 0;
1790 p.y = 0;
1791 dst_point = &p;
1793 else if (dst_point->x < 0 || dst_point->y < 0)
1795 WARN("Invalid destination point.\n");
1796 return WINED3DERR_INVALIDCALL;
1799 if (!src_rect)
1801 r.left = 0;
1802 r.top = 0;
1803 r.right = src_surface->resource.width;
1804 r.bottom = src_surface->resource.height;
1805 src_rect = &r;
1807 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
1808 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
1810 WARN("Invalid source rectangle.\n");
1811 return WINED3DERR_INVALIDCALL;
1814 dst_w = dst_surface->resource.width;
1815 dst_h = dst_surface->resource.height;
1817 update_w = src_rect->right - src_rect->left;
1818 update_h = src_rect->bottom - src_rect->top;
1820 if (update_w > dst_w || dst_point->x > dst_w - update_w
1821 || update_h > dst_h || dst_point->y > dst_h - update_h)
1823 WARN("Destination out of bounds.\n");
1824 return WINED3DERR_INVALIDCALL;
1827 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
1829 WARN("Source rectangle not block-aligned.\n");
1830 return WINED3DERR_INVALIDCALL;
1833 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
1834 if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
1836 WARN("Destination rectangle not block-aligned.\n");
1837 return WINED3DERR_INVALIDCALL;
1840 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1841 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
1842 if (convert != WINED3D_CT_NONE || format.convert)
1843 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
1845 context = context_acquire(dst_surface->resource.device, NULL);
1846 gl_info = context->gl_info;
1848 /* Only load the surface for partial updates. For newly allocated texture
1849 * the texture wouldn't be the current location, and we'd upload zeroes
1850 * just to overwrite them again. */
1851 if (update_w == dst_w && update_h == dst_h)
1852 surface_prepare_texture(dst_surface, context, FALSE);
1853 else
1854 surface_load_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
1855 wined3d_texture_bind(dst_surface->container, context, FALSE);
1857 surface_get_memory(src_surface, &data, src_surface->locations);
1858 src_pitch = wined3d_surface_get_pitch(src_surface);
1860 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
1862 context_invalidate_active_texture(context);
1864 context_release(context);
1866 surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
1867 surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
1869 return WINED3D_OK;
1872 /* This call just allocates the texture, the caller is responsible for binding
1873 * the correct texture. */
1874 /* Context activation is done by the caller. */
1875 static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
1876 const struct wined3d_format *format, BOOL srgb)
1878 BOOL disable_client_storage = FALSE;
1879 GLsizei width = surface->pow2Width;
1880 GLsizei height = surface->pow2Height;
1881 const BYTE *mem = NULL;
1882 GLenum internal;
1884 if (srgb)
1886 internal = format->glGammaInternal;
1888 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
1890 internal = format->rtInternal;
1892 else
1894 internal = format->glInternal;
1897 if (!internal)
1898 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
1900 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
1902 height *= format->height_scale.numerator;
1903 height /= format->height_scale.denominator;
1906 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
1907 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
1908 internal, width, height, format->glFormat, format->glType);
1910 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1912 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
1913 || !surface->resource.heap_memory)
1915 /* In some cases we want to disable client storage.
1916 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
1917 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
1918 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
1919 * heap_memory == NULL: Not defined in the extension. Seems to disable client storage effectively
1921 surface->flags &= ~SFLAG_CLIENT;
1923 else
1925 surface->flags |= SFLAG_CLIENT;
1926 mem = surface->resource.heap_memory;
1928 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1929 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1930 disable_client_storage = TRUE;
1934 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
1936 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
1937 internal, width, height, 0, surface->resource.size, mem));
1938 checkGLcall("glCompressedTexImage2DARB");
1940 else
1942 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
1943 internal, width, height, 0, format->glFormat, format->glType, mem);
1944 checkGLcall("glTexImage2D");
1947 if (disable_client_storage)
1949 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1950 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1954 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1955 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1956 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1957 /* Context activation is done by the caller. */
1958 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
1960 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
1961 struct wined3d_renderbuffer_entry *entry;
1962 GLuint renderbuffer = 0;
1963 unsigned int src_width, src_height;
1964 unsigned int width, height;
1966 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
1968 width = rt->pow2Width;
1969 height = rt->pow2Height;
1971 else
1973 width = surface->pow2Width;
1974 height = surface->pow2Height;
1977 src_width = surface->pow2Width;
1978 src_height = surface->pow2Height;
1980 /* A depth stencil smaller than the render target is not valid */
1981 if (width > src_width || height > src_height) return;
1983 /* Remove any renderbuffer set if the sizes match */
1984 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1985 || (width == src_width && height == src_height))
1987 surface->current_renderbuffer = NULL;
1988 return;
1991 /* Look if we've already got a renderbuffer of the correct dimensions */
1992 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1994 if (entry->width == width && entry->height == height)
1996 renderbuffer = entry->id;
1997 surface->current_renderbuffer = entry;
1998 break;
2002 if (!renderbuffer)
2004 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
2005 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
2006 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
2007 surface->resource.format->glInternal, width, height);
2009 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
2010 entry->width = width;
2011 entry->height = height;
2012 entry->id = renderbuffer;
2013 list_add_head(&surface->renderbuffers, &entry->entry);
2015 surface->current_renderbuffer = entry;
2018 checkGLcall("set_compatible_renderbuffer");
2021 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
2023 const struct wined3d_swapchain *swapchain = surface->swapchain;
2025 TRACE("surface %p.\n", surface);
2027 if (!swapchain)
2029 ERR("Surface %p is not on a swapchain.\n", surface);
2030 return GL_NONE;
2033 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
2035 if (swapchain->render_to_fbo)
2037 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2038 return GL_COLOR_ATTACHMENT0;
2040 TRACE("Returning GL_BACK\n");
2041 return GL_BACK;
2043 else if (surface == swapchain->front_buffer)
2045 TRACE("Returning GL_FRONT\n");
2046 return GL_FRONT;
2049 FIXME("Higher back buffer, returning GL_BACK\n");
2050 return GL_BACK;
2053 void surface_load(struct wined3d_surface *surface, BOOL srgb)
2055 DWORD location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
2056 BOOL ck_changed;
2058 TRACE("surface %p, srgb %#x.\n", surface, srgb);
2060 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
2061 ERR("Not supported on scratch surfaces.\n");
2063 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->container->color_key_flags & WINEDDSD_CKSRCBLT);
2065 /* Reload if either the texture and sysmem have different ideas about the
2066 * color key, or the actual key values changed. */
2067 if (ck_changed || ((surface->container->color_key_flags & WINEDDSD_CKSRCBLT)
2068 && (surface->gl_color_key.color_space_low_value
2069 != surface->container->src_blt_color_key.color_space_low_value
2070 || surface->gl_color_key.color_space_high_value
2071 != surface->container->src_blt_color_key.color_space_high_value)))
2073 TRACE("Reloading because of color keying\n");
2074 /* To perform the color key conversion we need a sysmem copy of
2075 * the surface. Make sure we have it. */
2077 surface_prepare_map_memory(surface);
2078 surface_load_location(surface, surface->map_binding);
2079 surface_invalidate_location(surface, ~surface->map_binding);
2080 /* Switching color keying on / off may change the internal format. */
2081 if (ck_changed)
2082 surface_force_reload(surface);
2084 else if (!(surface->locations & location))
2086 TRACE("Reloading because surface is dirty.\n");
2088 else
2090 TRACE("surface is already in texture\n");
2091 return;
2094 surface_load_location(surface, location);
2095 surface_evict_sysmem(surface);
2098 /* See also float_16_to_32() in wined3d_private.h */
2099 static inline unsigned short float_32_to_16(const float *in)
2101 int exp = 0;
2102 float tmp = fabsf(*in);
2103 unsigned int mantissa;
2104 unsigned short ret;
2106 /* Deal with special numbers */
2107 if (*in == 0.0f)
2108 return 0x0000;
2109 if (isnan(*in))
2110 return 0x7c01;
2111 if (isinf(*in))
2112 return (*in < 0.0f ? 0xfc00 : 0x7c00);
2114 if (tmp < powf(2, 10))
2118 tmp = tmp * 2.0f;
2119 exp--;
2120 } while (tmp < powf(2, 10));
2122 else if (tmp >= powf(2, 11))
2126 tmp /= 2.0f;
2127 exp++;
2128 } while (tmp >= powf(2, 11));
2131 mantissa = (unsigned int)tmp;
2132 if (tmp - mantissa >= 0.5f)
2133 ++mantissa; /* Round to nearest, away from zero. */
2135 exp += 10; /* Normalize the mantissa. */
2136 exp += 15; /* Exponent is encoded with excess 15. */
2138 if (exp > 30) /* too big */
2140 ret = 0x7c00; /* INF */
2142 else if (exp <= 0)
2144 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2145 while (exp <= 0)
2147 mantissa = mantissa >> 1;
2148 ++exp;
2150 ret = mantissa & 0x3ff;
2152 else
2154 ret = (exp << 10) | (mantissa & 0x3ff);
2157 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
2158 return ret;
2161 ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
2163 ULONG refcount;
2165 TRACE("surface %p, swapchain %p, container %p.\n",
2166 surface, surface->swapchain, surface->container);
2168 if (surface->swapchain)
2169 return wined3d_swapchain_incref(surface->swapchain);
2171 if (surface->container)
2172 return wined3d_texture_incref(surface->container);
2174 refcount = InterlockedIncrement(&surface->resource.ref);
2175 TRACE("%p increasing refcount to %u.\n", surface, refcount);
2177 return refcount;
2180 ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
2182 ULONG refcount;
2184 TRACE("surface %p, swapchain %p, container %p.\n",
2185 surface, surface->swapchain, surface->container);
2187 if (surface->swapchain)
2188 return wined3d_swapchain_decref(surface->swapchain);
2190 if (surface->container)
2191 return wined3d_texture_decref(surface->container);
2193 refcount = InterlockedDecrement(&surface->resource.ref);
2194 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
2196 if (!refcount)
2198 surface_cleanup(surface);
2199 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
2201 TRACE("Destroyed surface %p.\n", surface);
2202 HeapFree(GetProcessHeap(), 0, surface);
2205 return refcount;
2208 void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
2210 TRACE("surface %p.\n", surface);
2212 if (!surface->resource.device->d3d_initialized)
2214 ERR("D3D not initialized.\n");
2215 return;
2218 wined3d_texture_preload(surface->container);
2221 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
2223 TRACE("surface %p.\n", surface);
2225 return surface->resource.parent;
2228 struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
2230 TRACE("surface %p.\n", surface);
2232 return &surface->resource;
2235 HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
2237 TRACE("surface %p, flags %#x.\n", surface, flags);
2239 switch (flags)
2241 case WINEDDGBS_CANBLT:
2242 case WINEDDGBS_ISBLTDONE:
2243 return WINED3D_OK;
2245 default:
2246 return WINED3DERR_INVALIDCALL;
2250 HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
2252 TRACE("surface %p, flags %#x.\n", surface, flags);
2254 /* XXX: DDERR_INVALIDSURFACETYPE */
2256 switch (flags)
2258 case WINEDDGFS_CANFLIP:
2259 case WINEDDGFS_ISFLIPDONE:
2260 return WINED3D_OK;
2262 default:
2263 return WINED3DERR_INVALIDCALL;
2267 HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
2269 TRACE("surface %p.\n", surface);
2271 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2272 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
2275 HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
2277 TRACE("surface %p.\n", surface);
2279 surface->flags &= ~SFLAG_LOST;
2280 return WINED3D_OK;
2283 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
2285 unsigned int alignment;
2286 DWORD pitch;
2288 TRACE("surface %p.\n", surface);
2290 if (surface->pitch)
2291 return surface->pitch;
2293 alignment = surface->resource.device->surface_alignment;
2294 pitch = wined3d_format_calculate_pitch(surface->resource.format, surface->resource.width);
2295 pitch = (pitch + alignment - 1) & ~(alignment - 1);
2297 TRACE("Returning %u.\n", pitch);
2299 return pitch;
2302 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
2304 LONG w, h;
2306 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
2308 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2310 WARN("Not an overlay surface.\n");
2311 return WINEDDERR_NOTAOVERLAYSURFACE;
2314 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
2315 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
2316 surface->overlay_destrect.left = x;
2317 surface->overlay_destrect.top = y;
2318 surface->overlay_destrect.right = x + w;
2319 surface->overlay_destrect.bottom = y + h;
2321 return WINED3D_OK;
2324 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
2326 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
2328 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2330 TRACE("Not an overlay surface.\n");
2331 return WINEDDERR_NOTAOVERLAYSURFACE;
2334 if (!surface->overlay_dest)
2336 TRACE("Overlay not visible.\n");
2337 *x = 0;
2338 *y = 0;
2339 return WINEDDERR_OVERLAYNOTVISIBLE;
2342 *x = surface->overlay_destrect.left;
2343 *y = surface->overlay_destrect.top;
2345 TRACE("Returning position %d, %d.\n", *x, *y);
2347 return WINED3D_OK;
2350 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
2351 DWORD flags, struct wined3d_surface *ref)
2353 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
2355 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2357 TRACE("Not an overlay surface.\n");
2358 return WINEDDERR_NOTAOVERLAYSURFACE;
2361 return WINED3D_OK;
2364 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
2365 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
2367 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2368 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
2370 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2372 WARN("Not an overlay surface.\n");
2373 return WINEDDERR_NOTAOVERLAYSURFACE;
2375 else if (!dst_surface)
2377 WARN("Dest surface is NULL.\n");
2378 return WINED3DERR_INVALIDCALL;
2381 if (src_rect)
2383 surface->overlay_srcrect = *src_rect;
2385 else
2387 surface->overlay_srcrect.left = 0;
2388 surface->overlay_srcrect.top = 0;
2389 surface->overlay_srcrect.right = surface->resource.width;
2390 surface->overlay_srcrect.bottom = surface->resource.height;
2393 if (dst_rect)
2395 surface->overlay_destrect = *dst_rect;
2397 else
2399 surface->overlay_destrect.left = 0;
2400 surface->overlay_destrect.top = 0;
2401 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
2402 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
2405 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
2407 surface->overlay_dest = NULL;
2408 list_remove(&surface->overlay_entry);
2411 if (flags & WINEDDOVER_SHOW)
2413 if (surface->overlay_dest != dst_surface)
2415 surface->overlay_dest = dst_surface;
2416 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
2419 else if (flags & WINEDDOVER_HIDE)
2421 /* tests show that the rectangles are erased on hide */
2422 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
2423 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
2424 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
2425 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
2426 surface->overlay_dest = NULL;
2429 return WINED3D_OK;
2432 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
2433 UINT width, UINT height, enum wined3d_format_id format_id,
2434 enum wined3d_multisample_type multisample_type, UINT multisample_quality,
2435 void *mem, UINT pitch)
2437 struct wined3d_device *device = surface->resource.device;
2438 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2439 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
2440 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height, 1);
2441 BOOL create_dib = FALSE;
2442 HRESULT hr;
2443 DWORD valid_location = 0;
2445 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, "
2446 "mem %p, pitch %u.\n",
2447 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type, mem, pitch);
2449 if (!resource_size)
2450 return WINED3DERR_INVALIDCALL;
2452 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
2454 WARN("Surface is mapped or the DC is in use.\n");
2455 return WINED3DERR_INVALIDCALL;
2458 if (device->d3d_initialized)
2459 surface->resource.resource_ops->resource_unload(&surface->resource);
2461 if (surface->flags & SFLAG_DIBSECTION)
2463 DeleteDC(surface->hDC);
2464 DeleteObject(surface->dib.DIBsection);
2465 surface->dib.bitmap_data = NULL;
2466 surface->flags &= ~SFLAG_DIBSECTION;
2467 create_dib = TRUE;
2470 surface->locations = 0;
2471 wined3d_resource_free_sysmem(&surface->resource);
2473 surface->resource.width = width;
2474 surface->resource.height = height;
2475 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
2476 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
2478 surface->pow2Width = width;
2479 surface->pow2Height = height;
2481 else
2483 surface->pow2Width = surface->pow2Height = 1;
2484 while (surface->pow2Width < width)
2485 surface->pow2Width <<= 1;
2486 while (surface->pow2Height < height)
2487 surface->pow2Height <<= 1;
2490 if (surface->pow2Width != width || surface->pow2Height != height)
2491 surface->flags |= SFLAG_NONPOW2;
2492 else
2493 surface->flags &= ~SFLAG_NONPOW2;
2495 surface->user_memory = mem;
2496 if (surface->user_memory)
2498 surface->map_binding = WINED3D_LOCATION_USER_MEMORY;
2499 valid_location = WINED3D_LOCATION_USER_MEMORY;
2501 surface->pitch = pitch;
2502 surface->resource.format = format;
2503 surface->resource.multisample_type = multisample_type;
2504 surface->resource.multisample_quality = multisample_quality;
2505 if (surface->pitch)
2506 surface->resource.size = height * surface->pitch;
2507 else
2508 surface->resource.size = resource_size;
2510 /* The format might be changed to a format that needs conversion.
2511 * If the surface didn't use PBOs previously but could now, don't
2512 * change it - whatever made us not use PBOs might come back, e.g.
2513 * color keys. */
2514 if (surface->map_binding == WINED3D_LOCATION_BUFFER && !surface_use_pbo(surface))
2515 surface->map_binding = create_dib ? WINED3D_LOCATION_DIB : WINED3D_LOCATION_SYSMEM;
2517 if (create_dib)
2519 if (FAILED(hr = surface_create_dib_section(surface)))
2521 ERR("Failed to create dib section, hr %#x.\n", hr);
2522 return hr;
2524 if (!valid_location)
2525 valid_location = WINED3D_LOCATION_DIB;
2528 if (!valid_location)
2530 surface_prepare_system_memory(surface);
2531 valid_location = WINED3D_LOCATION_SYSMEM;
2534 surface_validate_location(surface, valid_location);
2536 return WINED3D_OK;
2539 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
2540 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2542 unsigned short *dst_s;
2543 const float *src_f;
2544 unsigned int x, y;
2546 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2548 for (y = 0; y < h; ++y)
2550 src_f = (const float *)(src + y * pitch_in);
2551 dst_s = (unsigned short *) (dst + y * pitch_out);
2552 for (x = 0; x < w; ++x)
2554 dst_s[x] = float_32_to_16(src_f + x);
2559 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
2560 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2562 static const unsigned char convert_5to8[] =
2564 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2565 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2566 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2567 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2569 static const unsigned char convert_6to8[] =
2571 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2572 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2573 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2574 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2575 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2576 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2577 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2578 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2580 unsigned int x, y;
2582 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2584 for (y = 0; y < h; ++y)
2586 const WORD *src_line = (const WORD *)(src + y * pitch_in);
2587 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2588 for (x = 0; x < w; ++x)
2590 WORD pixel = src_line[x];
2591 dst_line[x] = 0xff000000
2592 | convert_5to8[(pixel & 0xf800) >> 11] << 16
2593 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
2594 | convert_5to8[(pixel & 0x001f)];
2599 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2600 * in both cases we're just setting the X / Alpha channel to 0xff. */
2601 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
2602 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2604 unsigned int x, y;
2606 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2608 for (y = 0; y < h; ++y)
2610 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
2611 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2613 for (x = 0; x < w; ++x)
2615 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
2620 static inline BYTE cliptobyte(int x)
2622 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
2625 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
2626 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2628 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
2629 unsigned int x, y;
2631 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2633 for (y = 0; y < h; ++y)
2635 const BYTE *src_line = src + y * pitch_in;
2636 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2637 for (x = 0; x < w; ++x)
2639 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2640 * C = Y - 16; D = U - 128; E = V - 128;
2641 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2642 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2643 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2644 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2645 * U and V are shared between the pixels. */
2646 if (!(x & 1)) /* For every even pixel, read new U and V. */
2648 d = (int) src_line[1] - 128;
2649 e = (int) src_line[3] - 128;
2650 r2 = 409 * e + 128;
2651 g2 = - 100 * d - 208 * e + 128;
2652 b2 = 516 * d + 128;
2654 c2 = 298 * ((int) src_line[0] - 16);
2655 dst_line[x] = 0xff000000
2656 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
2657 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
2658 | cliptobyte((c2 + b2) >> 8); /* blue */
2659 /* Scale RGB values to 0..255 range,
2660 * then clip them if still not in range (may be negative),
2661 * then shift them within DWORD if necessary. */
2662 src_line += 2;
2667 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
2668 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2670 unsigned int x, y;
2671 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
2673 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
2675 for (y = 0; y < h; ++y)
2677 const BYTE *src_line = src + y * pitch_in;
2678 WORD *dst_line = (WORD *)(dst + y * pitch_out);
2679 for (x = 0; x < w; ++x)
2681 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2682 * C = Y - 16; D = U - 128; E = V - 128;
2683 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2684 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2685 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2686 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2687 * U and V are shared between the pixels. */
2688 if (!(x & 1)) /* For every even pixel, read new U and V. */
2690 d = (int) src_line[1] - 128;
2691 e = (int) src_line[3] - 128;
2692 r2 = 409 * e + 128;
2693 g2 = - 100 * d - 208 * e + 128;
2694 b2 = 516 * d + 128;
2696 c2 = 298 * ((int) src_line[0] - 16);
2697 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
2698 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
2699 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
2700 /* Scale RGB values to 0..255 range,
2701 * then clip them if still not in range (may be negative),
2702 * then shift them within DWORD if necessary. */
2703 src_line += 2;
2708 struct d3dfmt_converter_desc
2710 enum wined3d_format_id from, to;
2711 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
2714 static const struct d3dfmt_converter_desc converters[] =
2716 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
2717 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
2718 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
2719 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
2720 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
2721 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
2724 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
2725 enum wined3d_format_id to)
2727 unsigned int i;
2729 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
2731 if (converters[i].from == from && converters[i].to == to)
2732 return &converters[i];
2735 return NULL;
2738 static struct wined3d_texture *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
2740 struct wined3d_map_desc src_map, dst_map;
2741 const struct d3dfmt_converter_desc *conv;
2742 struct wined3d_texture *ret = NULL;
2743 struct wined3d_resource_desc desc;
2744 struct wined3d_surface *dst;
2746 conv = find_converter(source->resource.format->id, to_fmt);
2747 if (!conv)
2749 FIXME("Cannot find a conversion function from format %s to %s.\n",
2750 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
2751 return NULL;
2754 /* FIXME: Multisampled conversion? */
2755 wined3d_resource_get_desc(&source->resource, &desc);
2756 desc.resource_type = WINED3D_RTYPE_TEXTURE;
2757 desc.format = to_fmt;
2758 desc.usage = 0;
2759 desc.pool = WINED3D_POOL_SCRATCH;
2760 if (FAILED(wined3d_texture_create(source->resource.device, &desc, 1,
2761 WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, NULL, &wined3d_null_parent_ops, &ret)))
2763 ERR("Failed to create a destination surface for conversion.\n");
2764 return NULL;
2766 dst = surface_from_resource(wined3d_texture_get_sub_resource(ret, 0));
2768 memset(&src_map, 0, sizeof(src_map));
2769 memset(&dst_map, 0, sizeof(dst_map));
2771 if (FAILED(wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
2773 ERR("Failed to lock the source surface.\n");
2774 wined3d_texture_decref(ret);
2775 return NULL;
2777 if (FAILED(wined3d_surface_map(dst, &dst_map, NULL, 0)))
2779 ERR("Failed to lock the destination surface.\n");
2780 wined3d_surface_unmap(source);
2781 wined3d_texture_decref(ret);
2782 return NULL;
2785 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
2786 source->resource.width, source->resource.height);
2788 wined3d_surface_unmap(dst);
2789 wined3d_surface_unmap(source);
2791 return ret;
2794 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
2795 unsigned int bpp, UINT pitch, DWORD color)
2797 BYTE *first;
2798 unsigned int x, y;
2800 /* Do first row */
2802 #define COLORFILL_ROW(type) \
2803 do { \
2804 type *d = (type *)buf; \
2805 for (x = 0; x < width; ++x) \
2806 d[x] = (type)color; \
2807 } while(0)
2809 switch (bpp)
2811 case 1:
2812 COLORFILL_ROW(BYTE);
2813 break;
2815 case 2:
2816 COLORFILL_ROW(WORD);
2817 break;
2819 case 3:
2821 BYTE *d = buf;
2822 for (x = 0; x < width; ++x, d += 3)
2824 d[0] = (color ) & 0xff;
2825 d[1] = (color >> 8) & 0xff;
2826 d[2] = (color >> 16) & 0xff;
2828 break;
2830 case 4:
2831 COLORFILL_ROW(DWORD);
2832 break;
2834 default:
2835 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
2836 return WINED3DERR_NOTAVAILABLE;
2839 #undef COLORFILL_ROW
2841 /* Now copy first row. */
2842 first = buf;
2843 for (y = 1; y < height; ++y)
2845 buf += pitch;
2846 memcpy(buf, first, width * bpp);
2849 return WINED3D_OK;
2852 struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
2854 return surface_from_resource(resource);
2857 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
2859 TRACE("surface %p.\n", surface);
2861 if (!surface->resource.map_count)
2863 WARN("Trying to unmap unmapped surface.\n");
2864 return WINEDDERR_NOTLOCKED;
2866 --surface->resource.map_count;
2868 surface->surface_ops->surface_unmap(surface);
2870 return WINED3D_OK;
2873 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
2874 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
2876 const struct wined3d_format *format = surface->resource.format;
2877 struct wined3d_device *device = surface->resource.device;
2878 struct wined3d_context *context;
2879 const struct wined3d_gl_info *gl_info;
2880 BYTE *base_memory;
2882 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
2883 surface, map_desc, wine_dbgstr_rect(rect), flags);
2885 if (surface->resource.map_count)
2887 WARN("Surface is already mapped.\n");
2888 return WINED3DERR_INVALIDCALL;
2891 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
2892 && !surface_check_block_align(surface, rect))
2894 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
2895 wine_dbgstr_rect(rect), format->block_width, format->block_height);
2897 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
2898 return WINED3DERR_INVALIDCALL;
2901 ++surface->resource.map_count;
2903 if (!(surface->resource.access_flags & WINED3D_RESOURCE_ACCESS_CPU))
2904 WARN("Trying to lock unlockable surface.\n");
2906 /* Performance optimization: Count how often a surface is mapped, if it is
2907 * mapped regularly do not throw away the system memory copy. This avoids
2908 * the need to download the surface from OpenGL all the time. The surface
2909 * is still downloaded if the OpenGL texture is changed. */
2910 if (!(surface->flags & SFLAG_DYNLOCK) && surface->map_binding == WINED3D_LOCATION_SYSMEM)
2912 if (++surface->lockCount > MAXLOCKCOUNT)
2914 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
2915 surface->flags |= SFLAG_DYNLOCK;
2919 surface_prepare_map_memory(surface);
2920 if (flags & WINED3D_MAP_DISCARD)
2922 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2923 wined3d_debug_location(surface->map_binding));
2924 surface_validate_location(surface, surface->map_binding);
2926 else
2928 if (surface->resource.usage & WINED3DUSAGE_DYNAMIC)
2929 WARN_(d3d_perf)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
2931 surface_load_location(surface, surface->map_binding);
2934 if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
2935 surface_invalidate_location(surface, ~surface->map_binding);
2937 switch (surface->map_binding)
2939 case WINED3D_LOCATION_SYSMEM:
2940 base_memory = surface->resource.heap_memory;
2941 break;
2943 case WINED3D_LOCATION_USER_MEMORY:
2944 base_memory = surface->user_memory;
2945 break;
2947 case WINED3D_LOCATION_DIB:
2948 base_memory = surface->dib.bitmap_data;
2949 break;
2951 case WINED3D_LOCATION_BUFFER:
2952 context = context_acquire(device, NULL);
2953 gl_info = context->gl_info;
2955 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
2956 base_memory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
2957 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2958 checkGLcall("map PBO");
2960 context_release(context);
2961 break;
2963 default:
2964 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->map_binding));
2965 base_memory = NULL;
2968 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
2969 map_desc->row_pitch = surface->resource.width * format->byte_count;
2970 else
2971 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
2972 map_desc->slice_pitch = 0;
2974 if (!rect)
2976 map_desc->data = base_memory;
2977 surface->lockedRect.left = 0;
2978 surface->lockedRect.top = 0;
2979 surface->lockedRect.right = surface->resource.width;
2980 surface->lockedRect.bottom = surface->resource.height;
2982 else
2984 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
2986 /* Compressed textures are block based, so calculate the offset of
2987 * the block that contains the top-left pixel of the locked rectangle. */
2988 map_desc->data = base_memory
2989 + ((rect->top / format->block_height) * map_desc->row_pitch)
2990 + ((rect->left / format->block_width) * format->block_byte_count);
2992 else
2994 map_desc->data = base_memory
2995 + (map_desc->row_pitch * rect->top)
2996 + (rect->left * format->byte_count);
2998 surface->lockedRect.left = rect->left;
2999 surface->lockedRect.top = rect->top;
3000 surface->lockedRect.right = rect->right;
3001 surface->lockedRect.bottom = rect->bottom;
3004 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3005 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
3007 return WINED3D_OK;
3010 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
3012 HRESULT hr;
3014 TRACE("surface %p, dc %p.\n", surface, dc);
3016 /* Give more detailed info for ddraw. */
3017 if (surface->flags & SFLAG_DCINUSE)
3018 return WINEDDERR_DCALREADYCREATED;
3020 /* Can't GetDC if the surface is locked. */
3021 if (surface->resource.map_count)
3022 return WINED3DERR_INVALIDCALL;
3024 /* Create a DIB section if there isn't a dc yet. */
3025 if (!surface->hDC)
3027 if (surface->flags & SFLAG_CLIENT)
3029 surface_load_location(surface, WINED3D_LOCATION_SYSMEM);
3030 surface_release_client_storage(surface);
3032 hr = surface_create_dib_section(surface);
3033 if (FAILED(hr))
3034 return WINED3DERR_INVALIDCALL;
3035 if (!(surface->map_binding == WINED3D_LOCATION_USER_MEMORY
3036 || surface->flags & SFLAG_PIN_SYSMEM
3037 || surface->pbo))
3038 surface->map_binding = WINED3D_LOCATION_DIB;
3041 surface_load_location(surface, WINED3D_LOCATION_DIB);
3042 surface_invalidate_location(surface, ~WINED3D_LOCATION_DIB);
3044 surface->flags |= SFLAG_DCINUSE;
3045 surface->resource.map_count++;
3047 *dc = surface->hDC;
3048 TRACE("Returning dc %p.\n", *dc);
3050 return WINED3D_OK;
3053 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
3055 TRACE("surface %p, dc %p.\n", surface, dc);
3057 if (!(surface->flags & SFLAG_DCINUSE))
3058 return WINEDDERR_NODC;
3060 if (surface->hDC != dc)
3062 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3063 dc, surface->hDC);
3064 return WINEDDERR_NODC;
3067 surface->resource.map_count--;
3068 surface->flags &= ~SFLAG_DCINUSE;
3070 if (surface->map_binding == WINED3D_LOCATION_USER_MEMORY || (surface->flags & SFLAG_PIN_SYSMEM
3071 && surface->map_binding != WINED3D_LOCATION_DIB))
3073 /* The game Salammbo modifies the surface contents without mapping the surface between
3074 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
3075 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
3076 * Do not only copy the DIB to the map location, but also make sure the map location is
3077 * copied back to the DIB in the next getdc call.
3079 * The same consideration applies to user memory surfaces. */
3080 surface_load_location(surface, surface->map_binding);
3081 surface_invalidate_location(surface, WINED3D_LOCATION_DIB);
3084 return WINED3D_OK;
3087 static void read_from_framebuffer(struct wined3d_surface *surface, DWORD dst_location)
3089 struct wined3d_device *device = surface->resource.device;
3090 const struct wined3d_gl_info *gl_info;
3091 struct wined3d_context *context;
3092 BYTE *mem;
3093 BYTE *row, *top, *bottom;
3094 int i;
3095 BOOL srcIsUpsideDown;
3096 struct wined3d_bo_address data;
3098 surface_get_memory(surface, &data, dst_location);
3100 context = context_acquire(device, surface);
3101 context_apply_blit_state(context, device);
3102 gl_info = context->gl_info;
3104 /* Select the correct read buffer, and give some debug output.
3105 * There is no need to keep track of the current read buffer or reset it, every part of the code
3106 * that reads sets the read buffer as desired.
3108 if (surface_is_offscreen(surface))
3110 /* Mapping the primary render target which is not on a swapchain.
3111 * Read from the back buffer. */
3112 TRACE("Mapping offscreen render target.\n");
3113 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
3114 srcIsUpsideDown = TRUE;
3116 else
3118 /* Onscreen surfaces are always part of a swapchain */
3119 GLenum buffer = surface_get_gl_buffer(surface);
3120 TRACE("Mapping %#x buffer.\n", buffer);
3121 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
3122 checkGLcall("glReadBuffer");
3123 srcIsUpsideDown = FALSE;
3126 if (data.buffer_object)
3128 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, data.buffer_object));
3129 checkGLcall("glBindBufferARB");
3132 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3133 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
3134 checkGLcall("glPixelStorei");
3136 gl_info->gl_ops.gl.p_glReadPixels(0, 0,
3137 surface->resource.width, surface->resource.height,
3138 surface->resource.format->glFormat,
3139 surface->resource.format->glType, data.addr);
3140 checkGLcall("glReadPixels");
3142 /* Reset previous pixel store pack state */
3143 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
3144 checkGLcall("glPixelStorei");
3146 if (!srcIsUpsideDown)
3148 /* glReadPixels returns the image upside down, and there is no way to prevent this.
3149 * Flip the lines in software. */
3150 UINT pitch = wined3d_surface_get_pitch(surface);
3152 if (!(row = HeapAlloc(GetProcessHeap(), 0, pitch)))
3153 goto error;
3155 if (data.buffer_object)
3157 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB));
3158 checkGLcall("glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB)");
3160 else
3161 mem = data.addr;
3163 top = mem;
3164 bottom = mem + pitch * (surface->resource.height - 1);
3165 for (i = 0; i < surface->resource.height / 2; i++)
3167 memcpy(row, top, pitch);
3168 memcpy(top, bottom, pitch);
3169 memcpy(bottom, row, pitch);
3170 top += pitch;
3171 bottom -= pitch;
3173 HeapFree(GetProcessHeap(), 0, row);
3175 if (data.buffer_object)
3176 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB));
3179 error:
3180 if (data.buffer_object)
3182 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
3183 checkGLcall("glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)");
3186 context_release(context);
3189 /* Read the framebuffer contents into a texture. Note that this function
3190 * doesn't do any kind of flipping. Using this on an onscreen surface will
3191 * result in a flipped D3D texture. */
3192 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
3194 struct wined3d_device *device = surface->resource.device;
3195 const struct wined3d_gl_info *gl_info;
3196 struct wined3d_context *context;
3198 context = context_acquire(device, surface);
3199 gl_info = context->gl_info;
3200 device_invalidate_state(device, STATE_FRAMEBUFFER);
3202 surface_prepare_texture(surface, context, srgb);
3203 wined3d_texture_bind_and_dirtify(surface->container, context, srgb);
3205 TRACE("Reading back offscreen render target %p.\n", surface);
3207 if (surface_is_offscreen(surface))
3208 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
3209 else
3210 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
3211 checkGLcall("glReadBuffer");
3213 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
3214 0, 0, 0, 0, surface->resource.width, surface->resource.height);
3215 checkGLcall("glCopyTexSubImage2D");
3217 context_release(context);
3220 /* Context activation is done by the caller. */
3221 static void surface_prepare_texture_internal(struct wined3d_surface *surface,
3222 struct wined3d_context *context, BOOL srgb)
3224 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
3225 enum wined3d_conversion_type convert;
3226 struct wined3d_format format;
3228 if (surface->flags & alloc_flag) return;
3230 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
3231 if (convert != WINED3D_CT_NONE || format.convert)
3232 surface->flags |= SFLAG_CONVERTED;
3233 else surface->flags &= ~SFLAG_CONVERTED;
3235 wined3d_texture_bind_and_dirtify(surface->container, context, srgb);
3236 surface_allocate_surface(surface, context->gl_info, &format, srgb);
3237 surface->flags |= alloc_flag;
3240 /* Context activation is done by the caller. */
3241 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
3243 struct wined3d_texture *texture = surface->container;
3244 UINT sub_count = texture->level_count * texture->layer_count;
3245 UINT i;
3247 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
3249 for (i = 0; i < sub_count; ++i)
3251 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
3252 surface_prepare_texture_internal(s, context, srgb);
3255 return;
3258 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
3260 if (multisample)
3262 if (surface->rb_multisample)
3263 return;
3265 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
3266 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
3267 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
3268 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
3269 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
3271 else
3273 if (surface->rb_resolved)
3274 return;
3276 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
3277 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
3278 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
3279 surface->pow2Width, surface->pow2Height);
3280 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
3284 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
3286 /* FIXME: Is this really how color keys are supposed to work? I think it
3287 * makes more sense to compare the individual channels. */
3288 return color >= color_key->color_space_low_value
3289 && color <= color_key->color_space_high_value;
3292 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
3293 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
3295 const BYTE *source;
3296 BYTE *dest;
3298 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
3299 src, dst, pitch, width, height, outpitch, conversion_type, surface);
3301 switch (conversion_type)
3303 case WINED3D_CT_NONE:
3305 memcpy(dst, src, pitch * height);
3306 break;
3309 case WINED3D_CT_PALETTED:
3310 if (surface->swapchain && surface->swapchain->palette)
3312 unsigned int x, y;
3313 const struct wined3d_palette *palette = surface->swapchain->palette;
3314 for (y = 0; y < height; y++)
3316 source = src + pitch * y;
3317 dest = dst + outpitch * y;
3318 for (x = 0; x < width; x++)
3320 BYTE color = *source++;
3321 *dest++ = palette->colors[color].rgbRed;
3322 *dest++ = palette->colors[color].rgbGreen;
3323 *dest++ = palette->colors[color].rgbBlue;
3324 *dest++ = 0;
3328 else
3330 /* This should probably use the system palette, but unless
3331 * the X server is running in P8 mode there is no such thing.
3332 * The probably best solution is to set the fixed 20 colors
3333 * from the default windows palette and set the rest to black,
3334 * white, or some ugly pink. For now use black for the entire
3335 * palette. Don't use pink everywhere. Age of Empires 2 draws
3336 * a front buffer filled with zeroes without a palette when
3337 * starting and we don't want the screen to flash in an ugly
3338 * color. */
3339 FIXME("P8 surface loaded without a palette.\n");
3340 memset(dst, 0, height * outpitch);
3343 break;
3345 case WINED3D_CT_CK_565:
3347 /* Converting the 565 format in 5551 packed to emulate color-keying.
3349 Note : in all these conversion, it would be best to average the averaging
3350 pixels to get the color of the pixel that will be color-keyed to
3351 prevent 'color bleeding'. This will be done later on if ever it is
3352 too visible.
3354 Note2: Nvidia documents say that their driver does not support alpha + color keying
3355 on the same surface and disables color keying in such a case
3357 unsigned int x, y;
3358 const WORD *Source;
3359 WORD *Dest;
3361 TRACE("Color keyed 565\n");
3363 for (y = 0; y < height; y++) {
3364 Source = (const WORD *)(src + y * pitch);
3365 Dest = (WORD *) (dst + y * outpitch);
3366 for (x = 0; x < width; x++ ) {
3367 WORD color = *Source++;
3368 *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
3369 if (!color_in_range(&surface->container->src_blt_color_key, color))
3370 *Dest |= 0x0001;
3371 Dest++;
3375 break;
3377 case WINED3D_CT_CK_5551:
3379 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
3380 unsigned int x, y;
3381 const WORD *Source;
3382 WORD *Dest;
3383 TRACE("Color keyed 5551\n");
3384 for (y = 0; y < height; y++) {
3385 Source = (const WORD *)(src + y * pitch);
3386 Dest = (WORD *) (dst + y * outpitch);
3387 for (x = 0; x < width; x++ ) {
3388 WORD color = *Source++;
3389 *Dest = color;
3390 if (!color_in_range(&surface->container->src_blt_color_key, color))
3391 *Dest |= (1 << 15);
3392 else
3393 *Dest &= ~(1 << 15);
3394 Dest++;
3398 break;
3400 case WINED3D_CT_CK_RGB24:
3402 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
3403 unsigned int x, y;
3404 for (y = 0; y < height; y++)
3406 source = src + pitch * y;
3407 dest = dst + outpitch * y;
3408 for (x = 0; x < width; x++) {
3409 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
3410 DWORD dstcolor = color << 8;
3411 if (!color_in_range(&surface->container->src_blt_color_key, color))
3412 dstcolor |= 0xff;
3413 *(DWORD*)dest = dstcolor;
3414 source += 3;
3415 dest += 4;
3419 break;
3421 case WINED3D_CT_RGB32_888:
3423 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
3424 unsigned int x, y;
3425 for (y = 0; y < height; y++)
3427 source = src + pitch * y;
3428 dest = dst + outpitch * y;
3429 for (x = 0; x < width; x++) {
3430 DWORD color = 0xffffff & *(const DWORD*)source;
3431 DWORD dstcolor = color << 8;
3432 if (!color_in_range(&surface->container->src_blt_color_key, color))
3433 dstcolor |= 0xff;
3434 *(DWORD*)dest = dstcolor;
3435 source += 4;
3436 dest += 4;
3440 break;
3442 case WINED3D_CT_CK_ARGB32:
3444 unsigned int x, y;
3445 for (y = 0; y < height; ++y)
3447 source = src + pitch * y;
3448 dest = dst + outpitch * y;
3449 for (x = 0; x < width; ++x)
3451 DWORD color = *(const DWORD *)source;
3452 if (color_in_range(&surface->container->src_blt_color_key, color))
3453 color &= ~0xff000000;
3454 *(DWORD*)dest = color;
3455 source += 4;
3456 dest += 4;
3460 break;
3462 default:
3463 ERR("Unsupported conversion type %#x.\n", conversion_type);
3465 return WINED3D_OK;
3468 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
3470 if (front->container->level_count != 1 || front->container->layer_count != 1
3471 || back->container->level_count != 1 || back->container->layer_count != 1)
3472 ERR("Flip between surfaces %p and %p not supported.\n", front, back);
3474 /* Flip the surface contents */
3475 /* Flip the DC */
3477 HDC tmp;
3478 tmp = front->hDC;
3479 front->hDC = back->hDC;
3480 back->hDC = tmp;
3483 /* Flip the DIBsection */
3485 HBITMAP tmp = front->dib.DIBsection;
3486 front->dib.DIBsection = back->dib.DIBsection;
3487 back->dib.DIBsection = tmp;
3490 /* Flip the surface data */
3492 void* tmp;
3494 tmp = front->dib.bitmap_data;
3495 front->dib.bitmap_data = back->dib.bitmap_data;
3496 back->dib.bitmap_data = tmp;
3498 tmp = front->resource.heap_memory;
3499 front->resource.heap_memory = back->resource.heap_memory;
3500 back->resource.heap_memory = tmp;
3503 /* Flip the PBO */
3505 GLuint tmp_pbo = front->pbo;
3506 front->pbo = back->pbo;
3507 back->pbo = tmp_pbo;
3510 /* Flip the opengl texture */
3512 GLuint tmp;
3514 tmp = back->container->texture_rgb.name;
3515 back->container->texture_rgb.name = front->container->texture_rgb.name;
3516 front->container->texture_rgb.name = tmp;
3518 tmp = back->container->texture_srgb.name;
3519 back->container->texture_srgb.name = front->container->texture_srgb.name;
3520 front->container->texture_srgb.name = tmp;
3522 tmp = back->rb_multisample;
3523 back->rb_multisample = front->rb_multisample;
3524 front->rb_multisample = tmp;
3526 tmp = back->rb_resolved;
3527 back->rb_resolved = front->rb_resolved;
3528 front->rb_resolved = tmp;
3530 resource_unload(&back->resource);
3531 resource_unload(&front->resource);
3535 DWORD tmp_flags = back->flags;
3536 back->flags = front->flags;
3537 front->flags = tmp_flags;
3539 tmp_flags = back->locations;
3540 back->locations = front->locations;
3541 front->locations = tmp_flags;
3545 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3546 * pixel copy calls. */
3547 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
3548 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
3550 struct wined3d_device *device = dst_surface->resource.device;
3551 const struct wined3d_gl_info *gl_info;
3552 float xrel, yrel;
3553 struct wined3d_context *context;
3554 BOOL upsidedown = FALSE;
3555 RECT dst_rect = *dst_rect_in;
3557 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3558 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3560 if(dst_rect.top > dst_rect.bottom) {
3561 UINT tmp = dst_rect.bottom;
3562 dst_rect.bottom = dst_rect.top;
3563 dst_rect.top = tmp;
3564 upsidedown = TRUE;
3567 context = context_acquire(device, src_surface);
3568 gl_info = context->gl_info;
3569 context_apply_blit_state(context, device);
3570 wined3d_texture_load(dst_surface->container, context, FALSE);
3572 /* Bind the target texture */
3573 context_bind_texture(context, dst_surface->container->target, dst_surface->container->texture_rgb.name);
3574 if (surface_is_offscreen(src_surface))
3576 TRACE("Reading from an offscreen target\n");
3577 upsidedown = !upsidedown;
3578 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
3580 else
3582 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
3584 checkGLcall("glReadBuffer");
3586 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
3587 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
3589 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3591 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3593 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
3594 ERR("Texture filtering not supported in direct blit.\n");
3596 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
3597 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3599 ERR("Texture filtering not supported in direct blit\n");
3602 if (upsidedown
3603 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3604 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3606 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3607 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3608 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
3609 src_rect->left, src_surface->resource.height - src_rect->bottom,
3610 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3612 else
3614 LONG row;
3615 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
3616 /* I have to process this row by row to swap the image,
3617 * otherwise it would be upside down, so stretching in y direction
3618 * doesn't cost extra time
3620 * However, stretching in x direction can be avoided if not necessary
3622 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
3623 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3625 /* Well, that stuff works, but it's very slow.
3626 * find a better way instead
3628 LONG col;
3630 for (col = dst_rect.left; col < dst_rect.right; ++col)
3632 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3633 dst_rect.left + col /* x offset */, row /* y offset */,
3634 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
3637 else
3639 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
3640 dst_rect.left /* x offset */, row /* y offset */,
3641 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
3645 checkGLcall("glCopyTexSubImage2D");
3647 context_release(context);
3649 /* The texture is now most up to date - If the surface is a render target
3650 * and has a drawable, this path is never entered. */
3651 surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
3652 surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
3655 /* Uses the hardware to stretch and flip the image */
3656 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
3657 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
3659 struct wined3d_device *device = dst_surface->resource.device;
3660 GLuint src, backup = 0;
3661 float left, right, top, bottom; /* Texture coordinates */
3662 UINT fbwidth = src_surface->resource.width;
3663 UINT fbheight = src_surface->resource.height;
3664 const struct wined3d_gl_info *gl_info;
3665 struct wined3d_context *context;
3666 GLenum drawBuffer = GL_BACK;
3667 GLenum texture_target;
3668 BOOL noBackBufferBackup;
3669 BOOL src_offscreen;
3670 BOOL upsidedown = FALSE;
3671 RECT dst_rect = *dst_rect_in;
3673 TRACE("Using hwstretch blit\n");
3674 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3675 context = context_acquire(device, src_surface);
3676 gl_info = context->gl_info;
3677 context_apply_blit_state(context, device);
3678 wined3d_texture_load(dst_surface->container, context, FALSE);
3680 src_offscreen = surface_is_offscreen(src_surface);
3681 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
3682 if (!noBackBufferBackup && !src_surface->container->texture_rgb.name)
3684 /* Get it a description */
3685 wined3d_texture_load(src_surface->container, context, FALSE);
3688 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3689 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3691 if (context->aux_buffers >= 2)
3693 /* Got more than one aux buffer? Use the 2nd aux buffer */
3694 drawBuffer = GL_AUX1;
3696 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
3698 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3699 drawBuffer = GL_AUX0;
3702 if (noBackBufferBackup)
3704 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
3705 checkGLcall("glGenTextures");
3706 context_bind_texture(context, GL_TEXTURE_2D, backup);
3707 texture_target = GL_TEXTURE_2D;
3709 else
3711 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3712 * we are reading from the back buffer, the backup can be used as source texture
3714 texture_target = src_surface->texture_target;
3715 context_bind_texture(context, texture_target, src_surface->container->texture_rgb.name);
3716 gl_info->gl_ops.gl.p_glEnable(texture_target);
3717 checkGLcall("glEnable(texture_target)");
3719 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3720 src_surface->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
3723 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3724 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3726 if(dst_rect.top > dst_rect.bottom) {
3727 UINT tmp = dst_rect.bottom;
3728 dst_rect.bottom = dst_rect.top;
3729 dst_rect.top = tmp;
3730 upsidedown = TRUE;
3733 if (src_offscreen)
3735 TRACE("Reading from an offscreen target\n");
3736 upsidedown = !upsidedown;
3737 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
3739 else
3741 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
3744 /* TODO: Only back up the part that will be overwritten */
3745 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
3747 checkGLcall("glCopyTexSubImage2D");
3749 /* No issue with overriding these - the sampler is dirty due to blit usage */
3750 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
3751 wined3d_gl_mag_filter(magLookup, filter));
3752 checkGLcall("glTexParameteri");
3753 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
3754 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
3755 checkGLcall("glTexParameteri");
3757 if (!src_surface->swapchain || src_surface == src_surface->swapchain->back_buffers[0])
3759 src = backup ? backup : src_surface->container->texture_rgb.name;
3761 else
3763 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
3764 checkGLcall("glReadBuffer(GL_FRONT)");
3766 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
3767 checkGLcall("glGenTextures(1, &src)");
3768 context_bind_texture(context, GL_TEXTURE_2D, src);
3770 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3771 * out for power of 2 sizes
3773 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
3774 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
3775 checkGLcall("glTexImage2D");
3776 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
3778 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3779 checkGLcall("glTexParameteri");
3780 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3781 checkGLcall("glTexParameteri");
3783 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
3784 checkGLcall("glReadBuffer(GL_BACK)");
3786 if (texture_target != GL_TEXTURE_2D)
3788 gl_info->gl_ops.gl.p_glDisable(texture_target);
3789 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
3790 texture_target = GL_TEXTURE_2D;
3793 checkGLcall("glEnd and previous");
3795 left = src_rect->left;
3796 right = src_rect->right;
3798 if (!upsidedown)
3800 top = src_surface->resource.height - src_rect->top;
3801 bottom = src_surface->resource.height - src_rect->bottom;
3803 else
3805 top = src_surface->resource.height - src_rect->bottom;
3806 bottom = src_surface->resource.height - src_rect->top;
3809 if (src_surface->flags & SFLAG_NORMCOORD)
3811 left /= src_surface->pow2Width;
3812 right /= src_surface->pow2Width;
3813 top /= src_surface->pow2Height;
3814 bottom /= src_surface->pow2Height;
3817 /* draw the source texture stretched and upside down. The correct surface is bound already */
3818 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
3819 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
3821 context_set_draw_buffer(context, drawBuffer);
3822 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
3824 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
3825 /* bottom left */
3826 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
3827 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
3829 /* top left */
3830 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
3831 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
3833 /* top right */
3834 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
3835 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3837 /* bottom right */
3838 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
3839 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
3840 gl_info->gl_ops.gl.p_glEnd();
3841 checkGLcall("glEnd and previous");
3843 if (texture_target != dst_surface->texture_target)
3845 gl_info->gl_ops.gl.p_glDisable(texture_target);
3846 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
3847 texture_target = dst_surface->texture_target;
3850 /* Now read the stretched and upside down image into the destination texture */
3851 context_bind_texture(context, texture_target, dst_surface->container->texture_rgb.name);
3852 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
3854 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
3855 0, 0, /* We blitted the image to the origin */
3856 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3857 checkGLcall("glCopyTexSubImage2D");
3859 if (drawBuffer == GL_BACK)
3861 /* Write the back buffer backup back. */
3862 if (backup)
3864 if (texture_target != GL_TEXTURE_2D)
3866 gl_info->gl_ops.gl.p_glDisable(texture_target);
3867 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
3868 texture_target = GL_TEXTURE_2D;
3870 context_bind_texture(context, GL_TEXTURE_2D, backup);
3872 else
3874 if (texture_target != src_surface->texture_target)
3876 gl_info->gl_ops.gl.p_glDisable(texture_target);
3877 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
3878 texture_target = src_surface->texture_target;
3880 context_bind_texture(context, src_surface->texture_target, src_surface->container->texture_rgb.name);
3883 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
3884 /* top left */
3885 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
3886 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
3888 /* bottom left */
3889 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
3890 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
3892 /* bottom right */
3893 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
3894 (float)fbheight / (float)src_surface->pow2Height);
3895 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
3897 /* top right */
3898 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
3899 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
3900 gl_info->gl_ops.gl.p_glEnd();
3902 gl_info->gl_ops.gl.p_glDisable(texture_target);
3903 checkGLcall("glDisable(texture_target)");
3905 /* Cleanup */
3906 if (src != src_surface->container->texture_rgb.name && src != backup)
3908 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
3909 checkGLcall("glDeleteTextures(1, &src)");
3911 if (backup)
3913 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
3914 checkGLcall("glDeleteTextures(1, &backup)");
3917 if (wined3d_settings.strict_draw_ordering)
3918 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
3920 context_release(context);
3922 /* The texture is now most up to date - If the surface is a render target
3923 * and has a drawable, this path is never entered. */
3924 surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
3925 surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
3928 /* Front buffer coordinates are always full screen coordinates, but our GL
3929 * drawable is limited to the window's client area. The sysmem and texture
3930 * copies do have the full screen size. Note that GL has a bottom-left
3931 * origin, while D3D has a top-left origin. */
3932 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
3934 UINT drawable_height;
3936 if (surface->swapchain && surface == surface->swapchain->front_buffer)
3938 POINT offset = {0, 0};
3939 RECT windowsize;
3941 ScreenToClient(window, &offset);
3942 OffsetRect(rect, offset.x, offset.y);
3944 GetClientRect(window, &windowsize);
3945 drawable_height = windowsize.bottom - windowsize.top;
3947 else
3949 drawable_height = surface->resource.height;
3952 rect->top = drawable_height - rect->top;
3953 rect->bottom = drawable_height - rect->bottom;
3956 static void surface_blt_to_drawable(const struct wined3d_device *device,
3957 enum wined3d_texture_filter_type filter, BOOL alpha_test,
3958 struct wined3d_surface *src_surface, const RECT *src_rect_in,
3959 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
3961 const struct wined3d_gl_info *gl_info;
3962 struct wined3d_context *context;
3963 RECT src_rect, dst_rect;
3965 src_rect = *src_rect_in;
3966 dst_rect = *dst_rect_in;
3968 context = context_acquire(device, dst_surface);
3969 gl_info = context->gl_info;
3971 /* Make sure the surface is up-to-date. This should probably use
3972 * surface_load_location() and worry about the destination surface too,
3973 * unless we're overwriting it completely. */
3974 wined3d_texture_load(src_surface->container, context, FALSE);
3976 /* Activate the destination context, set it up for blitting */
3977 context_apply_blit_state(context, device);
3979 if (!surface_is_offscreen(dst_surface))
3980 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
3982 device->blitter->set_shader(device->blit_priv, context, src_surface);
3984 if (alpha_test)
3986 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
3987 checkGLcall("glEnable(GL_ALPHA_TEST)");
3989 /* For P8 surfaces, the alpha component contains the palette index.
3990 * Which means that the colorkey is one of the palette entries. In
3991 * other cases pixels that should be masked away have alpha set to 0. */
3992 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT)
3993 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
3994 (float)src_surface->container->src_blt_color_key.color_space_low_value / 256.0f);
3995 else
3996 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
3997 checkGLcall("glAlphaFunc");
3999 else
4001 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
4002 checkGLcall("glDisable(GL_ALPHA_TEST)");
4005 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
4007 if (alpha_test)
4009 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
4010 checkGLcall("glDisable(GL_ALPHA_TEST)");
4013 /* Leave the opengl state valid for blitting */
4014 device->blitter->unset_shader(context->gl_info);
4016 if (wined3d_settings.strict_draw_ordering
4017 || (dst_surface->swapchain && dst_surface->swapchain->front_buffer == dst_surface))
4018 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
4020 context_release(context);
4023 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
4025 struct wined3d_device *device = s->resource.device;
4026 const struct blit_shader *blitter;
4028 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
4029 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
4030 if (!blitter)
4032 FIXME("No blitter is capable of performing the requested color fill operation.\n");
4033 return WINED3DERR_INVALIDCALL;
4036 return blitter->color_fill(device, s, rect, color);
4039 static HRESULT surface_blt_special(struct wined3d_surface *dst_surface, const RECT *dst_rect,
4040 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
4041 enum wined3d_texture_filter_type filter)
4043 struct wined3d_device *device = dst_surface->resource.device;
4044 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4045 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
4047 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
4048 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
4049 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
4051 /* Get the swapchain. One of the surfaces has to be a primary surface */
4052 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
4054 WARN("Destination is in sysmem, rejecting gl blt\n");
4055 return WINED3DERR_INVALIDCALL;
4058 dst_swapchain = dst_surface->swapchain;
4060 if (src_surface)
4062 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
4064 WARN("Src is in sysmem, rejecting gl blt\n");
4065 return WINED3DERR_INVALIDCALL;
4068 src_swapchain = src_surface->swapchain;
4070 else
4072 src_swapchain = NULL;
4075 /* Early sort out of cases where no render target is used */
4076 if (!dst_swapchain && !src_swapchain
4077 && src_surface != device->fb.render_targets[0]
4078 && dst_surface != device->fb.render_targets[0])
4080 TRACE("No surface is render target, not using hardware blit.\n");
4081 return WINED3DERR_INVALIDCALL;
4084 /* No destination color keying supported */
4085 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
4087 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
4088 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
4089 return WINED3DERR_INVALIDCALL;
4092 if (dst_swapchain && dst_swapchain == src_swapchain)
4094 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
4095 return WINED3DERR_INVALIDCALL;
4098 if (dst_swapchain && src_swapchain)
4100 FIXME("Implement hardware blit between two different swapchains\n");
4101 return WINED3DERR_INVALIDCALL;
4104 if (dst_swapchain)
4106 /* Handled with regular texture -> swapchain blit */
4107 if (src_surface == device->fb.render_targets[0])
4108 TRACE("Blit from active render target to a swapchain\n");
4110 else if (src_swapchain && dst_surface == device->fb.render_targets[0])
4112 FIXME("Implement blit from a swapchain to the active render target\n");
4113 return WINED3DERR_INVALIDCALL;
4116 if ((src_swapchain || src_surface == device->fb.render_targets[0]) && !dst_swapchain)
4118 /* Blit from render target to texture */
4119 BOOL stretchx;
4121 /* P8 read back is not implemented */
4122 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
4123 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
4125 TRACE("P8 read back not supported by frame buffer to texture blit\n");
4126 return WINED3DERR_INVALIDCALL;
4129 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
4131 TRACE("Color keying not supported by frame buffer to texture blit\n");
4132 return WINED3DERR_INVALIDCALL;
4133 /* Destination color key is checked above */
4136 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
4137 stretchx = TRUE;
4138 else
4139 stretchx = FALSE;
4141 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
4142 * flip the image nor scale it.
4144 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
4145 * -> If the app wants an image width an unscaled width, copy it line per line
4146 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
4147 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
4148 * back buffer. This is slower than reading line per line, thus not used for flipping
4149 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
4150 * pixel by pixel. */
4151 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
4152 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
4154 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
4155 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
4157 else
4159 TRACE("Using hardware stretching to flip / stretch the texture.\n");
4160 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
4163 surface_evict_sysmem(dst_surface);
4165 return WINED3D_OK;
4167 else if (src_surface)
4169 /* Blit from offscreen surface to render target */
4170 struct wined3d_color_key old_blt_key = src_surface->container->src_blt_color_key;
4171 DWORD old_color_key_flags = src_surface->container->color_key_flags;
4173 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
4175 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4176 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
4177 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
4179 FIXME("Unsupported blit operation falling back to software\n");
4180 return WINED3DERR_INVALIDCALL;
4183 /* Color keying: Check if we have to do a color keyed blt,
4184 * and if not check if a color key is activated.
4186 * Just modify the color keying parameters in the surface and restore them afterwards
4187 * The surface keeps track of the color key last used to load the opengl surface.
4188 * PreLoad will catch the change to the flags and color key and reload if necessary.
4190 if (flags & WINEDDBLT_KEYSRC)
4192 /* Use color key from surface */
4194 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
4196 /* Use color key from DDBltFx */
4197 src_surface->container->color_key_flags |= WINEDDSD_CKSRCBLT;
4198 src_surface->container->src_blt_color_key = DDBltFx->ddckSrcColorkey;
4200 else
4202 /* Do not use color key */
4203 src_surface->container->color_key_flags &= ~WINEDDSD_CKSRCBLT;
4206 surface_blt_to_drawable(device, filter,
4207 flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_ALPHATEST),
4208 src_surface, src_rect, dst_surface, dst_rect);
4210 /* Restore the color key parameters */
4211 src_surface->container->color_key_flags = old_color_key_flags;
4212 src_surface->container->src_blt_color_key = old_blt_key;
4214 surface_validate_location(dst_surface, dst_surface->draw_binding);
4215 surface_invalidate_location(dst_surface, ~dst_surface->draw_binding);
4217 return WINED3D_OK;
4220 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
4221 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
4222 return WINED3DERR_INVALIDCALL;
4225 /* Context activation is done by the caller. */
4226 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
4227 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
4229 struct wined3d_device *device = surface->resource.device;
4230 const struct wined3d_gl_info *gl_info = context->gl_info;
4231 GLint compare_mode = GL_NONE;
4232 struct blt_info info;
4233 GLint old_binding = 0;
4234 RECT rect;
4236 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
4238 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
4239 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
4240 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
4241 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
4242 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
4243 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
4244 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
4245 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
4246 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
4247 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
4248 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
4250 SetRect(&rect, 0, h, w, 0);
4251 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
4252 context_active_texture(context, context->gl_info, 0);
4253 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
4254 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
4255 if (gl_info->supported[ARB_SHADOW])
4257 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
4258 if (compare_mode != GL_NONE)
4259 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
4262 device->shader_backend->shader_select_depth_blt(device->shader_priv,
4263 gl_info, info.tex_type, &surface->ds_current_size);
4265 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
4266 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
4267 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
4268 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
4269 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
4270 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
4271 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
4272 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
4273 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
4274 gl_info->gl_ops.gl.p_glEnd();
4276 if (compare_mode != GL_NONE)
4277 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
4278 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
4280 gl_info->gl_ops.gl.p_glPopAttrib();
4282 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
4285 void surface_modify_ds_location(struct wined3d_surface *surface,
4286 DWORD location, UINT w, UINT h)
4288 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
4290 if (((surface->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
4291 || (!(surface->locations & WINED3D_LOCATION_TEXTURE_RGB) && (location & WINED3D_LOCATION_TEXTURE_RGB)))
4292 wined3d_texture_set_dirty(surface->container);
4294 surface->ds_current_size.cx = w;
4295 surface->ds_current_size.cy = h;
4296 surface->locations = location;
4299 /* Context activation is done by the caller. */
4300 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
4302 const struct wined3d_gl_info *gl_info = context->gl_info;
4303 struct wined3d_device *device = surface->resource.device;
4304 GLsizei w, h;
4306 TRACE("surface %p, new location %#x.\n", surface, location);
4308 /* TODO: Make this work for modes other than FBO */
4309 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
4311 if (!(surface->locations & location))
4313 w = surface->ds_current_size.cx;
4314 h = surface->ds_current_size.cy;
4315 surface->ds_current_size.cx = 0;
4316 surface->ds_current_size.cy = 0;
4318 else
4320 w = surface->resource.width;
4321 h = surface->resource.height;
4324 if (surface->ds_current_size.cx == surface->resource.width
4325 && surface->ds_current_size.cy == surface->resource.height)
4327 TRACE("Location (%#x) is already up to date.\n", location);
4328 return;
4331 if (surface->current_renderbuffer)
4333 FIXME("Not supported with fixed up depth stencil.\n");
4334 return;
4337 if (surface->locations & WINED3D_LOCATION_DISCARDED)
4339 TRACE("Surface was discarded, no need copy data.\n");
4340 switch (location)
4342 case WINED3D_LOCATION_TEXTURE_RGB:
4343 surface_prepare_texture(surface, context, FALSE);
4344 break;
4345 case WINED3D_LOCATION_RB_MULTISAMPLE:
4346 surface_prepare_rb(surface, gl_info, TRUE);
4347 break;
4348 case WINED3D_LOCATION_DRAWABLE:
4349 /* Nothing to do */
4350 break;
4351 default:
4352 FIXME("Unhandled location %#x\n", location);
4354 surface->locations &= ~WINED3D_LOCATION_DISCARDED;
4355 surface->locations |= location;
4356 surface->ds_current_size.cx = surface->resource.width;
4357 surface->ds_current_size.cy = surface->resource.height;
4358 return;
4361 if (!surface->locations)
4363 FIXME("No up to date depth stencil location.\n");
4364 surface->locations |= location;
4365 surface->ds_current_size.cx = surface->resource.width;
4366 surface->ds_current_size.cy = surface->resource.height;
4367 return;
4370 if (location == WINED3D_LOCATION_TEXTURE_RGB)
4372 GLint old_binding = 0;
4373 GLenum bind_target;
4375 /* The render target is allowed to be smaller than the depth/stencil
4376 * buffer, so the onscreen depth/stencil buffer is potentially smaller
4377 * than the offscreen surface. Don't overwrite the offscreen surface
4378 * with undefined data. */
4379 w = min(w, context->swapchain->desc.backbuffer_width);
4380 h = min(h, context->swapchain->desc.backbuffer_height);
4382 TRACE("Copying onscreen depth buffer to depth texture.\n");
4384 if (!device->depth_blt_texture)
4385 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
4387 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4388 * directly on the FBO texture. That's because we need to flip. */
4389 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
4390 context->swapchain->front_buffer, NULL, WINED3D_LOCATION_DRAWABLE);
4391 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
4393 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
4394 bind_target = GL_TEXTURE_RECTANGLE_ARB;
4396 else
4398 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
4399 bind_target = GL_TEXTURE_2D;
4401 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
4402 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
4403 * internal format, because the internal format might include stencil
4404 * data. In principle we should copy stencil data as well, but unless
4405 * the driver supports stencil export it's hard to do, and doesn't
4406 * seem to be needed in practice. If the hardware doesn't support
4407 * writing stencil data, the glCopyTexImage2D() call might trigger
4408 * software fallbacks. */
4409 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
4410 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4411 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4412 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4413 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4414 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
4415 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
4416 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
4418 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
4419 NULL, surface, WINED3D_LOCATION_TEXTURE_RGB);
4420 context_set_draw_buffer(context, GL_NONE);
4422 /* Do the actual blit */
4423 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
4424 checkGLcall("depth_blt");
4426 context_invalidate_state(context, STATE_FRAMEBUFFER);
4428 if (wined3d_settings.strict_draw_ordering)
4429 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
4431 else if (location == WINED3D_LOCATION_DRAWABLE)
4433 TRACE("Copying depth texture to onscreen depth buffer.\n");
4435 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
4436 context->swapchain->front_buffer, NULL, WINED3D_LOCATION_DRAWABLE);
4437 surface_depth_blt(surface, context, surface->container->texture_rgb.name,
4438 0, surface->pow2Height - h, w, h, surface->texture_target);
4439 checkGLcall("depth_blt");
4441 context_invalidate_state(context, STATE_FRAMEBUFFER);
4443 if (wined3d_settings.strict_draw_ordering)
4444 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
4446 else
4448 ERR("Invalid location (%#x) specified.\n", location);
4451 surface->locations |= location;
4452 surface->ds_current_size.cx = surface->resource.width;
4453 surface->ds_current_size.cy = surface->resource.height;
4456 void surface_validate_location(struct wined3d_surface *surface, DWORD location)
4458 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
4460 surface->locations |= location;
4463 void surface_invalidate_location(struct wined3d_surface *surface, DWORD location)
4465 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
4467 if (location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
4468 wined3d_texture_set_dirty(surface->container);
4469 surface->locations &= ~location;
4471 if (!surface->locations)
4472 ERR("Surface %p does not have any up to date location.\n", surface);
4475 static DWORD resource_access_from_location(DWORD location)
4477 switch (location)
4479 case WINED3D_LOCATION_SYSMEM:
4480 case WINED3D_LOCATION_USER_MEMORY:
4481 case WINED3D_LOCATION_DIB:
4482 case WINED3D_LOCATION_BUFFER:
4483 return WINED3D_RESOURCE_ACCESS_CPU;
4485 case WINED3D_LOCATION_DRAWABLE:
4486 case WINED3D_LOCATION_TEXTURE_SRGB:
4487 case WINED3D_LOCATION_TEXTURE_RGB:
4488 case WINED3D_LOCATION_RB_MULTISAMPLE:
4489 case WINED3D_LOCATION_RB_RESOLVED:
4490 return WINED3D_RESOURCE_ACCESS_GPU;
4492 default:
4493 FIXME("Unhandled location %#x.\n", location);
4494 return 0;
4498 static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
4500 struct wined3d_device *device = surface->resource.device;
4501 struct wined3d_context *context;
4502 const struct wined3d_gl_info *gl_info;
4503 struct wined3d_bo_address dst, src;
4504 UINT size = surface->resource.size;
4506 surface_get_memory(surface, &dst, location);
4507 surface_get_memory(surface, &src, surface->locations);
4509 if (dst.buffer_object)
4511 context = context_acquire(device, NULL);
4512 gl_info = context->gl_info;
4513 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, dst.buffer_object));
4514 GL_EXTCALL(glBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, size, src.addr));
4515 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4516 checkGLcall("Upload PBO");
4517 context_release(context);
4518 return;
4520 if (src.buffer_object)
4522 context = context_acquire(device, NULL);
4523 gl_info = context->gl_info;
4524 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, src.buffer_object));
4525 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_PACK_BUFFER_ARB, 0, size, dst.addr));
4526 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4527 checkGLcall("Download PBO");
4528 context_release(context);
4529 return;
4531 memcpy(dst.addr, src.addr, size);
4534 static void surface_load_sysmem(struct wined3d_surface *surface,
4535 const struct wined3d_gl_info *gl_info, DWORD dst_location)
4537 if (surface->locations & surface_simple_locations)
4539 surface_copy_simple_location(surface, dst_location);
4540 return;
4543 if (surface->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
4544 surface_load_location(surface, WINED3D_LOCATION_TEXTURE_RGB);
4546 /* Download the surface to system memory. */
4547 if (surface->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
4549 struct wined3d_device *device = surface->resource.device;
4550 struct wined3d_context *context;
4552 /* TODO: Use already acquired context when possible. */
4553 context = context_acquire(device, NULL);
4555 wined3d_texture_bind_and_dirtify(surface->container, context,
4556 !(surface->locations & WINED3D_LOCATION_TEXTURE_RGB));
4557 surface_download_data(surface, gl_info, dst_location);
4559 context_release(context);
4561 return;
4564 if (surface->locations & WINED3D_LOCATION_DRAWABLE)
4566 read_from_framebuffer(surface, dst_location);
4567 return;
4570 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4571 surface, wined3d_debug_location(surface->locations));
4574 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
4575 const struct wined3d_gl_info *gl_info)
4577 RECT r;
4579 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
4581 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4582 return WINED3DERR_INVALIDCALL;
4585 surface_get_rect(surface, NULL, &r);
4586 surface_load_location(surface, WINED3D_LOCATION_TEXTURE_RGB);
4587 surface_blt_to_drawable(surface->resource.device,
4588 WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
4590 return WINED3D_OK;
4593 static HRESULT surface_load_texture(struct wined3d_surface *surface,
4594 const struct wined3d_gl_info *gl_info, BOOL srgb)
4596 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
4597 struct wined3d_device *device = surface->resource.device;
4598 enum wined3d_conversion_type convert;
4599 struct wined3d_context *context;
4600 UINT width, src_pitch, dst_pitch;
4601 struct wined3d_bo_address data;
4602 struct wined3d_format format;
4603 POINT dst_point = {0, 0};
4604 BYTE *mem = NULL;
4606 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
4607 && surface_is_offscreen(surface)
4608 && (surface->locations & WINED3D_LOCATION_DRAWABLE))
4610 surface_load_fb_texture(surface, srgb);
4612 return WINED3D_OK;
4615 if (surface->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
4616 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
4617 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4618 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
4619 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
4621 if (srgb)
4622 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
4623 &src_rect, surface, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
4624 else
4625 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_SRGB,
4626 &src_rect, surface, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
4628 return WINED3D_OK;
4631 if (surface->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
4632 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
4633 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4634 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
4635 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
4637 DWORD src_location = surface->locations & WINED3D_LOCATION_RB_RESOLVED ?
4638 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
4639 DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
4640 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
4642 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
4643 &rect, surface, dst_location, &rect);
4645 return WINED3D_OK;
4648 /* Upload from system memory */
4650 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
4651 TRUE /* We will use textures */, &format, &convert);
4653 if (srgb)
4655 if ((surface->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->map_binding))
4656 == WINED3D_LOCATION_TEXTURE_RGB)
4658 /* Performance warning... */
4659 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
4660 surface_prepare_map_memory(surface);
4661 surface_load_location(surface, surface->map_binding);
4664 else
4666 if ((surface->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->map_binding))
4667 == WINED3D_LOCATION_TEXTURE_SRGB)
4669 /* Performance warning... */
4670 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
4671 surface_prepare_map_memory(surface);
4672 surface_load_location(surface, surface->map_binding);
4676 if (!(surface->locations & surface_simple_locations))
4678 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4679 /* Lets hope we get it from somewhere... */
4680 surface_prepare_system_memory(surface);
4681 surface_load_location(surface, WINED3D_LOCATION_SYSMEM);
4684 /* TODO: Use already acquired context when possible. */
4685 context = context_acquire(device, NULL);
4687 surface_prepare_texture(surface, context, srgb);
4688 wined3d_texture_bind_and_dirtify(surface->container, context, srgb);
4690 if (surface->container->color_key_flags & WINEDDSD_CKSRCBLT)
4692 surface->flags |= SFLAG_GLCKEY;
4693 surface->gl_color_key = surface->container->src_blt_color_key;
4695 else surface->flags &= ~SFLAG_GLCKEY;
4697 width = surface->resource.width;
4698 src_pitch = wined3d_surface_get_pitch(surface);
4700 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4701 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
4702 * called. */
4703 if ((convert != WINED3D_CT_NONE || format.convert) && surface->pbo)
4705 TRACE("Removing the pbo attached to surface %p.\n", surface);
4707 if (surface->flags & SFLAG_DIBSECTION)
4708 surface->map_binding = WINED3D_LOCATION_DIB;
4709 else
4710 surface->map_binding = WINED3D_LOCATION_SYSMEM;
4712 surface_prepare_map_memory(surface);
4713 surface_load_location(surface, surface->map_binding);
4714 surface_remove_pbo(surface, gl_info);
4717 surface_get_memory(surface, &data, surface->locations);
4718 if (format.convert)
4720 /* This code is entered for texture formats which need a fixup. */
4721 UINT height = surface->resource.height;
4723 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4724 dst_pitch = width * format.conv_byte_count;
4725 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4727 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
4729 ERR("Out of memory (%u).\n", dst_pitch * height);
4730 context_release(context);
4731 return E_OUTOFMEMORY;
4733 format.convert(data.addr, mem, src_pitch, src_pitch * height,
4734 dst_pitch, dst_pitch * height, width, height, 1);
4735 format.byte_count = format.conv_byte_count;
4736 src_pitch = dst_pitch;
4737 data.addr = mem;
4739 else if (convert != WINED3D_CT_NONE)
4741 /* This code is only entered for color keying fixups */
4742 UINT height = surface->resource.height;
4744 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4745 dst_pitch = width * format.conv_byte_count;
4746 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4748 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
4750 ERR("Out of memory (%u).\n", dst_pitch * height);
4751 context_release(context);
4752 return E_OUTOFMEMORY;
4754 d3dfmt_convert_surface(data.addr, mem, src_pitch,
4755 width, height, dst_pitch, convert, surface);
4756 format.byte_count = format.conv_byte_count;
4757 src_pitch = dst_pitch;
4758 data.addr = mem;
4761 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
4763 context_release(context);
4765 HeapFree(GetProcessHeap(), 0, mem);
4767 return WINED3D_OK;
4770 static void surface_multisample_resolve(struct wined3d_surface *surface)
4772 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
4774 if (!(surface->locations & WINED3D_LOCATION_RB_MULTISAMPLE))
4775 ERR("Trying to resolve multisampled surface %p, but location WINED3D_LOCATION_RB_MULTISAMPLE not current.\n",
4776 surface);
4778 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
4779 surface, WINED3D_LOCATION_RB_MULTISAMPLE, &rect, surface, WINED3D_LOCATION_RB_RESOLVED, &rect);
4782 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location)
4784 struct wined3d_device *device = surface->resource.device;
4785 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4786 HRESULT hr;
4788 TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
4790 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
4792 if (location == WINED3D_LOCATION_TEXTURE_RGB
4793 && surface->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_DISCARDED))
4795 struct wined3d_context *context = context_acquire(device, NULL);
4796 surface_load_ds_location(surface, context, location);
4797 context_release(context);
4798 return WINED3D_OK;
4800 else if (location & surface->locations && surface->draw_binding != WINED3D_LOCATION_DRAWABLE)
4802 /* Already up to date, nothing to do. */
4803 return WINED3D_OK;
4805 else
4807 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4808 wined3d_debug_location(surface->locations), wined3d_debug_location(location));
4809 return WINED3DERR_INVALIDCALL;
4813 if (surface->locations & location)
4815 TRACE("Location already up to date.\n");
4816 return WINED3D_OK;
4819 if (WARN_ON(d3d_surface))
4821 DWORD required_access = resource_access_from_location(location);
4822 if ((surface->resource.access_flags & required_access) != required_access)
4823 WARN("Operation requires %#x access, but surface only has %#x.\n",
4824 required_access, surface->resource.access_flags);
4827 if (!surface->locations)
4829 ERR("Surface %p does not have any up to date location.\n", surface);
4830 surface->flags |= SFLAG_LOST;
4831 return WINED3DERR_DEVICELOST;
4834 switch (location)
4836 case WINED3D_LOCATION_DIB:
4837 case WINED3D_LOCATION_USER_MEMORY:
4838 case WINED3D_LOCATION_SYSMEM:
4839 case WINED3D_LOCATION_BUFFER:
4840 surface_load_sysmem(surface, gl_info, location);
4841 break;
4843 case WINED3D_LOCATION_DRAWABLE:
4844 if (FAILED(hr = surface_load_drawable(surface, gl_info)))
4845 return hr;
4846 break;
4848 case WINED3D_LOCATION_RB_RESOLVED:
4849 surface_multisample_resolve(surface);
4850 break;
4852 case WINED3D_LOCATION_TEXTURE_RGB:
4853 case WINED3D_LOCATION_TEXTURE_SRGB:
4854 if (FAILED(hr = surface_load_texture(surface, gl_info, location == WINED3D_LOCATION_TEXTURE_SRGB)))
4855 return hr;
4856 break;
4858 default:
4859 ERR("Don't know how to handle location %#x.\n", location);
4860 break;
4863 surface_validate_location(surface, location);
4865 if (location != WINED3D_LOCATION_SYSMEM && (surface->locations & WINED3D_LOCATION_SYSMEM))
4866 surface_evict_sysmem(surface);
4868 return WINED3D_OK;
4871 BOOL surface_is_offscreen(const struct wined3d_surface *surface)
4873 struct wined3d_swapchain *swapchain;
4875 /* Not on a swapchain - must be offscreen */
4876 if (!(swapchain = surface->swapchain))
4877 return TRUE;
4879 /* The front buffer is always onscreen */
4880 if (surface == swapchain->front_buffer) return FALSE;
4882 /* If the swapchain is rendered to an FBO, the backbuffer is
4883 * offscreen, otherwise onscreen */
4884 return swapchain->render_to_fbo;
4887 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
4888 /* Context activation is done by the caller. */
4889 static void ffp_blit_free(struct wined3d_device *device) { }
4891 /* Context activation is done by the caller. */
4892 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
4894 const struct wined3d_gl_info *gl_info = context->gl_info;
4896 gl_info->gl_ops.gl.p_glEnable(surface->container->target);
4897 checkGLcall("glEnable(target)");
4899 return WINED3D_OK;
4902 /* Context activation is done by the caller. */
4903 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
4905 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
4906 checkGLcall("glDisable(GL_TEXTURE_2D)");
4907 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
4909 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
4910 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4912 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
4914 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
4915 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4919 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
4920 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
4921 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
4923 switch (blit_op)
4925 case WINED3D_BLIT_OP_COLOR_BLIT:
4926 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
4927 return FALSE;
4929 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
4931 TRACE("Checking support for fixup:\n");
4932 dump_color_fixup_desc(src_format->color_fixup);
4935 /* We only support identity conversions. */
4936 if (!is_identity_fixup(src_format->color_fixup)
4937 || !is_identity_fixup(dst_format->color_fixup))
4939 TRACE("Fixups are not supported.\n");
4940 return FALSE;
4943 return TRUE;
4945 case WINED3D_BLIT_OP_COLOR_FILL:
4946 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
4947 return FALSE;
4949 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4951 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
4952 return FALSE;
4954 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
4956 TRACE("Color fill not supported\n");
4957 return FALSE;
4960 /* FIXME: We should reject color fills on formats with fixups,
4961 * but this would break P8 color fills for example. */
4963 return TRUE;
4965 case WINED3D_BLIT_OP_DEPTH_FILL:
4966 return TRUE;
4968 default:
4969 TRACE("Unsupported blit_op=%d\n", blit_op);
4970 return FALSE;
4974 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
4975 const RECT *dst_rect, const struct wined3d_color *color)
4977 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
4978 struct wined3d_fb_state fb = {&dst_surface, NULL};
4980 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
4982 return WINED3D_OK;
4985 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
4986 struct wined3d_surface *surface, const RECT *rect, float depth)
4988 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
4989 struct wined3d_fb_state fb = {NULL, surface};
4991 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
4993 return WINED3D_OK;
4996 const struct blit_shader ffp_blit = {
4997 ffp_blit_alloc,
4998 ffp_blit_free,
4999 ffp_blit_set,
5000 ffp_blit_unset,
5001 ffp_blit_supported,
5002 ffp_blit_color_fill,
5003 ffp_blit_depth_fill,
5006 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
5008 return WINED3D_OK;
5011 /* Context activation is done by the caller. */
5012 static void cpu_blit_free(struct wined3d_device *device)
5016 /* Context activation is done by the caller. */
5017 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
5019 return WINED3D_OK;
5022 /* Context activation is done by the caller. */
5023 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
5027 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
5028 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
5029 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
5031 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
5033 return TRUE;
5036 return FALSE;
5039 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
5040 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
5041 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
5043 UINT row_block_count;
5044 const BYTE *src_row;
5045 BYTE *dst_row;
5046 UINT x, y;
5048 src_row = src_data;
5049 dst_row = dst_data;
5051 row_block_count = (update_w + format->block_width - 1) / format->block_width;
5053 if (!flags)
5055 for (y = 0; y < update_h; y += format->block_height)
5057 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
5058 src_row += src_pitch;
5059 dst_row += dst_pitch;
5062 return WINED3D_OK;
5065 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
5067 src_row += (((update_h / format->block_height) - 1) * src_pitch);
5069 switch (format->id)
5071 case WINED3DFMT_DXT1:
5072 for (y = 0; y < update_h; y += format->block_height)
5074 struct block
5076 WORD color[2];
5077 BYTE control_row[4];
5080 const struct block *s = (const struct block *)src_row;
5081 struct block *d = (struct block *)dst_row;
5083 for (x = 0; x < row_block_count; ++x)
5085 d[x].color[0] = s[x].color[0];
5086 d[x].color[1] = s[x].color[1];
5087 d[x].control_row[0] = s[x].control_row[3];
5088 d[x].control_row[1] = s[x].control_row[2];
5089 d[x].control_row[2] = s[x].control_row[1];
5090 d[x].control_row[3] = s[x].control_row[0];
5092 src_row -= src_pitch;
5093 dst_row += dst_pitch;
5095 return WINED3D_OK;
5097 case WINED3DFMT_DXT2:
5098 case WINED3DFMT_DXT3:
5099 for (y = 0; y < update_h; y += format->block_height)
5101 struct block
5103 WORD alpha_row[4];
5104 WORD color[2];
5105 BYTE control_row[4];
5108 const struct block *s = (const struct block *)src_row;
5109 struct block *d = (struct block *)dst_row;
5111 for (x = 0; x < row_block_count; ++x)
5113 d[x].alpha_row[0] = s[x].alpha_row[3];
5114 d[x].alpha_row[1] = s[x].alpha_row[2];
5115 d[x].alpha_row[2] = s[x].alpha_row[1];
5116 d[x].alpha_row[3] = s[x].alpha_row[0];
5117 d[x].color[0] = s[x].color[0];
5118 d[x].color[1] = s[x].color[1];
5119 d[x].control_row[0] = s[x].control_row[3];
5120 d[x].control_row[1] = s[x].control_row[2];
5121 d[x].control_row[2] = s[x].control_row[1];
5122 d[x].control_row[3] = s[x].control_row[0];
5124 src_row -= src_pitch;
5125 dst_row += dst_pitch;
5127 return WINED3D_OK;
5129 default:
5130 FIXME("Compressed flip not implemented for format %s.\n",
5131 debug_d3dformat(format->id));
5132 return E_NOTIMPL;
5136 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
5137 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
5139 return E_NOTIMPL;
5142 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5143 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
5144 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
5146 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
5147 const struct wined3d_format *src_format, *dst_format;
5148 struct wined3d_texture *src_texture = NULL;
5149 struct wined3d_map_desc dst_map, src_map;
5150 const BYTE *sbase = NULL;
5151 HRESULT hr = WINED3D_OK;
5152 const BYTE *sbuf;
5153 BYTE *dbuf;
5154 int x, y;
5156 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5157 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5158 flags, fx, debug_d3dtexturefiltertype(filter));
5160 if (src_surface == dst_surface)
5162 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
5163 src_map = dst_map;
5164 src_format = dst_surface->resource.format;
5165 dst_format = src_format;
5167 else
5169 dst_format = dst_surface->resource.format;
5170 if (src_surface)
5172 if (dst_surface->resource.format->id != src_surface->resource.format->id)
5174 if (!(src_texture = surface_convert_format(src_surface, dst_format->id)))
5176 /* The conv function writes a FIXME */
5177 WARN("Cannot convert source surface format to dest format.\n");
5178 goto release;
5180 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, 0));
5182 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
5183 src_format = src_surface->resource.format;
5185 else
5187 src_format = dst_format;
5190 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
5193 bpp = dst_surface->resource.format->byte_count;
5194 srcheight = src_rect->bottom - src_rect->top;
5195 srcwidth = src_rect->right - src_rect->left;
5196 dstheight = dst_rect->bottom - dst_rect->top;
5197 dstwidth = dst_rect->right - dst_rect->left;
5198 width = (dst_rect->right - dst_rect->left) * bpp;
5200 if (src_surface)
5201 sbase = (BYTE *)src_map.data
5202 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
5203 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
5204 if (src_surface != dst_surface)
5205 dbuf = dst_map.data;
5206 else
5207 dbuf = (BYTE *)dst_map.data
5208 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
5209 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
5211 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
5213 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
5215 if (src_surface == dst_surface)
5217 FIXME("Only plain blits supported on compressed surfaces.\n");
5218 hr = E_NOTIMPL;
5219 goto release;
5222 if (srcheight != dstheight || srcwidth != dstwidth)
5224 WARN("Stretching not supported on compressed surfaces.\n");
5225 hr = WINED3DERR_INVALIDCALL;
5226 goto release;
5229 if (!surface_check_block_align(src_surface, src_rect))
5231 WARN("Source rectangle not block-aligned.\n");
5232 hr = WINED3DERR_INVALIDCALL;
5233 goto release;
5236 if (!surface_check_block_align(dst_surface, dst_rect))
5238 WARN("Destination rectangle not block-aligned.\n");
5239 hr = WINED3DERR_INVALIDCALL;
5240 goto release;
5243 hr = surface_cpu_blt_compressed(sbase, dbuf,
5244 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
5245 src_format, flags, fx);
5246 goto release;
5249 /* First, all the 'source-less' blits */
5250 if (flags & WINEDDBLT_COLORFILL)
5252 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
5253 flags &= ~WINEDDBLT_COLORFILL;
5256 if (flags & WINEDDBLT_DEPTHFILL)
5258 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
5260 if (flags & WINEDDBLT_ROP)
5262 /* Catch some degenerate cases here. */
5263 switch (fx->dwROP)
5265 case BLACKNESS:
5266 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
5267 break;
5268 case 0xaa0029: /* No-op */
5269 break;
5270 case WHITENESS:
5271 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
5272 break;
5273 case SRCCOPY: /* Well, we do that below? */
5274 break;
5275 default:
5276 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
5277 goto error;
5279 flags &= ~WINEDDBLT_ROP;
5281 if (flags & WINEDDBLT_DDROPS)
5283 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
5285 /* Now the 'with source' blits. */
5286 if (src_surface)
5288 int sx, xinc, sy, yinc;
5290 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
5291 goto release;
5293 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
5294 && (srcwidth != dstwidth || srcheight != dstheight))
5296 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
5297 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
5300 xinc = (srcwidth << 16) / dstwidth;
5301 yinc = (srcheight << 16) / dstheight;
5303 if (!flags)
5305 /* No effects, we can cheat here. */
5306 if (dstwidth == srcwidth)
5308 if (dstheight == srcheight)
5310 /* No stretching in either direction. This needs to be as
5311 * fast as possible. */
5312 sbuf = sbase;
5314 /* Check for overlapping surfaces. */
5315 if (src_surface != dst_surface || dst_rect->top < src_rect->top
5316 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
5318 /* No overlap, or dst above src, so copy from top downwards. */
5319 for (y = 0; y < dstheight; ++y)
5321 memcpy(dbuf, sbuf, width);
5322 sbuf += src_map.row_pitch;
5323 dbuf += dst_map.row_pitch;
5326 else if (dst_rect->top > src_rect->top)
5328 /* Copy from bottom upwards. */
5329 sbuf += src_map.row_pitch * dstheight;
5330 dbuf += dst_map.row_pitch * dstheight;
5331 for (y = 0; y < dstheight; ++y)
5333 sbuf -= src_map.row_pitch;
5334 dbuf -= dst_map.row_pitch;
5335 memcpy(dbuf, sbuf, width);
5338 else
5340 /* Src and dst overlapping on the same line, use memmove. */
5341 for (y = 0; y < dstheight; ++y)
5343 memmove(dbuf, sbuf, width);
5344 sbuf += src_map.row_pitch;
5345 dbuf += dst_map.row_pitch;
5349 else
5351 /* Stretching in y direction only. */
5352 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
5354 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
5355 memcpy(dbuf, sbuf, width);
5356 dbuf += dst_map.row_pitch;
5360 else
5362 /* Stretching in X direction. */
5363 int last_sy = -1;
5364 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
5366 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
5368 if ((sy >> 16) == (last_sy >> 16))
5370 /* This source row is the same as last source row -
5371 * Copy the already stretched row. */
5372 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
5374 else
5376 #define STRETCH_ROW(type) \
5377 do { \
5378 const type *s = (const type *)sbuf; \
5379 type *d = (type *)dbuf; \
5380 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5381 d[x] = s[sx >> 16]; \
5382 } while(0)
5384 switch(bpp)
5386 case 1:
5387 STRETCH_ROW(BYTE);
5388 break;
5389 case 2:
5390 STRETCH_ROW(WORD);
5391 break;
5392 case 4:
5393 STRETCH_ROW(DWORD);
5394 break;
5395 case 3:
5397 const BYTE *s;
5398 BYTE *d = dbuf;
5399 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
5401 DWORD pixel;
5403 s = sbuf + 3 * (sx >> 16);
5404 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
5405 d[0] = (pixel ) & 0xff;
5406 d[1] = (pixel >> 8) & 0xff;
5407 d[2] = (pixel >> 16) & 0xff;
5408 d += 3;
5410 break;
5412 default:
5413 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
5414 hr = WINED3DERR_NOTAVAILABLE;
5415 goto error;
5417 #undef STRETCH_ROW
5419 dbuf += dst_map.row_pitch;
5420 last_sy = sy;
5424 else
5426 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
5427 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
5428 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
5429 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
5431 /* The color keying flags are checked for correctness in ddraw */
5432 if (flags & WINEDDBLT_KEYSRC)
5434 keylow = src_surface->container->src_blt_color_key.color_space_low_value;
5435 keyhigh = src_surface->container->src_blt_color_key.color_space_high_value;
5437 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5439 keylow = fx->ddckSrcColorkey.color_space_low_value;
5440 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
5443 if (flags & WINEDDBLT_KEYDEST)
5445 /* Destination color keys are taken from the source surface! */
5446 destkeylow = src_surface->container->dst_blt_color_key.color_space_low_value;
5447 destkeyhigh = src_surface->container->dst_blt_color_key.color_space_high_value;
5449 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
5451 destkeylow = fx->ddckDestColorkey.color_space_low_value;
5452 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
5455 if (bpp == 1)
5457 keymask = 0xff;
5459 else
5461 DWORD masks[3];
5462 get_color_masks(src_format, masks);
5463 keymask = masks[0]
5464 | masks[1]
5465 | masks[2];
5467 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
5470 if (flags & WINEDDBLT_DDFX)
5472 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
5473 LONG tmpxy;
5474 dTopLeft = dbuf;
5475 dTopRight = dbuf + ((dstwidth - 1) * bpp);
5476 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
5477 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
5479 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
5481 /* I don't think we need to do anything about this flag */
5482 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
5484 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
5486 tmp = dTopRight;
5487 dTopRight = dTopLeft;
5488 dTopLeft = tmp;
5489 tmp = dBottomRight;
5490 dBottomRight = dBottomLeft;
5491 dBottomLeft = tmp;
5492 dstxinc = dstxinc * -1;
5494 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
5496 tmp = dTopLeft;
5497 dTopLeft = dBottomLeft;
5498 dBottomLeft = tmp;
5499 tmp = dTopRight;
5500 dTopRight = dBottomRight;
5501 dBottomRight = tmp;
5502 dstyinc = dstyinc * -1;
5504 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
5506 /* I don't think we need to do anything about this flag */
5507 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
5509 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
5511 tmp = dBottomRight;
5512 dBottomRight = dTopLeft;
5513 dTopLeft = tmp;
5514 tmp = dBottomLeft;
5515 dBottomLeft = dTopRight;
5516 dTopRight = tmp;
5517 dstxinc = dstxinc * -1;
5518 dstyinc = dstyinc * -1;
5520 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
5522 tmp = dTopLeft;
5523 dTopLeft = dBottomLeft;
5524 dBottomLeft = dBottomRight;
5525 dBottomRight = dTopRight;
5526 dTopRight = tmp;
5527 tmpxy = dstxinc;
5528 dstxinc = dstyinc;
5529 dstyinc = tmpxy;
5530 dstxinc = dstxinc * -1;
5532 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
5534 tmp = dTopLeft;
5535 dTopLeft = dTopRight;
5536 dTopRight = dBottomRight;
5537 dBottomRight = dBottomLeft;
5538 dBottomLeft = tmp;
5539 tmpxy = dstxinc;
5540 dstxinc = dstyinc;
5541 dstyinc = tmpxy;
5542 dstyinc = dstyinc * -1;
5544 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
5546 /* I don't think we need to do anything about this flag */
5547 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
5549 dbuf = dTopLeft;
5550 flags &= ~(WINEDDBLT_DDFX);
5553 #define COPY_COLORKEY_FX(type) \
5554 do { \
5555 const type *s; \
5556 type *d = (type *)dbuf, *dx, tmp; \
5557 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5559 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5560 dx = d; \
5561 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5563 tmp = s[sx >> 16]; \
5564 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5565 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5567 dx[0] = tmp; \
5569 dx = (type *)(((BYTE *)dx) + dstxinc); \
5571 d = (type *)(((BYTE *)d) + dstyinc); \
5573 } while(0)
5575 switch (bpp)
5577 case 1:
5578 COPY_COLORKEY_FX(BYTE);
5579 break;
5580 case 2:
5581 COPY_COLORKEY_FX(WORD);
5582 break;
5583 case 4:
5584 COPY_COLORKEY_FX(DWORD);
5585 break;
5586 case 3:
5588 const BYTE *s;
5589 BYTE *d = dbuf, *dx;
5590 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
5592 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
5593 dx = d;
5594 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
5596 DWORD pixel, dpixel = 0;
5597 s = sbuf + 3 * (sx>>16);
5598 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
5599 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
5600 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
5601 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
5603 dx[0] = (pixel ) & 0xff;
5604 dx[1] = (pixel >> 8) & 0xff;
5605 dx[2] = (pixel >> 16) & 0xff;
5607 dx += dstxinc;
5609 d += dstyinc;
5611 break;
5613 default:
5614 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5615 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
5616 hr = WINED3DERR_NOTAVAILABLE;
5617 goto error;
5618 #undef COPY_COLORKEY_FX
5623 error:
5624 if (flags && FIXME_ON(d3d_surface))
5626 FIXME("\tUnsupported flags: %#x.\n", flags);
5629 release:
5630 wined3d_surface_unmap(dst_surface);
5631 if (src_surface && src_surface != dst_surface)
5632 wined3d_surface_unmap(src_surface);
5633 /* Release the converted surface, if any. */
5634 if (src_texture)
5635 wined3d_texture_decref(src_texture);
5637 return hr;
5640 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
5641 const RECT *dst_rect, const struct wined3d_color *color)
5643 static const RECT src_rect;
5644 WINEDDBLTFX BltFx;
5646 memset(&BltFx, 0, sizeof(BltFx));
5647 BltFx.dwSize = sizeof(BltFx);
5648 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
5649 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
5650 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
5653 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
5654 struct wined3d_surface *surface, const RECT *rect, float depth)
5656 FIXME("Depth filling not implemented by cpu_blit.\n");
5657 return WINED3DERR_INVALIDCALL;
5660 const struct blit_shader cpu_blit = {
5661 cpu_blit_alloc,
5662 cpu_blit_free,
5663 cpu_blit_set,
5664 cpu_blit_unset,
5665 cpu_blit_supported,
5666 cpu_blit_color_fill,
5667 cpu_blit_depth_fill,
5670 HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
5671 struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
5672 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
5674 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
5675 struct wined3d_device *device = dst_surface->resource.device;
5676 DWORD src_ds_flags, dst_ds_flags;
5677 RECT src_rect, dst_rect;
5678 BOOL scale, convert;
5679 enum wined3d_conversion_type dst_convert_type;
5680 struct wined3d_format dst_conv_fmt;
5682 static const DWORD simple_blit = WINEDDBLT_ASYNC
5683 | WINEDDBLT_COLORFILL
5684 | WINEDDBLT_WAIT
5685 | WINEDDBLT_DEPTHFILL
5686 | WINEDDBLT_DONOTWAIT;
5688 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5689 dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
5690 flags, fx, debug_d3dtexturefiltertype(filter));
5691 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
5693 if (fx)
5695 TRACE("dwSize %#x.\n", fx->dwSize);
5696 TRACE("dwDDFX %#x.\n", fx->dwDDFX);
5697 TRACE("dwROP %#x.\n", fx->dwROP);
5698 TRACE("dwDDROP %#x.\n", fx->dwDDROP);
5699 TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle);
5700 TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode);
5701 TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow);
5702 TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh);
5703 TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest);
5704 TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth);
5705 TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest);
5706 TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth);
5707 TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc);
5708 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth);
5709 TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend);
5710 TRACE("dwReserved %#x.\n", fx->dwReserved);
5711 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth);
5712 TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest);
5713 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth);
5714 TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc);
5715 TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern);
5716 TRACE("ddckDestColorkey {%#x, %#x}.\n",
5717 fx->ddckDestColorkey.color_space_low_value,
5718 fx->ddckDestColorkey.color_space_high_value);
5719 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
5720 fx->ddckSrcColorkey.color_space_low_value,
5721 fx->ddckSrcColorkey.color_space_high_value);
5724 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
5726 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5727 return WINEDDERR_SURFACEBUSY;
5730 surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
5732 if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom
5733 || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0
5734 || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0
5735 || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0
5736 || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0)
5738 WARN("The application gave us a bad destination rectangle.\n");
5739 return WINEDDERR_INVALIDRECT;
5742 if (src_surface)
5744 surface_get_rect(src_surface, src_rect_in, &src_rect);
5746 if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom
5747 || src_rect.left > src_surface->resource.width || src_rect.left < 0
5748 || src_rect.top > src_surface->resource.height || src_rect.top < 0
5749 || src_rect.right > src_surface->resource.width || src_rect.right < 0
5750 || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0)
5752 WARN("Application gave us bad source rectangle for Blt.\n");
5753 return WINEDDERR_INVALIDRECT;
5756 else
5758 memset(&src_rect, 0, sizeof(src_rect));
5761 if (!fx || !(fx->dwDDFX))
5762 flags &= ~WINEDDBLT_DDFX;
5764 if (flags & WINEDDBLT_WAIT)
5765 flags &= ~WINEDDBLT_WAIT;
5767 if (flags & WINEDDBLT_ASYNC)
5769 static unsigned int once;
5771 if (!once++)
5772 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
5773 flags &= ~WINEDDBLT_ASYNC;
5776 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
5777 if (flags & WINEDDBLT_DONOTWAIT)
5779 static unsigned int once;
5781 if (!once++)
5782 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
5783 flags &= ~WINEDDBLT_DONOTWAIT;
5786 if (!device->d3d_initialized)
5788 WARN("D3D not initialized, using fallback.\n");
5789 goto cpu;
5792 /* We want to avoid invalidating the sysmem location for converted
5793 * surfaces, since otherwise we'd have to convert the data back when
5794 * locking them. */
5795 d3dfmt_get_conv(dst_surface, TRUE, TRUE, &dst_conv_fmt, &dst_convert_type);
5796 if (dst_convert_type != WINED3D_CT_NONE || dst_conv_fmt.convert || dst_surface->flags & SFLAG_CONVERTED)
5798 WARN_(d3d_perf)("Converted surface, using CPU blit.\n");
5799 goto cpu;
5802 if (flags & ~simple_blit)
5804 WARN_(d3d_perf)("Using fallback for complex blit (%#x).\n", flags);
5805 goto fallback;
5808 if (src_surface)
5809 src_swapchain = src_surface->swapchain;
5810 else
5811 src_swapchain = NULL;
5813 dst_swapchain = dst_surface->swapchain;
5815 /* This isn't strictly needed. FBO blits for example could deal with
5816 * cross-swapchain blits by first downloading the source to a texture
5817 * before switching to the destination context. We just have this here to
5818 * not have to deal with the issue, since cross-swapchain blits should be
5819 * rare. */
5820 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
5822 FIXME("Using fallback for cross-swapchain blit.\n");
5823 goto fallback;
5826 scale = src_surface
5827 && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
5828 || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top);
5829 convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
5831 dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
5832 if (src_surface)
5833 src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
5834 else
5835 src_ds_flags = 0;
5837 if (src_ds_flags || dst_ds_flags)
5839 if (flags & WINEDDBLT_DEPTHFILL)
5841 float depth;
5843 TRACE("Depth fill.\n");
5845 if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
5846 return WINED3DERR_INVALIDCALL;
5848 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth)))
5849 return WINED3D_OK;
5851 else
5853 if (src_ds_flags != dst_ds_flags)
5855 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
5856 return WINED3DERR_INVALIDCALL;
5859 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_surface->draw_binding, &src_rect,
5860 dst_surface, dst_surface->draw_binding, &dst_rect)))
5861 return WINED3D_OK;
5864 else
5866 /* In principle this would apply to depth blits as well, but we don't
5867 * implement those in the CPU blitter at the moment. */
5868 if ((dst_surface->locations & dst_surface->map_binding)
5869 && (!src_surface || (src_surface->locations & src_surface->map_binding)))
5871 if (scale)
5872 TRACE("Not doing sysmem blit because of scaling.\n");
5873 else if (convert)
5874 TRACE("Not doing sysmem blit because of format conversion.\n");
5875 else
5876 goto cpu;
5879 if (flags & WINEDDBLT_COLORFILL)
5881 struct wined3d_color color;
5883 TRACE("Color fill.\n");
5885 if (!surface_convert_color_to_float(dst_surface, fx->u5.dwFillColor, &color))
5886 goto fallback;
5888 if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
5889 return WINED3D_OK;
5891 else
5893 TRACE("Color blit.\n");
5895 /* Upload */
5896 if ((src_surface->locations & WINED3D_LOCATION_SYSMEM)
5897 && !(dst_surface->locations & WINED3D_LOCATION_SYSMEM))
5899 if (scale)
5900 TRACE("Not doing upload because of scaling.\n");
5901 else if (convert)
5902 TRACE("Not doing upload because of format conversion.\n");
5903 else
5905 POINT dst_point = {dst_rect.left, dst_rect.top};
5907 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect)))
5909 if (!surface_is_offscreen(dst_surface))
5910 surface_load_location(dst_surface, dst_surface->draw_binding);
5911 return WINED3D_OK;
5916 /* Use present for back -> front blits. The idea behind this is
5917 * that present is potentially faster than a blit, in particular
5918 * when FBO blits aren't available. Some ddraw applications like
5919 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
5920 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
5921 * applications can't blit directly to the frontbuffer. */
5922 if (dst_swapchain && dst_swapchain->back_buffers
5923 && dst_surface == dst_swapchain->front_buffer
5924 && src_surface == dst_swapchain->back_buffers[0])
5926 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
5928 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
5930 /* Set the swap effect to COPY, we don't want the backbuffer
5931 * to become undefined. */
5932 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
5933 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
5934 dst_swapchain->desc.swap_effect = swap_effect;
5936 return WINED3D_OK;
5939 if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5940 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5941 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5943 TRACE("Using FBO blit.\n");
5945 surface_blt_fbo(device, filter,
5946 src_surface, src_surface->draw_binding, &src_rect,
5947 dst_surface, dst_surface->draw_binding, &dst_rect);
5948 surface_validate_location(dst_surface, dst_surface->draw_binding);
5949 surface_invalidate_location(dst_surface, ~dst_surface->draw_binding);
5951 return WINED3D_OK;
5954 if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5955 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5956 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5958 TRACE("Using arbfp blit.\n");
5960 if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
5961 return WINED3D_OK;
5966 fallback:
5967 /* Special cases for render targets. */
5968 if (SUCCEEDED(surface_blt_special(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter)))
5969 return WINED3D_OK;
5971 cpu:
5973 /* For the rest call the X11 surface implementation. For render targets
5974 * this should be implemented OpenGL accelerated in surface_blt_special(),
5975 * other blits are rather rare. */
5976 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
5979 static HRESULT surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
5980 const struct wined3d_resource_desc *desc, GLenum target, GLint level, DWORD flags)
5982 struct wined3d_device *device = container->resource.device;
5983 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5984 const struct wined3d_format *format = wined3d_get_format(gl_info, desc->format);
5985 UINT multisample_quality = desc->multisample_quality;
5986 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
5987 unsigned int resource_size;
5988 HRESULT hr;
5990 if (multisample_quality > 0)
5992 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
5993 multisample_quality = 0;
5996 /* Quick lockable sanity check.
5997 * TODO: remove this after surfaces, usage and lockability have been debugged properly
5998 * this function is too deep to need to care about things like this.
5999 * Levels need to be checked too, since they all affect what can be done. */
6000 switch (desc->pool)
6002 case WINED3D_POOL_MANAGED:
6003 if (desc->usage & WINED3DUSAGE_DYNAMIC)
6004 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
6005 break;
6007 case WINED3D_POOL_DEFAULT:
6008 if (lockable && !(desc->usage & (WINED3DUSAGE_DYNAMIC
6009 | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
6010 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
6011 break;
6013 case WINED3D_POOL_SCRATCH:
6014 case WINED3D_POOL_SYSTEM_MEM:
6015 break;
6017 default:
6018 FIXME("Unknown pool %#x.\n", desc->pool);
6019 break;
6022 if (desc->usage & WINED3DUSAGE_RENDERTARGET && desc->pool != WINED3D_POOL_DEFAULT)
6023 FIXME("Trying to create a render target that isn't in the default pool.\n");
6025 /* FIXME: Check that the format is supported by the device. */
6027 resource_size = wined3d_format_calculate_size(format, device->surface_alignment, desc->width, desc->height, 1);
6028 if (!resource_size)
6029 return WINED3DERR_INVALIDCALL;
6031 if (device->wined3d->flags & WINED3D_NO3D)
6032 surface->surface_ops = &gdi_surface_ops;
6033 else
6034 surface->surface_ops = &surface_ops;
6036 if (FAILED(hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
6037 desc->multisample_type, multisample_quality, desc->usage, desc->pool, desc->width, desc->height, 1,
6038 resource_size, NULL, &wined3d_null_parent_ops, &surface_resource_ops)))
6040 WARN("Failed to initialize resource, returning %#x.\n", hr);
6041 return hr;
6044 surface_set_container(surface, container);
6045 surface_validate_location(surface, WINED3D_LOCATION_SYSMEM);
6046 list_init(&surface->renderbuffers);
6047 list_init(&surface->overlays);
6049 /* Flags */
6050 if (target != GL_TEXTURE_RECTANGLE_ARB)
6051 surface->flags |= SFLAG_NORMCOORD;
6052 if (flags & WINED3D_SURFACE_DISCARD)
6053 surface->flags |= SFLAG_DISCARD;
6054 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
6055 surface->flags |= SFLAG_PIN_SYSMEM;
6056 if (lockable || desc->format == WINED3DFMT_D16_LOCKABLE)
6057 surface->resource.access_flags |= WINED3D_RESOURCE_ACCESS_CPU;
6059 surface->map_binding = WINED3D_LOCATION_SYSMEM;
6060 surface->texture_target = target;
6061 surface->texture_level = level;
6063 /* Call the private setup routine */
6064 hr = surface->surface_ops->surface_private_setup(surface);
6065 if (FAILED(hr))
6067 ERR("Private setup failed, returning %#x\n", hr);
6068 surface_set_container(surface, NULL);
6069 surface_cleanup(surface);
6070 return hr;
6073 /* Similar to lockable rendertargets above, creating the DIB section
6074 * during surface initialization prevents the sysmem pointer from changing
6075 * after a wined3d_surface_getdc() call. */
6076 if ((desc->usage & WINED3DUSAGE_OWNDC) && !surface->hDC
6077 && SUCCEEDED(surface_create_dib_section(surface)))
6078 surface->map_binding = WINED3D_LOCATION_DIB;
6080 if (surface->map_binding == WINED3D_LOCATION_DIB)
6082 wined3d_resource_free_sysmem(&surface->resource);
6083 surface_validate_location(surface, WINED3D_LOCATION_DIB);
6084 surface_invalidate_location(surface, WINED3D_LOCATION_SYSMEM);
6087 return hr;
6090 HRESULT wined3d_surface_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc,
6091 GLenum target, GLint level, DWORD flags, struct wined3d_surface **surface)
6093 struct wined3d_device_parent *device_parent = container->resource.device->device_parent;
6094 const struct wined3d_parent_ops *parent_ops;
6095 struct wined3d_surface *object;
6096 void *parent;
6097 HRESULT hr;
6099 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
6100 "multisample_type %#x, multisample_quality %u, target %#x, level %d, flags %#x, surface %p.\n",
6101 container, desc->width, desc->height, debug_d3dformat(desc->format),
6102 debug_d3dusage(desc->usage), desc->usage, debug_d3dpool(desc->pool),
6103 desc->multisample_type, desc->multisample_quality, target, level, flags, surface);
6105 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
6106 return E_OUTOFMEMORY;
6108 if (FAILED(hr = surface_init(object, container, desc, target, level, flags)))
6110 WARN("Failed to initialize surface, returning %#x.\n", hr);
6111 HeapFree(GetProcessHeap(), 0, object);
6112 return hr;
6115 if (FAILED(hr = device_parent->ops->surface_created(device_parent,
6116 wined3d_texture_get_parent(container), object, &parent, &parent_ops)))
6118 WARN("Failed to create surface parent, hr %#x.\n", hr);
6119 surface_set_container(object, NULL);
6120 wined3d_surface_decref(object);
6121 return hr;
6124 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object, parent, parent_ops);
6126 object->resource.parent = parent;
6127 object->resource.parent_ops = parent_ops;
6128 *surface = object;
6130 return hr;