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 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
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d);
36 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
37 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
38 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter);
39 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
40 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *fx,
41 enum wined3d_texture_filter_type filter);
43 static void surface_cleanup(struct wined3d_surface *surface)
45 struct wined3d_surface *overlay, *cur;
47 TRACE("surface %p.\n", surface);
49 if (surface->texture_name || (surface->flags & SFLAG_PBO)
50 || surface->rb_multisample || surface->rb_resolved
51 || !list_empty(&surface->renderbuffers))
53 struct wined3d_renderbuffer_entry *entry, *entry2;
54 const struct wined3d_gl_info *gl_info;
55 struct wined3d_context *context;
57 context = context_acquire(surface->resource.device, NULL);
58 gl_info = context->gl_info;
62 if (surface->texture_name)
64 TRACE("Deleting texture %u.\n", surface->texture_name);
65 glDeleteTextures(1, &surface->texture_name);
68 if (surface->flags & SFLAG_PBO)
70 TRACE("Deleting PBO %u.\n", surface->pbo);
71 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
74 if (surface->rb_multisample)
76 TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
77 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
80 if (surface->rb_resolved)
82 TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved);
83 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
86 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
88 TRACE("Deleting renderbuffer %u.\n", entry->id);
89 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
90 HeapFree(GetProcessHeap(), 0, entry);
95 context_release(context);
98 if (surface->flags & SFLAG_DIBSECTION)
100 DeleteDC(surface->hDC);
101 DeleteObject(surface->dib.DIBsection);
102 surface->dib.bitmap_data = NULL;
103 surface->resource.allocatedMemory = NULL;
106 if (surface->flags & SFLAG_USERPTR)
107 wined3d_surface_set_mem(surface, NULL);
108 if (surface->overlay_dest)
109 list_remove(&surface->overlay_entry);
111 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry)
113 list_remove(&overlay->overlay_entry);
114 overlay->overlay_dest = NULL;
117 resource_cleanup(&surface->resource);
120 void surface_update_draw_binding(struct wined3d_surface *surface)
122 if (!surface_is_offscreen(surface) || wined3d_settings.offscreen_rendering_mode != ORM_FBO)
123 surface->draw_binding = SFLAG_INDRAWABLE;
124 else if (surface->resource.multisample_type)
125 surface->draw_binding = SFLAG_INRB_MULTISAMPLE;
127 surface->draw_binding = SFLAG_INTEXTURE;
130 void surface_set_container(struct wined3d_surface *surface, enum wined3d_container_type type, void *container)
132 TRACE("surface %p, container %p.\n", surface, container);
134 if (!container && type != WINED3D_CONTAINER_NONE)
135 ERR("Setting NULL container of type %#x.\n", type);
137 if (type == WINED3D_CONTAINER_SWAPCHAIN)
139 surface->get_drawable_size = get_drawable_size_swapchain;
143 switch (wined3d_settings.offscreen_rendering_mode)
146 surface->get_drawable_size = get_drawable_size_fbo;
150 surface->get_drawable_size = get_drawable_size_backbuffer;
154 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
159 surface->container.type = type;
160 surface->container.u.base = container;
161 surface_update_draw_binding(surface);
168 enum tex_types tex_type;
169 GLfloat coords[4][3];
180 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
182 f->l = ((r->left * 2.0f) / w) - 1.0f;
183 f->t = ((r->top * 2.0f) / h) - 1.0f;
184 f->r = ((r->right * 2.0f) / w) - 1.0f;
185 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
188 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
190 GLfloat (*coords)[3] = info->coords;
196 FIXME("Unsupported texture target %#x\n", target);
197 /* Fall back to GL_TEXTURE_2D */
199 info->binding = GL_TEXTURE_BINDING_2D;
200 info->bind_target = GL_TEXTURE_2D;
201 info->tex_type = tex_2d;
202 coords[0][0] = (float)rect->left / w;
203 coords[0][1] = (float)rect->top / h;
206 coords[1][0] = (float)rect->right / w;
207 coords[1][1] = (float)rect->top / h;
210 coords[2][0] = (float)rect->left / w;
211 coords[2][1] = (float)rect->bottom / h;
214 coords[3][0] = (float)rect->right / w;
215 coords[3][1] = (float)rect->bottom / h;
219 case GL_TEXTURE_RECTANGLE_ARB:
220 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
221 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
222 info->tex_type = tex_rect;
223 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
224 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
225 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
226 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
229 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
230 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
231 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
232 info->tex_type = tex_cube;
233 cube_coords_float(rect, w, h, &f);
235 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
236 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
237 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
238 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
241 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
242 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
243 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
244 info->tex_type = tex_cube;
245 cube_coords_float(rect, w, h, &f);
247 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
248 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
249 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
250 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
253 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
254 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
255 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
256 info->tex_type = tex_cube;
257 cube_coords_float(rect, w, h, &f);
259 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
260 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
261 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
262 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
265 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
266 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
267 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
268 info->tex_type = tex_cube;
269 cube_coords_float(rect, w, h, &f);
271 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
272 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
273 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
274 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
277 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
278 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
279 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
280 info->tex_type = tex_cube;
281 cube_coords_float(rect, w, h, &f);
283 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
284 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
285 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
286 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
289 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
290 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
291 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
292 info->tex_type = tex_cube;
293 cube_coords_float(rect, w, h, &f);
295 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
296 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
297 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
298 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
303 static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
306 *rect_out = *rect_in;
311 rect_out->right = surface->resource.width;
312 rect_out->bottom = surface->resource.height;
316 /* GL locking and context activation is done by the caller */
317 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
318 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
320 struct blt_info info;
322 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
324 glEnable(info.bind_target);
325 checkGLcall("glEnable(bind_target)");
327 context_bind_texture(context, info.bind_target, src_surface->texture_name);
329 /* Filtering for StretchRect */
330 glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
331 wined3d_gl_mag_filter(magLookup, filter));
332 checkGLcall("glTexParameteri");
333 glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
334 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
335 checkGLcall("glTexParameteri");
336 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
337 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
338 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
339 glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
340 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
341 checkGLcall("glTexEnvi");
344 glBegin(GL_TRIANGLE_STRIP);
345 glTexCoord3fv(info.coords[0]);
346 glVertex2i(dst_rect->left, dst_rect->top);
348 glTexCoord3fv(info.coords[1]);
349 glVertex2i(dst_rect->right, dst_rect->top);
351 glTexCoord3fv(info.coords[2]);
352 glVertex2i(dst_rect->left, dst_rect->bottom);
354 glTexCoord3fv(info.coords[3]);
355 glVertex2i(dst_rect->right, dst_rect->bottom);
358 /* Unbind the texture */
359 context_bind_texture(context, info.bind_target, 0);
361 /* We changed the filtering settings on the texture. Inform the
362 * container about this to get the filters reset properly next draw. */
363 if (src_surface->container.type == WINED3D_CONTAINER_TEXTURE)
365 struct wined3d_texture *texture = src_surface->container.u.texture;
366 texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT;
367 texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT;
368 texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE;
369 texture->texture_rgb.states[WINED3DTEXSTA_SRGBTEXTURE] = FALSE;
373 static HRESULT surface_create_dib_section(struct wined3d_surface *surface)
375 const struct wined3d_format *format = surface->resource.format;
381 TRACE("surface %p.\n", surface);
383 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
385 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
386 return WINED3DERR_INVALIDCALL;
389 switch (format->byte_count)
393 /* Allocate extra space to store the RGB bit masks. */
394 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
398 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
402 /* Allocate extra space for a palette. */
403 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
404 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
409 return E_OUTOFMEMORY;
411 /* Some applications access the surface in via DWORDs, and do not take
412 * the necessary care at the end of the surface. So we need at least
413 * 4 extra bytes at the end of the surface. Check against the page size,
414 * if the last page used for the surface has at least 4 spare bytes we're
415 * safe, otherwise add an extra line to the DIB section. */
416 GetSystemInfo(&sysInfo);
417 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
420 TRACE("Adding an extra line to the DIB section.\n");
423 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
424 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
425 b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count;
426 b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
427 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
428 * wined3d_surface_get_pitch(surface);
429 b_info->bmiHeader.biPlanes = 1;
430 b_info->bmiHeader.biBitCount = format->byte_count * 8;
432 b_info->bmiHeader.biXPelsPerMeter = 0;
433 b_info->bmiHeader.biYPelsPerMeter = 0;
434 b_info->bmiHeader.biClrUsed = 0;
435 b_info->bmiHeader.biClrImportant = 0;
437 /* Get the bit masks */
438 masks = (DWORD *)b_info->bmiColors;
439 switch (surface->resource.format->id)
441 case WINED3DFMT_B8G8R8_UNORM:
442 b_info->bmiHeader.biCompression = BI_RGB;
445 case WINED3DFMT_B5G5R5X1_UNORM:
446 case WINED3DFMT_B5G5R5A1_UNORM:
447 case WINED3DFMT_B4G4R4A4_UNORM:
448 case WINED3DFMT_B4G4R4X4_UNORM:
449 case WINED3DFMT_B2G3R3_UNORM:
450 case WINED3DFMT_B2G3R3A8_UNORM:
451 case WINED3DFMT_R10G10B10A2_UNORM:
452 case WINED3DFMT_R8G8B8A8_UNORM:
453 case WINED3DFMT_R8G8B8X8_UNORM:
454 case WINED3DFMT_B10G10R10A2_UNORM:
455 case WINED3DFMT_B5G6R5_UNORM:
456 case WINED3DFMT_R16G16B16A16_UNORM:
457 b_info->bmiHeader.biCompression = BI_BITFIELDS;
458 masks[0] = format->red_mask;
459 masks[1] = format->green_mask;
460 masks[2] = format->blue_mask;
464 /* Don't know palette */
465 b_info->bmiHeader.biCompression = BI_RGB;
469 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
470 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
471 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
472 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
474 if (!surface->dib.DIBsection)
476 ERR("Failed to create DIB section.\n");
477 HeapFree(GetProcessHeap(), 0, b_info);
478 return HRESULT_FROM_WIN32(GetLastError());
481 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
482 /* Copy the existing surface to the dib section. */
483 if (surface->resource.allocatedMemory)
485 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
486 surface->resource.height * wined3d_surface_get_pitch(surface));
490 /* This is to make maps read the GL texture although memory is allocated. */
491 surface->flags &= ~SFLAG_INSYSMEM;
493 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
495 HeapFree(GetProcessHeap(), 0, b_info);
497 /* Now allocate a DC. */
498 surface->hDC = CreateCompatibleDC(0);
499 SelectObject(surface->hDC, surface->dib.DIBsection);
500 TRACE("Using wined3d palette %p.\n", surface->palette);
501 SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
503 surface->flags |= SFLAG_DIBSECTION;
508 static BOOL surface_need_pbo(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
510 if (surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
512 if (!(surface->flags & SFLAG_DYNLOCK))
514 if (surface->flags & (SFLAG_CONVERTED | SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM))
516 if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT])
522 static void surface_load_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
524 struct wined3d_context *context;
527 context = context_acquire(surface->resource.device, NULL);
530 GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
531 error = glGetError();
532 if (!surface->pbo || error != GL_NO_ERROR)
533 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
535 TRACE("Binding PBO %u.\n", surface->pbo);
537 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
538 checkGLcall("glBindBufferARB");
540 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
541 surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
542 checkGLcall("glBufferDataARB");
544 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
545 checkGLcall("glBindBufferARB");
547 /* We don't need the system memory anymore and we can't even use it for PBOs. */
548 if (!(surface->flags & SFLAG_CLIENT))
550 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
551 surface->resource.heapMemory = NULL;
553 surface->resource.allocatedMemory = NULL;
554 surface->flags |= SFLAG_PBO;
556 context_release(context);
559 static void surface_prepare_system_memory(struct wined3d_surface *surface)
561 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
563 TRACE("surface %p.\n", surface);
565 if (!(surface->flags & SFLAG_PBO) && surface_need_pbo(surface, gl_info))
566 surface_load_pbo(surface, gl_info);
567 else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO))
569 /* Whatever surface we have, make sure that there is memory allocated
570 * for the downloaded copy, or a PBO to map. */
571 if (!surface->resource.heapMemory)
572 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
574 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
575 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
577 if (surface->flags & SFLAG_INSYSMEM)
578 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
582 static void surface_evict_sysmem(struct wined3d_surface *surface)
584 if (surface->resource.map_count || (surface->flags & SFLAG_DONOTFREE))
587 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
588 surface->resource.allocatedMemory = NULL;
589 surface->resource.heapMemory = NULL;
590 surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
593 /* Context activation is done by the caller. */
594 static void surface_bind(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
596 TRACE("surface %p, context %p, srgb %#x.\n", surface, context, srgb);
598 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
600 struct wined3d_texture *texture = surface->container.u.texture;
602 TRACE("Passing to container (%p).\n", texture);
603 texture->texture_ops->texture_bind(texture, context, srgb);
607 if (surface->texture_level)
609 ERR("Standalone surface %p is non-zero texture level %u.\n",
610 surface, surface->texture_level);
614 ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
618 if (!surface->texture_name)
620 glGenTextures(1, &surface->texture_name);
621 checkGLcall("glGenTextures");
623 TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
625 context_bind_texture(context, surface->texture_target, surface->texture_name);
626 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
627 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
628 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
629 glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
630 glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
631 checkGLcall("glTexParameteri");
635 context_bind_texture(context, surface->texture_target, surface->texture_name);
642 /* Context activation is done by the caller. */
643 static void surface_bind_and_dirtify(struct wined3d_surface *surface,
644 struct wined3d_context *context, BOOL srgb)
646 struct wined3d_device *device = surface->resource.device;
647 DWORD active_sampler;
649 /* We don't need a specific texture unit, but after binding the texture
650 * the current unit is dirty. Read the unit back instead of switching to
651 * 0, this avoids messing around with the state manager's GL states. The
652 * current texture unit should always be a valid one.
654 * To be more specific, this is tricky because we can implicitly be
655 * called from sampler() in state.c. This means we can't touch anything
656 * other than whatever happens to be the currently active texture, or we
657 * would risk marking already applied sampler states dirty again. */
658 active_sampler = device->rev_tex_unit_map[context->active_texture];
660 if (active_sampler != WINED3D_UNMAPPED_STAGE)
661 device_invalidate_state(device, STATE_SAMPLER(active_sampler));
662 surface_bind(surface, context, srgb);
665 static void surface_force_reload(struct wined3d_surface *surface)
667 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
670 static void surface_release_client_storage(struct wined3d_surface *surface)
672 struct wined3d_context *context = context_acquire(surface->resource.device, NULL);
675 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
676 if (surface->texture_name)
678 surface_bind_and_dirtify(surface, context, FALSE);
679 glTexImage2D(surface->texture_target, surface->texture_level,
680 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
682 if (surface->texture_name_srgb)
684 surface_bind_and_dirtify(surface, context, TRUE);
685 glTexImage2D(surface->texture_target, surface->texture_level,
686 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
688 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
691 context_release(context);
693 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
694 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
695 surface_force_reload(surface);
698 static HRESULT surface_private_setup(struct wined3d_surface *surface)
700 /* TODO: Check against the maximum texture sizes supported by the video card. */
701 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
702 unsigned int pow2Width, pow2Height;
704 TRACE("surface %p.\n", surface);
706 surface->texture_name = 0;
707 surface->texture_target = GL_TEXTURE_2D;
709 /* Non-power2 support */
710 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
712 pow2Width = surface->resource.width;
713 pow2Height = surface->resource.height;
717 /* Find the nearest pow2 match */
718 pow2Width = pow2Height = 1;
719 while (pow2Width < surface->resource.width)
721 while (pow2Height < surface->resource.height)
724 surface->pow2Width = pow2Width;
725 surface->pow2Height = pow2Height;
727 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
729 /* TODO: Add support for non power two compressed textures. */
730 if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
732 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
733 surface, surface->resource.width, surface->resource.height);
734 return WINED3DERR_NOTAVAILABLE;
738 if (pow2Width != surface->resource.width
739 || pow2Height != surface->resource.height)
741 surface->flags |= SFLAG_NONPOW2;
744 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
745 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
747 /* One of three options:
748 * 1: Do the same as we do with NPOT and scale the texture, (any
749 * texture ops would require the texture to be scaled which is
751 * 2: Set the texture to the maximum size (bad idea).
752 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
753 * 4: Create the surface, but allow it to be used only for DirectDraw
754 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
755 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
756 * the render target. */
757 if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED)
759 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
760 return WINED3DERR_NOTAVAILABLE;
763 /* We should never use this surface in combination with OpenGL! */
764 TRACE("Creating an oversized surface: %ux%u.\n",
765 surface->pow2Width, surface->pow2Height);
769 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
770 * and EXT_PALETTED_TEXTURE is used in combination with texture
771 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
772 * EXT_PALETTED_TEXTURE doesn't work in combination with
773 * ARB_TEXTURE_RECTANGLE. */
774 if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
775 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
776 && gl_info->supported[EXT_PALETTED_TEXTURE]
777 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
779 surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
780 surface->pow2Width = surface->resource.width;
781 surface->pow2Height = surface->resource.height;
782 surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
786 switch (wined3d_settings.offscreen_rendering_mode)
789 surface->get_drawable_size = get_drawable_size_fbo;
793 surface->get_drawable_size = get_drawable_size_backbuffer;
797 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
798 return WINED3DERR_INVALIDCALL;
801 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
802 surface->flags |= SFLAG_DISCARDED;
807 static void surface_realize_palette(struct wined3d_surface *surface)
809 struct wined3d_palette *palette = surface->palette;
811 TRACE("surface %p.\n", surface);
813 if (!palette) return;
815 if (surface->resource.format->id == WINED3DFMT_P8_UINT
816 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
818 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
820 /* Make sure the texture is up to date. This call doesn't do
821 * anything if the texture is already up to date. */
822 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
824 /* We want to force a palette refresh, so mark the drawable as not being up to date */
825 if (!surface_is_offscreen(surface))
826 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
830 if (!(surface->flags & SFLAG_INSYSMEM))
832 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
833 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
835 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
839 if (surface->flags & SFLAG_DIBSECTION)
844 TRACE("Updating the DC's palette.\n");
846 for (i = 0; i < 256; ++i)
848 col[i].rgbRed = palette->palents[i].peRed;
849 col[i].rgbGreen = palette->palents[i].peGreen;
850 col[i].rgbBlue = palette->palents[i].peBlue;
851 col[i].rgbReserved = 0;
853 SetDIBColorTable(surface->hDC, 0, 256, col);
856 /* Propagate the changes to the drawable when we have a palette. */
857 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
858 surface_load_location(surface, surface->draw_binding, NULL);
861 static HRESULT surface_draw_overlay(struct wined3d_surface *surface)
865 /* If there's no destination surface there is nothing to do. */
866 if (!surface->overlay_dest)
869 /* Blt calls ModifyLocation on the dest surface, which in turn calls
870 * DrawOverlay to update the overlay. Prevent an endless recursion. */
871 if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
874 surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
875 hr = wined3d_surface_blt(surface->overlay_dest, &surface->overlay_destrect, surface,
876 &surface->overlay_srcrect, WINEDDBLT_WAIT, NULL, WINED3D_TEXF_LINEAR);
877 surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
882 static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
884 struct wined3d_device *device = surface->resource.device;
885 const RECT *pass_rect = rect;
887 TRACE("surface %p, rect %s, flags %#x.\n",
888 surface, wine_dbgstr_rect(rect), flags);
890 if (flags & WINED3D_MAP_DISCARD)
892 TRACE("WINED3D_MAP_DISCARD flag passed, marking SYSMEM as up to date.\n");
893 surface_prepare_system_memory(surface);
894 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
898 /* surface_load_location() does not check if the rectangle specifies
899 * the full surface. Most callers don't need that, so do it here. */
900 if (rect && !rect->top && !rect->left
901 && rect->right == surface->resource.width
902 && rect->bottom == surface->resource.height)
904 surface_load_location(surface, SFLAG_INSYSMEM, pass_rect);
907 if (surface->flags & SFLAG_PBO)
909 const struct wined3d_gl_info *gl_info;
910 struct wined3d_context *context;
912 context = context_acquire(device, NULL);
913 gl_info = context->gl_info;
916 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
917 checkGLcall("glBindBufferARB");
919 /* This shouldn't happen but could occur if some other function
920 * didn't handle the PBO properly. */
921 if (surface->resource.allocatedMemory)
922 ERR("The surface already has PBO memory allocated.\n");
924 surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
925 checkGLcall("glMapBufferARB");
927 /* Make sure the PBO isn't set anymore in order not to break non-PBO
929 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
930 checkGLcall("glBindBufferARB");
933 context_release(context);
936 if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
939 surface_add_dirty_rect(surface, NULL);
942 struct wined3d_box b;
946 b.right = rect->right;
947 b.bottom = rect->bottom;
950 surface_add_dirty_rect(surface, &b);
955 static void surface_unmap(struct wined3d_surface *surface)
957 struct wined3d_device *device = surface->resource.device;
960 TRACE("surface %p.\n", surface);
962 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
964 if (surface->flags & SFLAG_PBO)
966 const struct wined3d_gl_info *gl_info;
967 struct wined3d_context *context;
969 TRACE("Freeing PBO memory.\n");
971 context = context_acquire(device, NULL);
972 gl_info = context->gl_info;
975 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
976 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
977 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
978 checkGLcall("glUnmapBufferARB");
980 context_release(context);
982 surface->resource.allocatedMemory = NULL;
985 TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
987 if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
989 TRACE("Not dirtified, nothing to do.\n");
993 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
994 && surface->container.u.swapchain->front_buffer == surface)
996 if (!surface->dirtyRect.left && !surface->dirtyRect.top
997 && surface->dirtyRect.right == surface->resource.width
998 && surface->dirtyRect.bottom == surface->resource.height)
1004 /* TODO: Proper partial rectangle tracking. */
1005 fullsurface = FALSE;
1006 surface->flags |= SFLAG_INSYSMEM;
1009 surface_load_location(surface, surface->draw_binding, fullsurface ? NULL : &surface->dirtyRect);
1011 /* Partial rectangle tracking is not commonly implemented, it is only
1012 * done for render targets. INSYSMEM was set before to tell
1013 * surface_load_location() where to read the rectangle from.
1014 * Indrawable is set because all modifications from the partial
1015 * sysmem copy are written back to the drawable, thus the surface is
1016 * merged again in the drawable. The sysmem copy is not fully up to
1017 * date because only a subrectangle was read in Map(). */
1020 surface_modify_location(surface, surface->draw_binding, TRUE);
1021 surface_evict_sysmem(surface);
1024 surface->dirtyRect.left = surface->resource.width;
1025 surface->dirtyRect.top = surface->resource.height;
1026 surface->dirtyRect.right = 0;
1027 surface->dirtyRect.bottom = 0;
1029 else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1031 FIXME("Depth / stencil buffer locking is not implemented.\n");
1035 /* Overlays have to be redrawn manually after changes with the GL implementation */
1036 if (surface->overlay_dest)
1037 surface_draw_overlay(surface);
1040 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
1042 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
1044 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
1049 static void wined3d_surface_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_surface *src_surface,
1050 const RECT *src_rect, struct wined3d_surface *dst_surface, const RECT *dst_rect)
1052 const struct wined3d_gl_info *gl_info;
1053 struct wined3d_context *context;
1054 DWORD src_mask, dst_mask;
1057 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
1058 device, src_surface, wine_dbgstr_rect(src_rect),
1059 dst_surface, wine_dbgstr_rect(dst_rect));
1061 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1062 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1064 if (src_mask != dst_mask)
1066 ERR("Incompatible formats %s and %s.\n",
1067 debug_d3dformat(src_surface->resource.format->id),
1068 debug_d3dformat(dst_surface->resource.format->id));
1074 ERR("Not a depth / stencil format: %s.\n",
1075 debug_d3dformat(src_surface->resource.format->id));
1080 if (src_mask & WINED3DFMT_FLAG_DEPTH)
1081 gl_mask |= GL_DEPTH_BUFFER_BIT;
1082 if (src_mask & WINED3DFMT_FLAG_STENCIL)
1083 gl_mask |= GL_STENCIL_BUFFER_BIT;
1085 /* Make sure the locations are up-to-date. Loading the destination
1086 * surface isn't required if the entire surface is overwritten. */
1087 surface_load_location(src_surface, SFLAG_INTEXTURE, NULL);
1088 if (!surface_is_full_rect(dst_surface, dst_rect))
1089 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
1091 context = context_acquire(device, NULL);
1092 if (!context->valid)
1094 context_release(context);
1095 WARN("Invalid context, skipping blit.\n");
1099 gl_info = context->gl_info;
1103 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, SFLAG_INTEXTURE);
1104 glReadBuffer(GL_NONE);
1105 checkGLcall("glReadBuffer()");
1106 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1108 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, SFLAG_INTEXTURE);
1109 context_set_draw_buffer(context, GL_NONE);
1110 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1111 context_invalidate_state(context, STATE_FRAMEBUFFER);
1113 if (gl_mask & GL_DEPTH_BUFFER_BIT)
1115 glDepthMask(GL_TRUE);
1116 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
1118 if (gl_mask & GL_STENCIL_BUFFER_BIT)
1120 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
1122 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1123 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
1126 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1129 glDisable(GL_SCISSOR_TEST);
1130 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1132 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
1133 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
1134 checkGLcall("glBlitFramebuffer()");
1138 if (wined3d_settings.strict_draw_ordering)
1139 wglFlush(); /* Flush to ensure ordering across contexts. */
1141 context_release(context);
1144 /* Blit between surface locations. Onscreen on different swapchains is not supported.
1145 * Depth / stencil is not supported. */
1146 static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_texture_filter_type filter,
1147 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
1148 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
1150 const struct wined3d_gl_info *gl_info;
1151 struct wined3d_context *context;
1152 RECT src_rect, dst_rect;
1156 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
1157 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1158 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
1159 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1160 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
1162 src_rect = *src_rect_in;
1163 dst_rect = *dst_rect_in;
1167 case WINED3D_TEXF_LINEAR:
1168 gl_filter = GL_LINEAR;
1172 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
1173 case WINED3D_TEXF_NONE:
1174 case WINED3D_TEXF_POINT:
1175 gl_filter = GL_NEAREST;
1179 /* Resolve the source surface first if needed. */
1180 if (src_location == SFLAG_INRB_MULTISAMPLE
1181 && (src_surface->resource.format->id != dst_surface->resource.format->id
1182 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
1183 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
1184 src_location = SFLAG_INRB_RESOLVED;
1186 /* Make sure the locations are up-to-date. Loading the destination
1187 * surface isn't required if the entire surface is overwritten. (And is
1188 * in fact harmful if we're being called by surface_load_location() with
1189 * the purpose of loading the destination surface.) */
1190 surface_load_location(src_surface, src_location, NULL);
1191 if (!surface_is_full_rect(dst_surface, &dst_rect))
1192 surface_load_location(dst_surface, dst_location, NULL);
1194 if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
1195 else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
1196 else context = context_acquire(device, NULL);
1198 if (!context->valid)
1200 context_release(context);
1201 WARN("Invalid context, skipping blit.\n");
1205 gl_info = context->gl_info;
1207 if (src_location == SFLAG_INDRAWABLE)
1209 TRACE("Source surface %p is onscreen.\n", src_surface);
1210 buffer = surface_get_gl_buffer(src_surface);
1211 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
1215 TRACE("Source surface %p is offscreen.\n", src_surface);
1216 buffer = GL_COLOR_ATTACHMENT0;
1220 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
1221 glReadBuffer(buffer);
1222 checkGLcall("glReadBuffer()");
1223 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1226 if (dst_location == SFLAG_INDRAWABLE)
1228 TRACE("Destination surface %p is onscreen.\n", dst_surface);
1229 buffer = surface_get_gl_buffer(dst_surface);
1230 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
1234 TRACE("Destination surface %p is offscreen.\n", dst_surface);
1235 buffer = GL_COLOR_ATTACHMENT0;
1239 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
1240 context_set_draw_buffer(context, buffer);
1241 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1242 context_invalidate_state(context, STATE_FRAMEBUFFER);
1244 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1245 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
1246 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
1247 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
1248 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
1250 glDisable(GL_SCISSOR_TEST);
1251 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1253 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
1254 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
1255 checkGLcall("glBlitFramebuffer()");
1259 if (wined3d_settings.strict_draw_ordering
1260 || (dst_location == SFLAG_INDRAWABLE
1261 && dst_surface->container.u.swapchain->front_buffer == dst_surface))
1264 context_release(context);
1267 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
1268 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
1269 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
1271 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1274 /* Source and/or destination need to be on the GL side */
1275 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
1280 case WINED3D_BLIT_OP_COLOR_BLIT:
1281 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
1283 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
1287 case WINED3D_BLIT_OP_DEPTH_BLIT:
1288 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1290 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1298 if (!(src_format->id == dst_format->id
1299 || (is_identity_fixup(src_format->color_fixup)
1300 && is_identity_fixup(dst_format->color_fixup))))
1306 /* This function checks if the primary render target uses the 8bit paletted format. */
1307 static BOOL primary_render_target_is_p8(const struct wined3d_device *device)
1309 if (device->fb.render_targets && device->fb.render_targets[0])
1311 const struct wined3d_surface *render_target = device->fb.render_targets[0];
1312 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
1313 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
1319 static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface,
1320 DWORD color, struct wined3d_color *float_color)
1322 const struct wined3d_format *format = surface->resource.format;
1323 const struct wined3d_device *device = surface->resource.device;
1327 case WINED3DFMT_P8_UINT:
1328 if (surface->palette)
1330 float_color->r = surface->palette->palents[color].peRed / 255.0f;
1331 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
1332 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
1336 float_color->r = 0.0f;
1337 float_color->g = 0.0f;
1338 float_color->b = 0.0f;
1340 float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
1343 case WINED3DFMT_B5G6R5_UNORM:
1344 float_color->r = ((color >> 11) & 0x1f) / 31.0f;
1345 float_color->g = ((color >> 5) & 0x3f) / 63.0f;
1346 float_color->b = (color & 0x1f) / 31.0f;
1347 float_color->a = 1.0f;
1350 case WINED3DFMT_B8G8R8_UNORM:
1351 case WINED3DFMT_B8G8R8X8_UNORM:
1352 float_color->r = D3DCOLOR_R(color);
1353 float_color->g = D3DCOLOR_G(color);
1354 float_color->b = D3DCOLOR_B(color);
1355 float_color->a = 1.0f;
1358 case WINED3DFMT_B8G8R8A8_UNORM:
1359 float_color->r = D3DCOLOR_R(color);
1360 float_color->g = D3DCOLOR_G(color);
1361 float_color->b = D3DCOLOR_B(color);
1362 float_color->a = D3DCOLOR_A(color);
1366 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1373 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
1375 const struct wined3d_format *format = surface->resource.format;
1379 case WINED3DFMT_S1_UINT_D15_UNORM:
1380 *float_depth = depth / (float)0x00007fff;
1383 case WINED3DFMT_D16_UNORM:
1384 *float_depth = depth / (float)0x0000ffff;
1387 case WINED3DFMT_D24_UNORM_S8_UINT:
1388 case WINED3DFMT_X8D24_UNORM:
1389 *float_depth = depth / (float)0x00ffffff;
1392 case WINED3DFMT_D32_UNORM:
1393 *float_depth = depth / (float)0xffffffff;
1397 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1404 /* Do not call while under the GL lock. */
1405 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
1407 const struct wined3d_resource *resource = &surface->resource;
1408 struct wined3d_device *device = resource->device;
1409 const struct blit_shader *blitter;
1411 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
1412 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
1415 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1416 return WINED3DERR_INVALIDCALL;
1419 return blitter->depth_fill(device, surface, rect, depth);
1422 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, const RECT *src_rect,
1423 struct wined3d_surface *dst_surface, const RECT *dst_rect)
1425 struct wined3d_device *device = src_surface->resource.device;
1427 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
1428 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1429 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1430 return WINED3DERR_INVALIDCALL;
1432 wined3d_surface_depth_blt_fbo(device, src_surface, src_rect, dst_surface, dst_rect);
1434 surface_modify_ds_location(dst_surface, SFLAG_INTEXTURE,
1435 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
1440 /* Do not call while under the GL lock. */
1441 HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
1442 struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
1443 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
1445 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
1446 struct wined3d_device *device = dst_surface->resource.device;
1447 DWORD src_ds_flags, dst_ds_flags;
1448 RECT src_rect, dst_rect;
1449 BOOL scale, convert;
1451 static const DWORD simple_blit = WINEDDBLT_ASYNC
1452 | WINEDDBLT_COLORFILL
1454 | WINEDDBLT_DEPTHFILL
1455 | WINEDDBLT_DONOTWAIT;
1457 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1458 dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
1459 flags, fx, debug_d3dtexturefiltertype(filter));
1460 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
1464 TRACE("dwSize %#x.\n", fx->dwSize);
1465 TRACE("dwDDFX %#x.\n", fx->dwDDFX);
1466 TRACE("dwROP %#x.\n", fx->dwROP);
1467 TRACE("dwDDROP %#x.\n", fx->dwDDROP);
1468 TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle);
1469 TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode);
1470 TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow);
1471 TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh);
1472 TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest);
1473 TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth);
1474 TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest);
1475 TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth);
1476 TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc);
1477 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth);
1478 TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend);
1479 TRACE("dwReserved %#x.\n", fx->dwReserved);
1480 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth);
1481 TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest);
1482 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth);
1483 TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc);
1484 TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern);
1485 TRACE("ddckDestColorkey {%#x, %#x}.\n",
1486 fx->ddckDestColorkey.color_space_low_value,
1487 fx->ddckDestColorkey.color_space_high_value);
1488 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
1489 fx->ddckSrcColorkey.color_space_low_value,
1490 fx->ddckSrcColorkey.color_space_high_value);
1493 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
1495 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1496 return WINEDDERR_SURFACEBUSY;
1499 surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
1501 if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom
1502 || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0
1503 || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0
1504 || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0
1505 || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0)
1507 WARN("The application gave us a bad destination rectangle.\n");
1508 return WINEDDERR_INVALIDRECT;
1513 surface_get_rect(src_surface, src_rect_in, &src_rect);
1515 if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom
1516 || src_rect.left > src_surface->resource.width || src_rect.left < 0
1517 || src_rect.top > src_surface->resource.height || src_rect.top < 0
1518 || src_rect.right > src_surface->resource.width || src_rect.right < 0
1519 || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0)
1521 WARN("Application gave us bad source rectangle for Blt.\n");
1522 return WINEDDERR_INVALIDRECT;
1527 memset(&src_rect, 0, sizeof(src_rect));
1530 if (!fx || !(fx->dwDDFX))
1531 flags &= ~WINEDDBLT_DDFX;
1533 if (flags & WINEDDBLT_WAIT)
1534 flags &= ~WINEDDBLT_WAIT;
1536 if (flags & WINEDDBLT_ASYNC)
1538 static unsigned int once;
1541 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1542 flags &= ~WINEDDBLT_ASYNC;
1545 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1546 if (flags & WINEDDBLT_DONOTWAIT)
1548 static unsigned int once;
1551 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1552 flags &= ~WINEDDBLT_DONOTWAIT;
1555 if (!device->d3d_initialized)
1557 WARN("D3D not initialized, using fallback.\n");
1561 /* We want to avoid invalidating the sysmem location for converted
1562 * surfaces, since otherwise we'd have to convert the data back when
1564 if (dst_surface->flags & SFLAG_CONVERTED)
1566 WARN("Converted surface, using CPU blit.\n");
1567 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1570 if (flags & ~simple_blit)
1572 WARN("Using fallback for complex blit (%#x).\n", flags);
1576 if (src_surface && src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1577 src_swapchain = src_surface->container.u.swapchain;
1579 src_swapchain = NULL;
1581 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1582 dst_swapchain = dst_surface->container.u.swapchain;
1584 dst_swapchain = NULL;
1586 /* This isn't strictly needed. FBO blits for example could deal with
1587 * cross-swapchain blits by first downloading the source to a texture
1588 * before switching to the destination context. We just have this here to
1589 * not have to deal with the issue, since cross-swapchain blits should be
1591 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
1593 FIXME("Using fallback for cross-swapchain blit.\n");
1598 && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
1599 || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top);
1600 convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
1602 dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1604 src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1608 if (src_ds_flags || dst_ds_flags)
1610 if (flags & WINEDDBLT_DEPTHFILL)
1614 TRACE("Depth fill.\n");
1616 if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
1617 return WINED3DERR_INVALIDCALL;
1619 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth)))
1624 if (src_ds_flags != dst_ds_flags)
1626 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1627 return WINED3DERR_INVALIDCALL;
1630 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, &src_rect, dst_surface, &dst_rect)))
1636 /* In principle this would apply to depth blits as well, but we don't
1637 * implement those in the CPU blitter at the moment. */
1638 if ((dst_surface->flags & SFLAG_INSYSMEM)
1639 && (!src_surface || (src_surface->flags & SFLAG_INSYSMEM)))
1642 TRACE("Not doing sysmem blit because of scaling.\n");
1644 TRACE("Not doing sysmem blit because of format conversion.\n");
1646 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1649 if (flags & WINEDDBLT_COLORFILL)
1651 struct wined3d_color color;
1653 TRACE("Color fill.\n");
1655 if (!surface_convert_color_to_float(dst_surface, fx->u5.dwFillColor, &color))
1658 if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
1663 TRACE("Color blit.\n");
1666 if ((src_surface->flags & SFLAG_INSYSMEM) && !(dst_surface->flags & SFLAG_INSYSMEM))
1669 TRACE("Not doing upload because of scaling.\n");
1671 TRACE("Not doing upload because of format conversion.\n");
1674 POINT dst_point = {dst_rect.left, dst_rect.top};
1676 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect)))
1678 if (!surface_is_offscreen(dst_surface))
1679 surface_load_location(dst_surface, dst_surface->draw_binding, NULL);
1685 /* Use present for back -> front blits. The idea behind this is
1686 * that present is potentially faster than a blit, in particular
1687 * when FBO blits aren't available. Some ddraw applications like
1688 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
1689 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
1690 * applications can't blit directly to the frontbuffer. */
1691 if (dst_swapchain && dst_swapchain->back_buffers
1692 && dst_surface == dst_swapchain->front_buffer
1693 && src_surface == dst_swapchain->back_buffers[0])
1695 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
1697 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1699 /* Set the swap effect to COPY, we don't want the backbuffer
1700 * to become undefined. */
1701 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
1702 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
1703 dst_swapchain->desc.swap_effect = swap_effect;
1708 if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1709 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1710 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1712 TRACE("Using FBO blit.\n");
1714 surface_blt_fbo(device, filter,
1715 src_surface, src_surface->draw_binding, &src_rect,
1716 dst_surface, dst_surface->draw_binding, &dst_rect);
1717 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
1721 if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1722 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1723 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1725 TRACE("Using arbfp blit.\n");
1727 if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
1735 /* Special cases for render targets. */
1736 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1737 || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)))
1739 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface, &dst_rect,
1740 src_surface, &src_rect, flags, fx, filter)))
1746 /* For the rest call the X11 surface implementation. For render targets
1747 * this should be implemented OpenGL accelerated in BltOverride, other
1748 * blits are rather rare. */
1749 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1752 HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *surface,
1753 struct wined3d_surface *render_target)
1755 TRACE("surface %p, render_target %p.\n", surface, render_target);
1757 /* TODO: Check surface sizes, pools, etc. */
1759 if (render_target->resource.multisample_type)
1760 return WINED3DERR_INVALIDCALL;
1762 return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT);
1765 /* Context activation is done by the caller. */
1766 static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
1768 if (surface->flags & SFLAG_DIBSECTION)
1770 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1774 if (!surface->resource.heapMemory)
1775 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
1776 else if (!(surface->flags & SFLAG_CLIENT))
1777 ERR("Surface %p has heapMemory %p and flags %#x.\n",
1778 surface, surface->resource.heapMemory, surface->flags);
1780 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
1781 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1785 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
1786 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1787 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
1788 surface->resource.size, surface->resource.allocatedMemory));
1789 checkGLcall("glGetBufferSubDataARB");
1790 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
1791 checkGLcall("glDeleteBuffersARB");
1795 surface->flags &= ~SFLAG_PBO;
1798 static BOOL surface_init_sysmem(struct wined3d_surface *surface)
1800 if (!surface->resource.allocatedMemory)
1802 if (!surface->resource.heapMemory)
1804 if (!(surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1805 surface->resource.size + RESOURCE_ALIGNMENT)))
1807 ERR("Failed to allocate memory.\n");
1811 else if (!(surface->flags & SFLAG_CLIENT))
1813 ERR("Surface %p has heapMemory %p and flags %#x.\n",
1814 surface, surface->resource.heapMemory, surface->flags);
1817 surface->resource.allocatedMemory =
1818 (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1822 memset(surface->resource.allocatedMemory, 0, surface->resource.size);
1825 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1830 /* Do not call while under the GL lock. */
1831 static void surface_unload(struct wined3d_resource *resource)
1833 struct wined3d_surface *surface = surface_from_resource(resource);
1834 struct wined3d_renderbuffer_entry *entry, *entry2;
1835 struct wined3d_device *device = resource->device;
1836 const struct wined3d_gl_info *gl_info;
1837 struct wined3d_context *context;
1839 TRACE("surface %p.\n", surface);
1841 if (resource->pool == WINED3D_POOL_DEFAULT)
1843 /* Default pool resources are supposed to be destroyed before Reset is called.
1844 * Implicit resources stay however. So this means we have an implicit render target
1845 * or depth stencil. The content may be destroyed, but we still have to tear down
1846 * opengl resources, so we cannot leave early.
1848 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1849 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1850 * or the depth stencil into an FBO the texture or render buffer will be removed
1851 * and all flags get lost
1853 if (!(surface->flags & SFLAG_PBO))
1854 surface_init_sysmem(surface);
1855 /* We also get here when the ddraw swapchain is destroyed, for example
1856 * for a mode switch. In this case this surface won't necessarily be
1857 * an implicit surface. We have to mark it lost so that the
1858 * application can restore it after the mode switch. */
1859 surface->flags |= SFLAG_LOST;
1863 /* Load the surface into system memory */
1864 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1865 surface_modify_location(surface, surface->draw_binding, FALSE);
1867 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
1868 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
1869 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1871 context = context_acquire(device, NULL);
1872 gl_info = context->gl_info;
1874 /* Destroy PBOs, but load them into real sysmem before */
1875 if (surface->flags & SFLAG_PBO)
1876 surface_remove_pbo(surface, gl_info);
1878 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1879 * all application-created targets the application has to release the surface
1880 * before calling _Reset
1882 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1885 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1887 list_remove(&entry->entry);
1888 HeapFree(GetProcessHeap(), 0, entry);
1890 list_init(&surface->renderbuffers);
1891 surface->current_renderbuffer = NULL;
1895 /* If we're in a texture, the texture name belongs to the texture.
1896 * Otherwise, destroy it. */
1897 if (surface->container.type != WINED3D_CONTAINER_TEXTURE)
1899 glDeleteTextures(1, &surface->texture_name);
1900 surface->texture_name = 0;
1901 glDeleteTextures(1, &surface->texture_name_srgb);
1902 surface->texture_name_srgb = 0;
1904 if (surface->rb_multisample)
1906 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
1907 surface->rb_multisample = 0;
1909 if (surface->rb_resolved)
1911 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
1912 surface->rb_resolved = 0;
1917 context_release(context);
1919 resource_unload(resource);
1922 static const struct wined3d_resource_ops surface_resource_ops =
1927 static const struct wined3d_surface_ops surface_ops =
1929 surface_private_setup,
1930 surface_realize_palette,
1935 /*****************************************************************************
1936 * Initializes the GDI surface, aka creates the DIB section we render to
1937 * The DIB section creation is done by calling GetDC, which will create the
1938 * section and releasing the dc to allow the app to use it. The dib section
1939 * will stay until the surface is released
1941 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1942 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1943 * avoid confusion in the shared surface code.
1946 * WINED3D_OK on success
1947 * The return values of called methods on failure
1949 *****************************************************************************/
1950 static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface)
1954 TRACE("surface %p.\n", surface);
1956 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
1958 ERR("Overlays not yet supported by GDI surfaces.\n");
1959 return WINED3DERR_INVALIDCALL;
1962 /* Sysmem textures have memory already allocated - release it,
1963 * this avoids an unnecessary memcpy. */
1964 hr = surface_create_dib_section(surface);
1967 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
1968 surface->resource.heapMemory = NULL;
1969 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1972 /* We don't mind the nonpow2 stuff in GDI. */
1973 surface->pow2Width = surface->resource.width;
1974 surface->pow2Height = surface->resource.height;
1979 static void gdi_surface_realize_palette(struct wined3d_surface *surface)
1981 struct wined3d_palette *palette = surface->palette;
1983 TRACE("surface %p.\n", surface);
1985 if (!palette) return;
1987 if (surface->flags & SFLAG_DIBSECTION)
1992 TRACE("Updating the DC's palette.\n");
1994 for (i = 0; i < 256; ++i)
1996 col[i].rgbRed = palette->palents[i].peRed;
1997 col[i].rgbGreen = palette->palents[i].peGreen;
1998 col[i].rgbBlue = palette->palents[i].peBlue;
1999 col[i].rgbReserved = 0;
2001 SetDIBColorTable(surface->hDC, 0, 256, col);
2004 /* Update the image because of the palette change. Some games like e.g.
2005 * Red Alert call SetEntries a lot to implement fading. */
2006 /* Tell the swapchain to update the screen. */
2007 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
2009 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2010 if (surface == swapchain->front_buffer)
2012 x11_copy_to_screen(swapchain, NULL);
2017 static void gdi_surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
2019 TRACE("surface %p, rect %s, flags %#x.\n",
2020 surface, wine_dbgstr_rect(rect), flags);
2022 if (!(surface->flags & SFLAG_DIBSECTION))
2026 /* This happens on gdi surfaces if the application set a user pointer
2027 * and resets it. Recreate the DIB section. */
2028 if (FAILED(hr = surface_create_dib_section(surface)))
2030 ERR("Failed to create dib section, hr %#x.\n", hr);
2033 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
2034 surface->resource.heapMemory = NULL;
2035 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2039 static void gdi_surface_unmap(struct wined3d_surface *surface)
2041 TRACE("surface %p.\n", surface);
2043 /* Tell the swapchain to update the screen. */
2044 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
2046 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2047 if (surface == swapchain->front_buffer)
2049 x11_copy_to_screen(swapchain, &surface->lockedRect);
2053 memset(&surface->lockedRect, 0, sizeof(RECT));
2056 static const struct wined3d_surface_ops gdi_surface_ops =
2058 gdi_surface_private_setup,
2059 gdi_surface_realize_palette,
2064 void surface_set_texture_name(struct wined3d_surface *surface, GLuint new_name, BOOL srgb)
2069 TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
2073 name = &surface->texture_name_srgb;
2074 flag = SFLAG_INSRGBTEX;
2078 name = &surface->texture_name;
2079 flag = SFLAG_INTEXTURE;
2082 if (!*name && new_name)
2084 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2085 * surface has no texture name yet. See if we can get rid of this. */
2086 if (surface->flags & flag)
2088 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
2089 surface_modify_location(surface, flag, FALSE);
2094 surface_force_reload(surface);
2097 void surface_set_texture_target(struct wined3d_surface *surface, GLenum target)
2099 TRACE("surface %p, target %#x.\n", surface, target);
2101 if (surface->texture_target != target)
2103 if (target == GL_TEXTURE_RECTANGLE_ARB)
2105 surface->flags &= ~SFLAG_NORMCOORD;
2107 else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2109 surface->flags |= SFLAG_NORMCOORD;
2112 surface->texture_target = target;
2113 surface_force_reload(surface);
2116 /* This call just downloads data, the caller is responsible for binding the
2117 * correct texture. */
2118 /* Context activation is done by the caller. */
2119 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2121 const struct wined3d_format *format = surface->resource.format;
2123 /* Only support read back of converted P8 surfaces. */
2124 if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
2126 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
2132 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2134 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2135 surface, surface->texture_level, format->glFormat, format->glType,
2136 surface->resource.allocatedMemory);
2138 if (surface->flags & SFLAG_PBO)
2140 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2141 checkGLcall("glBindBufferARB");
2142 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
2143 checkGLcall("glGetCompressedTexImageARB");
2144 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2145 checkGLcall("glBindBufferARB");
2149 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
2150 surface->texture_level, surface->resource.allocatedMemory));
2151 checkGLcall("glGetCompressedTexImageARB");
2159 GLenum gl_format = format->glFormat;
2160 GLenum gl_type = format->glType;
2164 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2165 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device))
2167 gl_format = GL_ALPHA;
2168 gl_type = GL_UNSIGNED_BYTE;
2171 if (surface->flags & SFLAG_NONPOW2)
2173 unsigned char alignment = surface->resource.device->surface_alignment;
2174 src_pitch = format->byte_count * surface->pow2Width;
2175 dst_pitch = wined3d_surface_get_pitch(surface);
2176 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
2177 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
2181 mem = surface->resource.allocatedMemory;
2184 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2185 surface, surface->texture_level, gl_format, gl_type, mem);
2187 if (surface->flags & SFLAG_PBO)
2189 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2190 checkGLcall("glBindBufferARB");
2192 glGetTexImage(surface->texture_target, surface->texture_level, gl_format, gl_type, NULL);
2193 checkGLcall("glGetTexImage");
2195 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2196 checkGLcall("glBindBufferARB");
2200 glGetTexImage(surface->texture_target, surface->texture_level, gl_format, gl_type, mem);
2201 checkGLcall("glGetTexImage");
2205 if (surface->flags & SFLAG_NONPOW2)
2207 const BYTE *src_data;
2211 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2212 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2213 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2215 * We're doing this...
2217 * instead of boxing the texture :
2218 * |<-texture width ->| -->pow2width| /\
2219 * |111111111111111111| | |
2220 * |222 Texture 222222| boxed empty | texture height
2221 * |3333 Data 33333333| | |
2222 * |444444444444444444| | \/
2223 * ----------------------------------- |
2224 * | boxed empty | boxed empty | pow2height
2226 * -----------------------------------
2229 * we're repacking the data to the expected texture width
2231 * |<-texture width ->| -->pow2width| /\
2232 * |111111111111111111222222222222222| |
2233 * |222333333333333333333444444444444| texture height
2237 * | empty | pow2height
2239 * -----------------------------------
2243 * |<-texture width ->| /\
2244 * |111111111111111111|
2245 * |222222222222222222|texture height
2246 * |333333333333333333|
2247 * |444444444444444444| \/
2248 * --------------------
2250 * this also means that any references to allocatedMemory should work with the data as if were a
2251 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2253 * internally the texture is still stored in a boxed format so any references to textureName will
2254 * get a boxed texture with width pow2width and not a texture of width resource.width.
2256 * Performance should not be an issue, because applications normally do not lock the surfaces when
2257 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2258 * and doesn't have to be re-read. */
2260 dst_data = surface->resource.allocatedMemory;
2261 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
2262 for (y = 1; y < surface->resource.height; ++y)
2264 /* skip the first row */
2265 src_data += src_pitch;
2266 dst_data += dst_pitch;
2267 memcpy(dst_data, src_data, dst_pitch);
2270 HeapFree(GetProcessHeap(), 0, mem);
2274 /* Surface has now been downloaded */
2275 surface->flags |= SFLAG_INSYSMEM;
2278 /* This call just uploads data, the caller is responsible for binding the
2279 * correct texture. */
2280 /* Context activation is done by the caller. */
2281 static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2282 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
2283 BOOL srgb, const struct wined3d_bo_address *data)
2285 UINT update_w = src_rect->right - src_rect->left;
2286 UINT update_h = src_rect->bottom - src_rect->top;
2288 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
2289 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
2290 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
2292 if (surface->resource.map_count)
2294 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
2295 surface->flags |= SFLAG_PIN_SYSMEM;
2298 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2300 update_h *= format->height_scale.numerator;
2301 update_h /= format->height_scale.denominator;
2306 if (data->buffer_object)
2308 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
2309 checkGLcall("glBindBufferARB");
2312 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2314 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1);
2315 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
2316 const BYTE *addr = data->addr;
2319 addr += (src_rect->top / format->block_height) * src_pitch;
2320 addr += (src_rect->left / format->block_width) * format->block_byte_count;
2323 internal = format->glGammaInternal;
2324 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2325 internal = format->rtInternal;
2327 internal = format->glInternal;
2329 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2330 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
2331 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
2333 if (row_length == src_pitch)
2335 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2336 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
2342 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2343 * can't use the unpack row length like below. */
2344 for (row = 0, y = dst_point->y; row < row_count; ++row)
2346 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2347 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
2348 y += format->block_height;
2352 checkGLcall("glCompressedTexSubImage2DARB");
2356 const BYTE *addr = data->addr;
2358 addr += src_rect->top * src_pitch;
2359 addr += src_rect->left * format->byte_count;
2361 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2362 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
2363 update_w, update_h, format->glFormat, format->glType, addr);
2365 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
2366 glTexSubImage2D(surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
2367 update_w, update_h, format->glFormat, format->glType, addr);
2368 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2369 checkGLcall("glTexSubImage2D");
2372 if (data->buffer_object)
2374 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2375 checkGLcall("glBindBufferARB");
2380 if (wined3d_settings.strict_draw_ordering)
2383 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2385 struct wined3d_device *device = surface->resource.device;
2388 for (i = 0; i < device->context_count; ++i)
2390 context_surface_update(device->contexts[i], surface);
2395 static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
2396 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
2398 BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2399 const struct wined3d_device *device = surface->resource.device;
2400 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2401 BOOL blit_supported = FALSE;
2403 /* Copy the default values from the surface. Below we might perform fixups */
2404 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2405 *format = *surface->resource.format;
2406 *conversion_type = WINED3D_CT_NONE;
2408 /* Ok, now look if we have to do any conversion */
2409 switch (surface->resource.format->id)
2411 case WINED3DFMT_P8_UINT:
2412 /* Below the call to blit_supported is disabled for Wine 1.2
2413 * because the function isn't operating correctly yet. At the
2414 * moment 8-bit blits are handled in software and if certain GL
2415 * extensions are around, surface conversion is performed at
2416 * upload time. The blit_supported call recognizes it as a
2417 * destination fixup. This type of upload 'fixup' and 8-bit to
2418 * 8-bit blits need to be handled by the blit_shader.
2419 * TODO: get rid of this #if 0. */
2421 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2422 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
2423 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
2425 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2427 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2428 * texturing. Further also use conversion in case of color keying.
2429 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2430 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2431 * conflicts with this.
2433 if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
2434 || colorkey_active || !use_texturing)
2436 format->glFormat = GL_RGBA;
2437 format->glInternal = GL_RGBA;
2438 format->glType = GL_UNSIGNED_BYTE;
2439 format->conv_byte_count = 4;
2440 if (colorkey_active)
2441 *conversion_type = WINED3D_CT_PALETTED_CK;
2443 *conversion_type = WINED3D_CT_PALETTED;
2447 case WINED3DFMT_B2G3R3_UNORM:
2448 /* **********************
2449 GL_UNSIGNED_BYTE_3_3_2
2450 ********************** */
2451 if (colorkey_active) {
2452 /* This texture format will never be used.. So do not care about color keying
2453 up until the point in time it will be needed :-) */
2454 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2458 case WINED3DFMT_B5G6R5_UNORM:
2459 if (colorkey_active)
2461 *conversion_type = WINED3D_CT_CK_565;
2462 format->glFormat = GL_RGBA;
2463 format->glInternal = GL_RGB5_A1;
2464 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2465 format->conv_byte_count = 2;
2469 case WINED3DFMT_B5G5R5X1_UNORM:
2470 if (colorkey_active)
2472 *conversion_type = WINED3D_CT_CK_5551;
2473 format->glFormat = GL_BGRA;
2474 format->glInternal = GL_RGB5_A1;
2475 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2476 format->conv_byte_count = 2;
2480 case WINED3DFMT_B8G8R8_UNORM:
2481 if (colorkey_active)
2483 *conversion_type = WINED3D_CT_CK_RGB24;
2484 format->glFormat = GL_RGBA;
2485 format->glInternal = GL_RGBA8;
2486 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2487 format->conv_byte_count = 4;
2491 case WINED3DFMT_B8G8R8X8_UNORM:
2492 if (colorkey_active)
2494 *conversion_type = WINED3D_CT_RGB32_888;
2495 format->glFormat = GL_RGBA;
2496 format->glInternal = GL_RGBA8;
2497 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2498 format->conv_byte_count = 4;
2502 case WINED3DFMT_B8G8R8A8_UNORM:
2503 if (colorkey_active)
2505 *conversion_type = WINED3D_CT_CK_ARGB32;
2506 format->conv_byte_count = 4;
2514 if (*conversion_type != WINED3D_CT_NONE)
2516 format->rtInternal = format->glInternal;
2517 format->glGammaInternal = format->glInternal;
2523 static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
2525 UINT width_mask, height_mask;
2527 if (!rect->left && !rect->top
2528 && rect->right == surface->resource.width
2529 && rect->bottom == surface->resource.height)
2532 /* This assumes power of two block sizes, but NPOT block sizes would be
2534 width_mask = surface->resource.format->block_width - 1;
2535 height_mask = surface->resource.format->block_height - 1;
2537 if (!(rect->left & width_mask) && !(rect->top & height_mask)
2538 && !(rect->right & width_mask) && !(rect->bottom & height_mask))
2544 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
2545 struct wined3d_surface *src_surface, const RECT *src_rect)
2547 const struct wined3d_format *src_format;
2548 const struct wined3d_format *dst_format;
2549 const struct wined3d_gl_info *gl_info;
2550 enum wined3d_conversion_type convert;
2551 struct wined3d_context *context;
2552 struct wined3d_bo_address data;
2553 struct wined3d_format format;
2554 UINT update_w, update_h;
2561 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2562 dst_surface, wine_dbgstr_point(dst_point),
2563 src_surface, wine_dbgstr_rect(src_rect));
2565 src_format = src_surface->resource.format;
2566 dst_format = dst_surface->resource.format;
2568 if (src_format->id != dst_format->id)
2570 WARN("Source and destination surfaces should have the same format.\n");
2571 return WINED3DERR_INVALIDCALL;
2580 else if (dst_point->x < 0 || dst_point->y < 0)
2582 WARN("Invalid destination point.\n");
2583 return WINED3DERR_INVALIDCALL;
2590 r.right = src_surface->resource.width;
2591 r.bottom = src_surface->resource.height;
2594 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
2595 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
2597 WARN("Invalid source rectangle.\n");
2598 return WINED3DERR_INVALIDCALL;
2601 src_w = src_surface->resource.width;
2602 src_h = src_surface->resource.height;
2604 dst_w = dst_surface->resource.width;
2605 dst_h = dst_surface->resource.height;
2607 update_w = src_rect->right - src_rect->left;
2608 update_h = src_rect->bottom - src_rect->top;
2610 if (update_w > dst_w || dst_point->x > dst_w - update_w
2611 || update_h > dst_h || dst_point->y > dst_h - update_h)
2613 WARN("Destination out of bounds.\n");
2614 return WINED3DERR_INVALIDCALL;
2617 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
2619 WARN("Source rectangle not block-aligned.\n");
2620 return WINED3DERR_INVALIDCALL;
2623 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
2624 if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
2626 WARN("Destination rectangle not block-aligned.\n");
2627 return WINED3DERR_INVALIDCALL;
2630 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2631 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
2632 if (convert != WINED3D_CT_NONE || format.convert)
2633 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
2635 context = context_acquire(dst_surface->resource.device, NULL);
2636 gl_info = context->gl_info;
2638 /* Only load the surface for partial updates. For newly allocated texture
2639 * the texture wouldn't be the current location, and we'd upload zeroes
2640 * just to overwrite them again. */
2641 if (update_w == dst_w && update_h == dst_h)
2642 surface_prepare_texture(dst_surface, context, FALSE);
2644 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
2645 surface_bind(dst_surface, context, FALSE);
2647 data.buffer_object = src_surface->pbo;
2648 data.addr = src_surface->resource.allocatedMemory;
2649 src_pitch = wined3d_surface_get_pitch(src_surface);
2651 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
2653 invalidate_active_texture(dst_surface->resource.device, context);
2655 context_release(context);
2657 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2661 /* This call just allocates the texture, the caller is responsible for binding
2662 * the correct texture. */
2663 /* Context activation is done by the caller. */
2664 static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2665 const struct wined3d_format *format, BOOL srgb)
2667 BOOL enable_client_storage = FALSE;
2668 GLsizei width = surface->pow2Width;
2669 GLsizei height = surface->pow2Height;
2670 const BYTE *mem = NULL;
2675 internal = format->glGammaInternal;
2677 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2679 internal = format->rtInternal;
2683 internal = format->glInternal;
2687 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2689 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2691 height *= format->height_scale.numerator;
2692 height /= format->height_scale.denominator;
2695 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",
2696 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
2697 internal, width, height, format->glFormat, format->glType);
2701 if (gl_info->supported[APPLE_CLIENT_STORAGE])
2703 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2704 || !surface->resource.allocatedMemory)
2706 /* In some cases we want to disable client storage.
2707 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2708 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2709 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2710 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2712 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2713 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2714 surface->flags &= ~SFLAG_CLIENT;
2715 enable_client_storage = TRUE;
2719 surface->flags |= SFLAG_CLIENT;
2721 /* Point OpenGL to our allocated texture memory. Do not use
2722 * resource.allocatedMemory here because it might point into a
2723 * PBO. Instead use heapMemory, but get the alignment right. */
2724 mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2725 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2729 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
2731 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
2732 internal, width, height, 0, surface->resource.size, mem));
2733 checkGLcall("glCompressedTexImage2DARB");
2737 glTexImage2D(surface->texture_target, surface->texture_level,
2738 internal, width, height, 0, format->glFormat, format->glType, mem);
2739 checkGLcall("glTexImage2D");
2742 if(enable_client_storage) {
2743 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2744 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2749 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2750 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2751 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2752 /* GL locking is done by the caller */
2753 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
2755 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
2756 struct wined3d_renderbuffer_entry *entry;
2757 GLuint renderbuffer = 0;
2758 unsigned int src_width, src_height;
2759 unsigned int width, height;
2761 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
2763 width = rt->pow2Width;
2764 height = rt->pow2Height;
2768 width = surface->pow2Width;
2769 height = surface->pow2Height;
2772 src_width = surface->pow2Width;
2773 src_height = surface->pow2Height;
2775 /* A depth stencil smaller than the render target is not valid */
2776 if (width > src_width || height > src_height) return;
2778 /* Remove any renderbuffer set if the sizes match */
2779 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
2780 || (width == src_width && height == src_height))
2782 surface->current_renderbuffer = NULL;
2786 /* Look if we've already got a renderbuffer of the correct dimensions */
2787 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2789 if (entry->width == width && entry->height == height)
2791 renderbuffer = entry->id;
2792 surface->current_renderbuffer = entry;
2799 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
2800 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
2801 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
2802 surface->resource.format->glInternal, width, height);
2804 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
2805 entry->width = width;
2806 entry->height = height;
2807 entry->id = renderbuffer;
2808 list_add_head(&surface->renderbuffers, &entry->entry);
2810 surface->current_renderbuffer = entry;
2813 checkGLcall("set_compatible_renderbuffer");
2816 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
2818 const struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2820 TRACE("surface %p.\n", surface);
2822 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
2824 ERR("Surface %p is not on a swapchain.\n", surface);
2828 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
2830 if (swapchain->render_to_fbo)
2832 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2833 return GL_COLOR_ATTACHMENT0;
2835 TRACE("Returning GL_BACK\n");
2838 else if (surface == swapchain->front_buffer)
2840 TRACE("Returning GL_FRONT\n");
2844 FIXME("Higher back buffer, returning GL_BACK\n");
2848 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2849 void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
2851 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
2853 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
2854 /* No partial locking for textures yet. */
2855 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2857 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2860 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
2861 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
2862 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
2863 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
2867 surface->dirtyRect.left = 0;
2868 surface->dirtyRect.top = 0;
2869 surface->dirtyRect.right = surface->resource.width;
2870 surface->dirtyRect.bottom = surface->resource.height;
2873 /* if the container is a texture then mark it dirty. */
2874 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
2876 TRACE("Passing to container.\n");
2877 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
2881 HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
2883 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2886 TRACE("surface %p, srgb %#x.\n", surface, srgb);
2888 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
2890 ERR("Not supported on scratch surfaces.\n");
2891 return WINED3DERR_INVALIDCALL;
2894 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2896 /* Reload if either the texture and sysmem have different ideas about the
2897 * color key, or the actual key values changed. */
2898 if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
2899 && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
2900 || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
2902 TRACE("Reloading because of color keying\n");
2903 /* To perform the color key conversion we need a sysmem copy of
2904 * the surface. Make sure we have it. */
2906 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2907 /* Make sure the texture is reloaded because of the color key change,
2908 * this kills performance though :( */
2909 /* TODO: This is not necessarily needed with hw palettized texture support. */
2910 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2911 /* Switching color keying on / off may change the internal format. */
2913 surface_force_reload(surface);
2915 else if (!(surface->flags & flag))
2917 TRACE("Reloading because surface is dirty.\n");
2921 TRACE("surface is already in texture\n");
2925 /* No partial locking for textures yet. */
2926 surface_load_location(surface, flag, NULL);
2927 surface_evict_sysmem(surface);
2932 /* See also float_16_to_32() in wined3d_private.h */
2933 static inline unsigned short float_32_to_16(const float *in)
2936 float tmp = fabsf(*in);
2937 unsigned int mantissa;
2940 /* Deal with special numbers */
2946 return (*in < 0.0f ? 0xfc00 : 0x7c00);
2948 if (tmp < powf(2, 10))
2954 } while (tmp < powf(2, 10));
2956 else if (tmp >= powf(2, 11))
2962 } while (tmp >= powf(2, 11));
2965 mantissa = (unsigned int)tmp;
2966 if (tmp - mantissa >= 0.5f)
2967 ++mantissa; /* Round to nearest, away from zero. */
2969 exp += 10; /* Normalize the mantissa. */
2970 exp += 15; /* Exponent is encoded with excess 15. */
2972 if (exp > 30) /* too big */
2974 ret = 0x7c00; /* INF */
2978 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2981 mantissa = mantissa >> 1;
2984 ret = mantissa & 0x3ff;
2988 ret = (exp << 10) | (mantissa & 0x3ff);
2991 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
2995 ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
2999 TRACE("Surface %p, container %p of type %#x.\n",
3000 surface, surface->container.u.base, surface->container.type);
3002 switch (surface->container.type)
3004 case WINED3D_CONTAINER_TEXTURE:
3005 return wined3d_texture_incref(surface->container.u.texture);
3007 case WINED3D_CONTAINER_SWAPCHAIN:
3008 return wined3d_swapchain_incref(surface->container.u.swapchain);
3011 ERR("Unhandled container type %#x.\n", surface->container.type);
3012 case WINED3D_CONTAINER_NONE:
3016 refcount = InterlockedIncrement(&surface->resource.ref);
3017 TRACE("%p increasing refcount to %u.\n", surface, refcount);
3022 /* Do not call while under the GL lock. */
3023 ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
3027 TRACE("Surface %p, container %p of type %#x.\n",
3028 surface, surface->container.u.base, surface->container.type);
3030 switch (surface->container.type)
3032 case WINED3D_CONTAINER_TEXTURE:
3033 return wined3d_texture_decref(surface->container.u.texture);
3035 case WINED3D_CONTAINER_SWAPCHAIN:
3036 return wined3d_swapchain_decref(surface->container.u.swapchain);
3039 ERR("Unhandled container type %#x.\n", surface->container.type);
3040 case WINED3D_CONTAINER_NONE:
3044 refcount = InterlockedDecrement(&surface->resource.ref);
3045 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3049 surface_cleanup(surface);
3050 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3052 TRACE("Destroyed surface %p.\n", surface);
3053 HeapFree(GetProcessHeap(), 0, surface);
3059 DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
3061 return resource_set_priority(&surface->resource, priority);
3064 DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
3066 return resource_get_priority(&surface->resource);
3069 void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
3071 TRACE("surface %p.\n", surface);
3073 if (!surface->resource.device->d3d_initialized)
3075 ERR("D3D not initialized.\n");
3079 surface_internal_preload(surface, SRGB_ANY);
3082 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
3084 TRACE("surface %p.\n", surface);
3086 return surface->resource.parent;
3089 struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
3091 TRACE("surface %p.\n", surface);
3093 return &surface->resource;
3096 HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
3098 TRACE("surface %p, flags %#x.\n", surface, flags);
3102 case WINEDDGBS_CANBLT:
3103 case WINEDDGBS_ISBLTDONE:
3107 return WINED3DERR_INVALIDCALL;
3111 HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
3113 TRACE("surface %p, flags %#x.\n", surface, flags);
3115 /* XXX: DDERR_INVALIDSURFACETYPE */
3119 case WINEDDGFS_CANFLIP:
3120 case WINEDDGFS_ISFLIPDONE:
3124 return WINED3DERR_INVALIDCALL;
3128 HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
3130 TRACE("surface %p.\n", surface);
3132 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
3133 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3136 HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
3138 TRACE("surface %p.\n", surface);
3140 surface->flags &= ~SFLAG_LOST;
3144 HRESULT CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
3146 TRACE("surface %p, palette %p.\n", surface, palette);
3148 if (surface->palette == palette)
3150 TRACE("Nop palette change.\n");
3154 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
3155 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3157 surface->palette = palette;
3161 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3162 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
3164 surface->surface_ops->surface_realize_palette(surface);
3170 HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3171 DWORD flags, const struct wined3d_color_key *color_key)
3173 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3175 if (flags & WINEDDCKEY_COLORSPACE)
3177 FIXME(" colorkey value not supported (%08x) !\n", flags);
3178 return WINED3DERR_INVALIDCALL;
3181 /* Dirtify the surface, but only if a key was changed. */
3184 switch (flags & ~WINEDDCKEY_COLORSPACE)
3186 case WINEDDCKEY_DESTBLT:
3187 surface->dst_blt_color_key = *color_key;
3188 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3191 case WINEDDCKEY_DESTOVERLAY:
3192 surface->dst_overlay_color_key = *color_key;
3193 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3196 case WINEDDCKEY_SRCOVERLAY:
3197 surface->src_overlay_color_key = *color_key;
3198 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3201 case WINEDDCKEY_SRCBLT:
3202 surface->src_blt_color_key = *color_key;
3203 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3209 switch (flags & ~WINEDDCKEY_COLORSPACE)
3211 case WINEDDCKEY_DESTBLT:
3212 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3215 case WINEDDCKEY_DESTOVERLAY:
3216 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3219 case WINEDDCKEY_SRCOVERLAY:
3220 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3223 case WINEDDCKEY_SRCBLT:
3224 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3232 struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3234 TRACE("surface %p.\n", surface);
3236 return surface->palette;
3239 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3241 const struct wined3d_format *format = surface->resource.format;
3244 TRACE("surface %p.\n", surface);
3246 if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3248 /* Since compressed formats are block based, pitch means the amount of
3249 * bytes to the next row of block rather than the next row of pixels. */
3250 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3251 pitch = row_block_count * format->block_byte_count;
3255 unsigned char alignment = surface->resource.device->surface_alignment;
3256 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
3257 pitch = (pitch + alignment - 1) & ~(alignment - 1);
3260 TRACE("Returning %u.\n", pitch);
3265 HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem)
3267 TRACE("surface %p, mem %p.\n", surface, mem);
3269 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3271 WARN("Surface is mapped or the DC is in use.\n");
3272 return WINED3DERR_INVALIDCALL;
3275 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3276 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3278 ERR("Not supported on render targets.\n");
3279 return WINED3DERR_INVALIDCALL;
3282 if (mem && mem != surface->resource.allocatedMemory)
3284 void *release = NULL;
3286 /* Do I have to copy the old surface content? */
3287 if (surface->flags & SFLAG_DIBSECTION)
3289 DeleteDC(surface->hDC);
3290 DeleteObject(surface->dib.DIBsection);
3291 surface->dib.bitmap_data = NULL;
3292 surface->resource.allocatedMemory = NULL;
3293 surface->hDC = NULL;
3294 surface->flags &= ~SFLAG_DIBSECTION;
3296 else if (!(surface->flags & SFLAG_USERPTR))
3298 release = surface->resource.heapMemory;
3299 surface->resource.heapMemory = NULL;
3301 surface->resource.allocatedMemory = mem;
3302 surface->flags |= SFLAG_USERPTR;
3304 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3305 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3307 /* For client textures OpenGL has to be notified. */
3308 if (surface->flags & SFLAG_CLIENT)
3309 surface_release_client_storage(surface);
3311 /* Now free the old memory if any. */
3312 HeapFree(GetProcessHeap(), 0, release);
3314 else if (surface->flags & SFLAG_USERPTR)
3316 /* HeapMemory should be NULL already. */
3317 if (surface->resource.heapMemory)
3318 ERR("User pointer surface has heap memory allocated.\n");
3322 surface->resource.allocatedMemory = NULL;
3323 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3325 if (surface->flags & SFLAG_CLIENT)
3326 surface_release_client_storage(surface);
3328 surface_prepare_system_memory(surface);
3331 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3337 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3341 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3343 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3345 WARN("Not an overlay surface.\n");
3346 return WINEDDERR_NOTAOVERLAYSURFACE;
3349 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3350 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3351 surface->overlay_destrect.left = x;
3352 surface->overlay_destrect.top = y;
3353 surface->overlay_destrect.right = x + w;
3354 surface->overlay_destrect.bottom = y + h;
3356 surface_draw_overlay(surface);
3361 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3363 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3365 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3367 TRACE("Not an overlay surface.\n");
3368 return WINEDDERR_NOTAOVERLAYSURFACE;
3371 if (!surface->overlay_dest)
3373 TRACE("Overlay not visible.\n");
3376 return WINEDDERR_OVERLAYNOTVISIBLE;
3379 *x = surface->overlay_destrect.left;
3380 *y = surface->overlay_destrect.top;
3382 TRACE("Returning position %d, %d.\n", *x, *y);
3387 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3388 DWORD flags, struct wined3d_surface *ref)
3390 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3392 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3394 TRACE("Not an overlay surface.\n");
3395 return WINEDDERR_NOTAOVERLAYSURFACE;
3401 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3402 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3404 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3405 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3407 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3409 WARN("Not an overlay surface.\n");
3410 return WINEDDERR_NOTAOVERLAYSURFACE;
3412 else if (!dst_surface)
3414 WARN("Dest surface is NULL.\n");
3415 return WINED3DERR_INVALIDCALL;
3420 surface->overlay_srcrect = *src_rect;
3424 surface->overlay_srcrect.left = 0;
3425 surface->overlay_srcrect.top = 0;
3426 surface->overlay_srcrect.right = surface->resource.width;
3427 surface->overlay_srcrect.bottom = surface->resource.height;
3432 surface->overlay_destrect = *dst_rect;
3436 surface->overlay_destrect.left = 0;
3437 surface->overlay_destrect.top = 0;
3438 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3439 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3442 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3444 surface->overlay_dest = NULL;
3445 list_remove(&surface->overlay_entry);
3448 if (flags & WINEDDOVER_SHOW)
3450 if (surface->overlay_dest != dst_surface)
3452 surface->overlay_dest = dst_surface;
3453 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3456 else if (flags & WINEDDOVER_HIDE)
3458 /* tests show that the rectangles are erased on hide */
3459 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3460 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3461 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3462 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3463 surface->overlay_dest = NULL;
3466 surface_draw_overlay(surface);
3471 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3472 UINT width, UINT height, enum wined3d_format_id format_id,
3473 enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3475 struct wined3d_device *device = surface->resource.device;
3476 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3477 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3478 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3480 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3481 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3484 return WINED3DERR_INVALIDCALL;
3486 if (device->d3d_initialized)
3487 surface->resource.resource_ops->resource_unload(&surface->resource);
3489 if (surface->flags & SFLAG_DIBSECTION)
3491 DeleteDC(surface->hDC);
3492 DeleteObject(surface->dib.DIBsection);
3493 surface->dib.bitmap_data = NULL;
3494 surface->flags &= ~SFLAG_DIBSECTION;
3497 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3498 surface->resource.allocatedMemory = NULL;
3499 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3500 surface->resource.heapMemory = NULL;
3502 surface->resource.width = width;
3503 surface->resource.height = height;
3504 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3505 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3507 surface->pow2Width = width;
3508 surface->pow2Height = height;
3512 surface->pow2Width = surface->pow2Height = 1;
3513 while (surface->pow2Width < width)
3514 surface->pow2Width <<= 1;
3515 while (surface->pow2Height < height)
3516 surface->pow2Height <<= 1;
3519 if (surface->pow2Width != width || surface->pow2Height != height)
3520 surface->flags |= SFLAG_NONPOW2;
3522 surface->flags &= ~SFLAG_NONPOW2;
3524 surface->resource.format = format;
3525 surface->resource.multisample_type = multisample_type;
3526 surface->resource.multisample_quality = multisample_quality;
3527 surface->resource.size = resource_size;
3529 if (!surface_init_sysmem(surface))
3530 return E_OUTOFMEMORY;
3535 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3536 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3538 unsigned short *dst_s;
3542 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3544 for (y = 0; y < h; ++y)
3546 src_f = (const float *)(src + y * pitch_in);
3547 dst_s = (unsigned short *) (dst + y * pitch_out);
3548 for (x = 0; x < w; ++x)
3550 dst_s[x] = float_32_to_16(src_f + x);
3555 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3556 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3558 static const unsigned char convert_5to8[] =
3560 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3561 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3562 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3563 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3565 static const unsigned char convert_6to8[] =
3567 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3568 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3569 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3570 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3571 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3572 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3573 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3574 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3578 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3580 for (y = 0; y < h; ++y)
3582 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3583 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3584 for (x = 0; x < w; ++x)
3586 WORD pixel = src_line[x];
3587 dst_line[x] = 0xff000000
3588 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3589 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3590 | convert_5to8[(pixel & 0x001f)];
3595 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3596 * in both cases we're just setting the X / Alpha channel to 0xff. */
3597 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3598 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3602 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3604 for (y = 0; y < h; ++y)
3606 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3607 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3609 for (x = 0; x < w; ++x)
3611 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3616 static inline BYTE cliptobyte(int x)
3618 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3621 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3622 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3624 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3627 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3629 for (y = 0; y < h; ++y)
3631 const BYTE *src_line = src + y * pitch_in;
3632 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3633 for (x = 0; x < w; ++x)
3635 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3636 * C = Y - 16; D = U - 128; E = V - 128;
3637 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3638 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3639 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3640 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3641 * U and V are shared between the pixels. */
3642 if (!(x & 1)) /* For every even pixel, read new U and V. */
3644 d = (int) src_line[1] - 128;
3645 e = (int) src_line[3] - 128;
3647 g2 = - 100 * d - 208 * e + 128;
3650 c2 = 298 * ((int) src_line[0] - 16);
3651 dst_line[x] = 0xff000000
3652 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3653 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3654 | cliptobyte((c2 + b2) >> 8); /* blue */
3655 /* Scale RGB values to 0..255 range,
3656 * then clip them if still not in range (may be negative),
3657 * then shift them within DWORD if necessary. */
3663 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3664 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3667 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3669 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3671 for (y = 0; y < h; ++y)
3673 const BYTE *src_line = src + y * pitch_in;
3674 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3675 for (x = 0; x < w; ++x)
3677 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3678 * C = Y - 16; D = U - 128; E = V - 128;
3679 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3680 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3681 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3682 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3683 * U and V are shared between the pixels. */
3684 if (!(x & 1)) /* For every even pixel, read new U and V. */
3686 d = (int) src_line[1] - 128;
3687 e = (int) src_line[3] - 128;
3689 g2 = - 100 * d - 208 * e + 128;
3692 c2 = 298 * ((int) src_line[0] - 16);
3693 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3694 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3695 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3696 /* Scale RGB values to 0..255 range,
3697 * then clip them if still not in range (may be negative),
3698 * then shift them within DWORD if necessary. */
3704 struct d3dfmt_convertor_desc
3706 enum wined3d_format_id from, to;
3707 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3710 static const struct d3dfmt_convertor_desc convertors[] =
3712 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3713 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3714 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3715 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3716 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3717 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3720 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from,
3721 enum wined3d_format_id to)
3725 for (i = 0; i < (sizeof(convertors) / sizeof(*convertors)); ++i)
3727 if (convertors[i].from == from && convertors[i].to == to)
3728 return &convertors[i];
3734 /*****************************************************************************
3735 * surface_convert_format
3737 * Creates a duplicate of a surface in a different format. Is used by Blt to
3738 * blit between surfaces with different formats.
3741 * source: Source surface
3742 * fmt: Requested destination format
3744 *****************************************************************************/
3745 static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
3747 struct wined3d_map_desc src_map, dst_map;
3748 const struct d3dfmt_convertor_desc *conv;
3749 struct wined3d_surface *ret = NULL;
3752 conv = find_convertor(source->resource.format->id, to_fmt);
3755 FIXME("Cannot find a conversion function from format %s to %s.\n",
3756 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
3760 wined3d_surface_create(source->resource.device, source->resource.width,
3761 source->resource.height, to_fmt, 0 /* level */, 0 /* usage */, WINED3D_POOL_SCRATCH,
3762 WINED3D_MULTISAMPLE_NONE /* TODO: Multisampled conversion */, 0 /* MultiSampleQuality */,
3763 source->surface_type, WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD,
3764 NULL /* parent */, &wined3d_null_parent_ops, &ret);
3767 ERR("Failed to create a destination surface for conversion.\n");
3771 memset(&src_map, 0, sizeof(src_map));
3772 memset(&dst_map, 0, sizeof(dst_map));
3774 if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
3776 ERR("Failed to lock the source surface.\n");
3777 wined3d_surface_decref(ret);
3780 if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
3782 ERR("Failed to lock the destination surface.\n");
3783 wined3d_surface_unmap(source);
3784 wined3d_surface_decref(ret);
3788 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
3789 source->resource.width, source->resource.height);
3791 wined3d_surface_unmap(ret);
3792 wined3d_surface_unmap(source);
3797 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
3798 unsigned int bpp, UINT pitch, DWORD color)
3805 #define COLORFILL_ROW(type) \
3807 type *d = (type *)buf; \
3808 for (x = 0; x < width; ++x) \
3809 d[x] = (type)color; \
3815 COLORFILL_ROW(BYTE);
3819 COLORFILL_ROW(WORD);
3825 for (x = 0; x < width; ++x, d += 3)
3827 d[0] = (color ) & 0xFF;
3828 d[1] = (color >> 8) & 0xFF;
3829 d[2] = (color >> 16) & 0xFF;
3834 COLORFILL_ROW(DWORD);
3838 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
3839 return WINED3DERR_NOTAVAILABLE;
3842 #undef COLORFILL_ROW
3844 /* Now copy first row. */
3846 for (y = 1; y < height; ++y)
3849 memcpy(buf, first, width * bpp);
3855 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
3857 TRACE("surface %p.\n", surface);
3859 if (!surface->resource.map_count)
3861 WARN("Trying to unmap unmapped surface.\n");
3862 return WINEDDERR_NOTLOCKED;
3864 --surface->resource.map_count;
3866 surface->surface_ops->surface_unmap(surface);
3871 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
3872 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
3874 const struct wined3d_format *format = surface->resource.format;
3876 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
3877 surface, map_desc, wine_dbgstr_rect(rect), flags);
3879 if (surface->resource.map_count)
3881 WARN("Surface is already mapped.\n");
3882 return WINED3DERR_INVALIDCALL;
3885 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
3886 && !surface_check_block_align(surface, rect))
3888 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
3889 wine_dbgstr_rect(rect), format->block_width, format->block_height);
3891 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
3892 return WINED3DERR_INVALIDCALL;
3895 ++surface->resource.map_count;
3897 if (!(surface->flags & SFLAG_LOCKABLE))
3898 WARN("Trying to lock unlockable surface.\n");
3900 /* Performance optimization: Count how often a surface is mapped, if it is
3901 * mapped regularly do not throw away the system memory copy. This avoids
3902 * the need to download the surface from OpenGL all the time. The surface
3903 * is still downloaded if the OpenGL texture is changed. */
3904 if (!(surface->flags & SFLAG_DYNLOCK))
3906 if (++surface->lockCount > MAXLOCKCOUNT)
3908 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3909 surface->flags |= SFLAG_DYNLOCK;
3913 surface->surface_ops->surface_map(surface, rect, flags);
3915 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
3916 map_desc->row_pitch = surface->resource.width * format->byte_count;
3918 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
3919 map_desc->slice_pitch = 0;
3923 map_desc->data = surface->resource.allocatedMemory;
3924 surface->lockedRect.left = 0;
3925 surface->lockedRect.top = 0;
3926 surface->lockedRect.right = surface->resource.width;
3927 surface->lockedRect.bottom = surface->resource.height;
3931 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
3933 /* Compressed textures are block based, so calculate the offset of
3934 * the block that contains the top-left pixel of the locked rectangle. */
3935 map_desc->data = surface->resource.allocatedMemory
3936 + ((rect->top / format->block_height) * map_desc->row_pitch)
3937 + ((rect->left / format->block_width) * format->block_byte_count);
3941 map_desc->data = surface->resource.allocatedMemory
3942 + (map_desc->row_pitch * rect->top)
3943 + (rect->left * format->byte_count);
3945 surface->lockedRect.left = rect->left;
3946 surface->lockedRect.top = rect->top;
3947 surface->lockedRect.right = rect->right;
3948 surface->lockedRect.bottom = rect->bottom;
3951 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3952 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
3957 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
3959 struct wined3d_map_desc map;
3962 TRACE("surface %p, dc %p.\n", surface, dc);
3964 if (surface->flags & SFLAG_USERPTR)
3966 ERR("Not supported on surfaces with application-provided memory.\n");
3967 return WINEDDERR_NODC;
3970 /* Give more detailed info for ddraw. */
3971 if (surface->flags & SFLAG_DCINUSE)
3972 return WINEDDERR_DCALREADYCREATED;
3974 /* Can't GetDC if the surface is locked. */
3975 if (surface->resource.map_count)
3976 return WINED3DERR_INVALIDCALL;
3978 /* Create a DIB section if there isn't a dc yet. */
3981 if (surface->flags & SFLAG_CLIENT)
3983 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3984 surface_release_client_storage(surface);
3986 hr = surface_create_dib_section(surface);
3988 return WINED3DERR_INVALIDCALL;
3990 /* Use the DIB section from now on if we are not using a PBO. */
3991 if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
3993 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3994 surface->resource.heapMemory = NULL;
3995 surface->resource.allocatedMemory = surface->dib.bitmap_data;
3999 /* Map the surface. */
4000 hr = wined3d_surface_map(surface, &map, NULL, 0);
4003 ERR("Map failed, hr %#x.\n", hr);
4007 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4008 * activates the allocatedMemory. */
4009 if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4010 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4012 if (surface->resource.format->id == WINED3DFMT_P8_UINT
4013 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4015 /* GetDC on palettized formats is unsupported in D3D9, and the method
4016 * is missing in D3D8, so this should only be used for DX <=7
4017 * surfaces (with non-device palettes). */
4018 const PALETTEENTRY *pal = NULL;
4020 if (surface->palette)
4022 pal = surface->palette->palents;
4026 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4027 struct wined3d_surface *dds_primary = swapchain->front_buffer;
4029 if (dds_primary && dds_primary->palette)
4030 pal = dds_primary->palette->palents;
4038 for (i = 0; i < 256; ++i)
4040 col[i].rgbRed = pal[i].peRed;
4041 col[i].rgbGreen = pal[i].peGreen;
4042 col[i].rgbBlue = pal[i].peBlue;
4043 col[i].rgbReserved = 0;
4045 SetDIBColorTable(surface->hDC, 0, 256, col);
4049 surface->flags |= SFLAG_DCINUSE;
4052 TRACE("Returning dc %p.\n", *dc);
4057 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4059 TRACE("surface %p, dc %p.\n", surface, dc);
4061 if (!(surface->flags & SFLAG_DCINUSE))
4062 return WINEDDERR_NODC;
4064 if (surface->hDC != dc)
4066 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4068 return WINEDDERR_NODC;
4071 /* Copy the contents of the DIB over to the PBO. */
4072 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4073 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4075 /* We locked first, so unlock now. */
4076 wined3d_surface_unmap(surface);
4078 surface->flags &= ~SFLAG_DCINUSE;
4083 HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4085 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4091 FIXME("Ignoring flags %#x.\n", flags);
4093 WARN("Ignoring flags %#x.\n", flags);
4096 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
4098 ERR("Not supported on swapchain surfaces.\n");
4099 return WINEDDERR_NOTFLIPPABLE;
4102 /* Flipping is only supported on render targets and overlays. */
4103 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
4105 WARN("Tried to flip a non-render target, non-overlay surface.\n");
4106 return WINEDDERR_NOTFLIPPABLE;
4109 flip_surface(surface, override);
4111 /* Update overlays if they're visible. */
4112 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4113 return surface_draw_overlay(surface);
4118 /* Do not call while under the GL lock. */
4119 void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4121 struct wined3d_device *device = surface->resource.device;
4123 TRACE("iface %p, srgb %#x.\n", surface, srgb);
4125 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4127 struct wined3d_texture *texture = surface->container.u.texture;
4129 TRACE("Passing to container (%p).\n", texture);
4130 texture->texture_ops->texture_preload(texture, srgb);
4134 struct wined3d_context *context;
4136 TRACE("(%p) : About to load surface\n", surface);
4138 /* TODO: Use already acquired context when possible. */
4139 context = context_acquire(device, NULL);
4141 surface_load(surface, srgb == SRGB_SRGB ? TRUE : FALSE);
4143 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4145 /* Tell opengl to try and keep this texture in video ram (well mostly) */
4149 glPrioritizeTextures(1, &surface->texture_name, &tmp);
4153 context_release(context);
4157 /* Read the framebuffer back into the surface */
4158 static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4160 struct wined3d_device *device = surface->resource.device;
4161 const struct wined3d_gl_info *gl_info;
4162 struct wined3d_context *context;
4166 BYTE *row, *top, *bottom;
4170 BOOL srcIsUpsideDown;
4175 context = context_acquire(device, surface);
4176 context_apply_blit_state(context, device);
4177 gl_info = context->gl_info;
4181 /* Select the correct read buffer, and give some debug output.
4182 * There is no need to keep track of the current read buffer or reset it, every part of the code
4183 * that reads sets the read buffer as desired.
4185 if (surface_is_offscreen(surface))
4187 /* Mapping the primary render target which is not on a swapchain.
4188 * Read from the back buffer. */
4189 TRACE("Mapping offscreen render target.\n");
4190 glReadBuffer(device->offscreenBuffer);
4191 srcIsUpsideDown = TRUE;
4195 /* Onscreen surfaces are always part of a swapchain */
4196 GLenum buffer = surface_get_gl_buffer(surface);
4197 TRACE("Mapping %#x buffer.\n", buffer);
4198 glReadBuffer(buffer);
4199 checkGLcall("glReadBuffer");
4200 srcIsUpsideDown = FALSE;
4203 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4206 local_rect.left = 0;
4208 local_rect.right = surface->resource.width;
4209 local_rect.bottom = surface->resource.height;
4215 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4217 switch (surface->resource.format->id)
4219 case WINED3DFMT_P8_UINT:
4221 if (primary_render_target_is_p8(device))
4223 /* In case of P8 render targets the index is stored in the alpha component */
4225 type = GL_UNSIGNED_BYTE;
4227 bpp = surface->resource.format->byte_count;
4231 /* GL can't return palettized data, so read ARGB pixels into a
4232 * separate block of memory and convert them into palettized format
4233 * in software. Slow, but if the app means to use palettized render
4234 * targets and locks it...
4236 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4237 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4238 * for the color channels when palettizing the colors.
4241 type = GL_UNSIGNED_BYTE;
4243 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4246 ERR("Out of memory\n");
4250 bpp = surface->resource.format->byte_count * 3;
4257 fmt = surface->resource.format->glFormat;
4258 type = surface->resource.format->glType;
4259 bpp = surface->resource.format->byte_count;
4262 if (surface->flags & SFLAG_PBO)
4264 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4265 checkGLcall("glBindBufferARB");
4268 ERR("mem not null for pbo -- unexpected\n");
4273 /* Save old pixel store pack state */
4274 glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4275 checkGLcall("glGetIntegerv");
4276 glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4277 checkGLcall("glGetIntegerv");
4278 glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4279 checkGLcall("glGetIntegerv");
4281 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4282 glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4283 checkGLcall("glPixelStorei");
4284 glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4285 checkGLcall("glPixelStorei");
4286 glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4287 checkGLcall("glPixelStorei");
4289 glReadPixels(local_rect.left, !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4290 local_rect.right - local_rect.left,
4291 local_rect.bottom - local_rect.top,
4293 checkGLcall("glReadPixels");
4295 /* Reset previous pixel store pack state */
4296 glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4297 checkGLcall("glPixelStorei");
4298 glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4299 checkGLcall("glPixelStorei");
4300 glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4301 checkGLcall("glPixelStorei");
4303 if (surface->flags & SFLAG_PBO)
4305 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4306 checkGLcall("glBindBufferARB");
4308 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4309 * to get a pointer to it and perform the flipping in software. This is a lot
4310 * faster than calling glReadPixels for each line. In case we want more speed
4311 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4312 if (!srcIsUpsideDown)
4314 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4315 checkGLcall("glBindBufferARB");
4317 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4318 checkGLcall("glMapBufferARB");
4322 /* TODO: Merge this with the palettization loop below for P8 targets */
4323 if(!srcIsUpsideDown) {
4325 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4326 Flip the lines in software */
4327 len = (local_rect.right - local_rect.left) * bpp;
4328 off = local_rect.left * bpp;
4330 row = HeapAlloc(GetProcessHeap(), 0, len);
4332 ERR("Out of memory\n");
4333 if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4334 HeapFree(GetProcessHeap(), 0, mem);
4339 top = mem + pitch * local_rect.top;
4340 bottom = mem + pitch * (local_rect.bottom - 1);
4341 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4342 memcpy(row, top + off, len);
4343 memcpy(top + off, bottom + off, len);
4344 memcpy(bottom + off, row, len);
4348 HeapFree(GetProcessHeap(), 0, row);
4350 /* Unmap the temp PBO buffer */
4351 if (surface->flags & SFLAG_PBO)
4353 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4354 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4359 context_release(context);
4361 /* For P8 textures we need to perform an inverse palette lookup. This is
4362 * done by searching for a palette index which matches the RGB value.
4363 * Note this isn't guaranteed to work when there are multiple entries for
4364 * the same color but we have no choice. In case of P8 render targets,
4365 * the index is stored in the alpha component so no conversion is needed. */
4366 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4368 const PALETTEENTRY *pal = NULL;
4369 DWORD width = pitch / 3;
4372 if (surface->palette)
4374 pal = surface->palette->palents;
4378 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4379 HeapFree(GetProcessHeap(), 0, mem);
4383 for(y = local_rect.top; y < local_rect.bottom; y++) {
4384 for(x = local_rect.left; x < local_rect.right; x++) {
4385 /* start lines pixels */
4386 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4387 const BYTE *green = blue + 1;
4388 const BYTE *red = green + 1;
4390 for(c = 0; c < 256; c++) {
4391 if(*red == pal[c].peRed &&
4392 *green == pal[c].peGreen &&
4393 *blue == pal[c].peBlue)
4395 *((BYTE *) dest + y * width + x) = c;
4401 HeapFree(GetProcessHeap(), 0, mem);
4405 /* Read the framebuffer contents into a texture. Note that this function
4406 * doesn't do any kind of flipping. Using this on an onscreen surface will
4407 * result in a flipped D3D texture. */
4408 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4410 struct wined3d_device *device = surface->resource.device;
4411 struct wined3d_context *context;
4413 context = context_acquire(device, surface);
4414 device_invalidate_state(device, STATE_FRAMEBUFFER);
4416 surface_prepare_texture(surface, context, srgb);
4417 surface_bind_and_dirtify(surface, context, srgb);
4419 TRACE("Reading back offscreen render target %p.\n", surface);
4423 if (surface_is_offscreen(surface))
4424 glReadBuffer(device->offscreenBuffer);
4426 glReadBuffer(surface_get_gl_buffer(surface));
4427 checkGLcall("glReadBuffer");
4429 glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4430 0, 0, 0, 0, surface->resource.width, surface->resource.height);
4431 checkGLcall("glCopyTexSubImage2D");
4435 context_release(context);
4438 /* Context activation is done by the caller. */
4439 static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4440 struct wined3d_context *context, BOOL srgb)
4442 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4443 enum wined3d_conversion_type convert;
4444 struct wined3d_format format;
4446 if (surface->flags & alloc_flag) return;
4448 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4449 if (convert != WINED3D_CT_NONE || format.convert)
4450 surface->flags |= SFLAG_CONVERTED;
4451 else surface->flags &= ~SFLAG_CONVERTED;
4453 surface_bind_and_dirtify(surface, context, srgb);
4454 surface_allocate_surface(surface, context->gl_info, &format, srgb);
4455 surface->flags |= alloc_flag;
4458 /* Context activation is done by the caller. */
4459 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4461 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4463 struct wined3d_texture *texture = surface->container.u.texture;
4464 UINT sub_count = texture->level_count * texture->layer_count;
4467 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4469 for (i = 0; i < sub_count; ++i)
4471 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4472 surface_prepare_texture_internal(s, context, srgb);
4478 surface_prepare_texture_internal(surface, context, srgb);
4481 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4485 if (surface->rb_multisample)
4488 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4489 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4490 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4491 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4492 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4496 if (surface->rb_resolved)
4499 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4500 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4501 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4502 surface->pow2Width, surface->pow2Height);
4503 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4507 static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4508 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4510 struct wined3d_device *device = surface->resource.device;
4511 UINT pitch = wined3d_surface_get_pitch(surface);
4512 const struct wined3d_gl_info *gl_info;
4513 struct wined3d_context *context;
4517 surface_get_rect(surface, rect, &local_rect);
4519 mem += local_rect.top * pitch + local_rect.left * bpp;
4520 w = local_rect.right - local_rect.left;
4521 h = local_rect.bottom - local_rect.top;
4523 /* Activate the correct context for the render target */
4524 context = context_acquire(device, surface);
4525 context_apply_blit_state(context, device);
4526 gl_info = context->gl_info;
4530 if (!surface_is_offscreen(surface))
4532 GLenum buffer = surface_get_gl_buffer(surface);
4533 TRACE("Unlocking %#x buffer.\n", buffer);
4534 context_set_draw_buffer(context, buffer);
4536 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4537 glPixelZoom(1.0f, -1.0f);
4541 /* Primary offscreen render target */
4542 TRACE("Offscreen render target.\n");
4543 context_set_draw_buffer(context, device->offscreenBuffer);
4545 glPixelZoom(1.0f, 1.0f);
4548 glRasterPos3i(local_rect.left, local_rect.top, 1);
4549 checkGLcall("glRasterPos3i");
4551 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4552 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4554 if (surface->flags & SFLAG_PBO)
4556 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4557 checkGLcall("glBindBufferARB");
4560 glDrawPixels(w, h, fmt, type, mem);
4561 checkGLcall("glDrawPixels");
4563 if (surface->flags & SFLAG_PBO)
4565 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4566 checkGLcall("glBindBufferARB");
4569 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4570 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4574 if (wined3d_settings.strict_draw_ordering
4575 || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4576 && surface->container.u.swapchain->front_buffer == surface))
4579 context_release(context);
4582 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4584 /* FIXME: Is this really how color keys are supposed to work? I think it
4585 * makes more sense to compare the individual channels. */
4586 return color >= color_key->color_space_low_value
4587 && color <= color_key->color_space_high_value;
4590 void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4592 const struct wined3d_device *device = surface->resource.device;
4593 const struct wined3d_palette *pal = surface->palette;
4594 BOOL index_in_alpha = FALSE;
4597 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4598 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4599 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4600 * duplicate entries. Store the color key in the unused alpha component to speed the
4601 * download up and to make conversion unneeded. */
4602 index_in_alpha = primary_render_target_is_p8(device);
4606 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4609 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4610 * there's no palette at this time. */
4611 for (i = 0; i < 256; i++) table[i][3] = i;
4616 TRACE("Using surface palette %p\n", pal);
4617 /* Get the surface's palette */
4618 for (i = 0; i < 256; ++i)
4620 table[i][0] = pal->palents[i].peRed;
4621 table[i][1] = pal->palents[i].peGreen;
4622 table[i][2] = pal->palents[i].peBlue;
4624 /* When index_in_alpha is set the palette index is stored in the
4625 * alpha component. In case of a readback we can then read
4626 * GL_ALPHA. Color keying is handled in BltOverride using a
4627 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4628 * color key itself is passed to glAlphaFunc in other cases the
4629 * alpha component of pixels that should be masked away is set to 0. */
4632 else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4634 else if (pal->flags & WINEDDPCAPS_ALPHA)
4635 table[i][3] = pal->palents[i].peFlags;
4642 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4643 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4648 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4649 src, dst, pitch, width, height, outpitch, conversion_type, surface);
4651 switch (conversion_type)
4653 case WINED3D_CT_NONE:
4655 memcpy(dst, src, pitch * height);
4659 case WINED3D_CT_PALETTED:
4660 case WINED3D_CT_PALETTED_CK:
4665 d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4667 for (y = 0; y < height; y++)
4669 source = src + pitch * y;
4670 dest = dst + outpitch * y;
4671 /* This is an 1 bpp format, using the width here is fine */
4672 for (x = 0; x < width; x++) {
4673 BYTE color = *source++;
4674 *dest++ = table[color][0];
4675 *dest++ = table[color][1];
4676 *dest++ = table[color][2];
4677 *dest++ = table[color][3];
4683 case WINED3D_CT_CK_565:
4685 /* Converting the 565 format in 5551 packed to emulate color-keying.
4687 Note : in all these conversion, it would be best to average the averaging
4688 pixels to get the color of the pixel that will be color-keyed to
4689 prevent 'color bleeding'. This will be done later on if ever it is
4692 Note2: Nvidia documents say that their driver does not support alpha + color keying
4693 on the same surface and disables color keying in such a case
4699 TRACE("Color keyed 565\n");
4701 for (y = 0; y < height; y++) {
4702 Source = (const WORD *)(src + y * pitch);
4703 Dest = (WORD *) (dst + y * outpitch);
4704 for (x = 0; x < width; x++ ) {
4705 WORD color = *Source++;
4706 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
4707 if (!color_in_range(&surface->src_blt_color_key, color))
4715 case WINED3D_CT_CK_5551:
4717 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4721 TRACE("Color keyed 5551\n");
4722 for (y = 0; y < height; y++) {
4723 Source = (const WORD *)(src + y * pitch);
4724 Dest = (WORD *) (dst + y * outpitch);
4725 for (x = 0; x < width; x++ ) {
4726 WORD color = *Source++;
4728 if (!color_in_range(&surface->src_blt_color_key, color))
4731 *Dest &= ~(1 << 15);
4738 case WINED3D_CT_CK_RGB24:
4740 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4742 for (y = 0; y < height; y++)
4744 source = src + pitch * y;
4745 dest = dst + outpitch * y;
4746 for (x = 0; x < width; x++) {
4747 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4748 DWORD dstcolor = color << 8;
4749 if (!color_in_range(&surface->src_blt_color_key, color))
4751 *(DWORD*)dest = dstcolor;
4759 case WINED3D_CT_RGB32_888:
4761 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4763 for (y = 0; y < height; y++)
4765 source = src + pitch * y;
4766 dest = dst + outpitch * y;
4767 for (x = 0; x < width; x++) {
4768 DWORD color = 0xffffff & *(const DWORD*)source;
4769 DWORD dstcolor = color << 8;
4770 if (!color_in_range(&surface->src_blt_color_key, color))
4772 *(DWORD*)dest = dstcolor;
4780 case WINED3D_CT_CK_ARGB32:
4783 for (y = 0; y < height; ++y)
4785 source = src + pitch * y;
4786 dest = dst + outpitch * y;
4787 for (x = 0; x < width; ++x)
4789 DWORD color = *(const DWORD *)source;
4790 if (color_in_range(&surface->src_blt_color_key, color))
4791 color &= ~0xff000000;
4792 *(DWORD*)dest = color;
4801 ERR("Unsupported conversion type %#x.\n", conversion_type);
4806 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
4808 /* Flip the surface contents */
4813 front->hDC = back->hDC;
4817 /* Flip the DIBsection */
4819 HBITMAP tmp = front->dib.DIBsection;
4820 front->dib.DIBsection = back->dib.DIBsection;
4821 back->dib.DIBsection = tmp;
4824 /* Flip the surface data */
4828 tmp = front->dib.bitmap_data;
4829 front->dib.bitmap_data = back->dib.bitmap_data;
4830 back->dib.bitmap_data = tmp;
4832 tmp = front->resource.allocatedMemory;
4833 front->resource.allocatedMemory = back->resource.allocatedMemory;
4834 back->resource.allocatedMemory = tmp;
4836 tmp = front->resource.heapMemory;
4837 front->resource.heapMemory = back->resource.heapMemory;
4838 back->resource.heapMemory = tmp;
4843 GLuint tmp_pbo = front->pbo;
4844 front->pbo = back->pbo;
4845 back->pbo = tmp_pbo;
4848 /* Flip the opengl texture */
4852 tmp = back->texture_name;
4853 back->texture_name = front->texture_name;
4854 front->texture_name = tmp;
4856 tmp = back->texture_name_srgb;
4857 back->texture_name_srgb = front->texture_name_srgb;
4858 front->texture_name_srgb = tmp;
4860 tmp = back->rb_multisample;
4861 back->rb_multisample = front->rb_multisample;
4862 front->rb_multisample = tmp;
4864 tmp = back->rb_resolved;
4865 back->rb_resolved = front->rb_resolved;
4866 front->rb_resolved = tmp;
4868 resource_unload(&back->resource);
4869 resource_unload(&front->resource);
4873 DWORD tmp_flags = back->flags;
4874 back->flags = front->flags;
4875 front->flags = tmp_flags;
4879 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4880 * pixel copy calls. */
4881 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
4882 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
4884 struct wined3d_device *device = dst_surface->resource.device;
4887 struct wined3d_context *context;
4888 BOOL upsidedown = FALSE;
4889 RECT dst_rect = *dst_rect_in;
4891 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4892 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4894 if(dst_rect.top > dst_rect.bottom) {
4895 UINT tmp = dst_rect.bottom;
4896 dst_rect.bottom = dst_rect.top;
4901 context = context_acquire(device, src_surface);
4902 context_apply_blit_state(context, device);
4903 surface_internal_preload(dst_surface, SRGB_RGB);
4906 /* Bind the target texture */
4907 context_bind_texture(context, dst_surface->texture_target, dst_surface->texture_name);
4908 if (surface_is_offscreen(src_surface))
4910 TRACE("Reading from an offscreen target\n");
4911 upsidedown = !upsidedown;
4912 glReadBuffer(device->offscreenBuffer);
4916 glReadBuffer(surface_get_gl_buffer(src_surface));
4918 checkGLcall("glReadBuffer");
4920 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
4921 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
4923 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4925 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4927 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4928 ERR("Texture filtering not supported in direct blit.\n");
4930 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4931 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4933 ERR("Texture filtering not supported in direct blit\n");
4937 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4938 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4940 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
4942 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4943 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
4944 src_rect->left, src_surface->resource.height - src_rect->bottom,
4945 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4949 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
4950 /* I have to process this row by row to swap the image,
4951 * otherwise it would be upside down, so stretching in y direction
4952 * doesn't cost extra time
4954 * However, stretching in x direction can be avoided if not necessary
4956 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
4957 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4959 /* Well, that stuff works, but it's very slow.
4960 * find a better way instead
4964 for (col = dst_rect.left; col < dst_rect.right; ++col)
4966 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4967 dst_rect.left + col /* x offset */, row /* y offset */,
4968 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
4973 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4974 dst_rect.left /* x offset */, row /* y offset */,
4975 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
4979 checkGLcall("glCopyTexSubImage2D");
4982 context_release(context);
4984 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
4985 * path is never entered
4987 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
4990 /* Uses the hardware to stretch and flip the image */
4991 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
4992 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
4994 struct wined3d_device *device = dst_surface->resource.device;
4995 struct wined3d_swapchain *src_swapchain = NULL;
4996 GLuint src, backup = 0;
4997 float left, right, top, bottom; /* Texture coordinates */
4998 UINT fbwidth = src_surface->resource.width;
4999 UINT fbheight = src_surface->resource.height;
5000 struct wined3d_context *context;
5001 GLenum drawBuffer = GL_BACK;
5002 GLenum texture_target;
5003 BOOL noBackBufferBackup;
5005 BOOL upsidedown = FALSE;
5006 RECT dst_rect = *dst_rect_in;
5008 TRACE("Using hwstretch blit\n");
5009 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5010 context = context_acquire(device, src_surface);
5011 context_apply_blit_state(context, device);
5012 surface_internal_preload(dst_surface, SRGB_RGB);
5014 src_offscreen = surface_is_offscreen(src_surface);
5015 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5016 if (!noBackBufferBackup && !src_surface->texture_name)
5018 /* Get it a description */
5019 surface_internal_preload(src_surface, SRGB_RGB);
5023 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5024 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5026 if (context->aux_buffers >= 2)
5028 /* Got more than one aux buffer? Use the 2nd aux buffer */
5029 drawBuffer = GL_AUX1;
5031 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5033 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5034 drawBuffer = GL_AUX0;
5037 if(noBackBufferBackup) {
5038 glGenTextures(1, &backup);
5039 checkGLcall("glGenTextures");
5040 context_bind_texture(context, GL_TEXTURE_2D, backup);
5041 texture_target = GL_TEXTURE_2D;
5043 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5044 * we are reading from the back buffer, the backup can be used as source texture
5046 texture_target = src_surface->texture_target;
5047 context_bind_texture(context, texture_target, src_surface->texture_name);
5048 glEnable(texture_target);
5049 checkGLcall("glEnable(texture_target)");
5051 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5052 src_surface->flags &= ~SFLAG_INTEXTURE;
5055 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5056 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5058 if(dst_rect.top > dst_rect.bottom) {
5059 UINT tmp = dst_rect.bottom;
5060 dst_rect.bottom = dst_rect.top;
5067 TRACE("Reading from an offscreen target\n");
5068 upsidedown = !upsidedown;
5069 glReadBuffer(device->offscreenBuffer);
5073 glReadBuffer(surface_get_gl_buffer(src_surface));
5076 /* TODO: Only back up the part that will be overwritten */
5077 glCopyTexSubImage2D(texture_target, 0,
5078 0, 0 /* read offsets */,
5083 checkGLcall("glCopyTexSubImage2D");
5085 /* No issue with overriding these - the sampler is dirty due to blit usage */
5086 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5087 wined3d_gl_mag_filter(magLookup, filter));
5088 checkGLcall("glTexParameteri");
5089 glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5090 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5091 checkGLcall("glTexParameteri");
5093 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5094 src_swapchain = src_surface->container.u.swapchain;
5095 if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
5097 src = backup ? backup : src_surface->texture_name;
5101 glReadBuffer(GL_FRONT);
5102 checkGLcall("glReadBuffer(GL_FRONT)");
5104 glGenTextures(1, &src);
5105 checkGLcall("glGenTextures(1, &src)");
5106 context_bind_texture(context, GL_TEXTURE_2D, src);
5108 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5109 * out for power of 2 sizes
5111 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5112 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5113 checkGLcall("glTexImage2D");
5114 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
5115 0, 0 /* read offsets */,
5120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5121 checkGLcall("glTexParameteri");
5122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5123 checkGLcall("glTexParameteri");
5125 glReadBuffer(GL_BACK);
5126 checkGLcall("glReadBuffer(GL_BACK)");
5128 if(texture_target != GL_TEXTURE_2D) {
5129 glDisable(texture_target);
5130 glEnable(GL_TEXTURE_2D);
5131 texture_target = GL_TEXTURE_2D;
5134 checkGLcall("glEnd and previous");
5136 left = src_rect->left;
5137 right = src_rect->right;
5141 top = src_surface->resource.height - src_rect->top;
5142 bottom = src_surface->resource.height - src_rect->bottom;
5146 top = src_surface->resource.height - src_rect->bottom;
5147 bottom = src_surface->resource.height - src_rect->top;
5150 if (src_surface->flags & SFLAG_NORMCOORD)
5152 left /= src_surface->pow2Width;
5153 right /= src_surface->pow2Width;
5154 top /= src_surface->pow2Height;
5155 bottom /= src_surface->pow2Height;
5158 /* draw the source texture stretched and upside down. The correct surface is bound already */
5159 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5160 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5162 context_set_draw_buffer(context, drawBuffer);
5163 glReadBuffer(drawBuffer);
5167 glTexCoord2f(left, bottom);
5171 glTexCoord2f(left, top);
5172 glVertex2i(0, dst_rect.bottom - dst_rect.top);
5175 glTexCoord2f(right, top);
5176 glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5179 glTexCoord2f(right, bottom);
5180 glVertex2i(dst_rect.right - dst_rect.left, 0);
5182 checkGLcall("glEnd and previous");
5184 if (texture_target != dst_surface->texture_target)
5186 glDisable(texture_target);
5187 glEnable(dst_surface->texture_target);
5188 texture_target = dst_surface->texture_target;
5191 /* Now read the stretched and upside down image into the destination texture */
5192 context_bind_texture(context, texture_target, dst_surface->texture_name);
5193 glCopyTexSubImage2D(texture_target,
5195 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5196 0, 0, /* We blitted the image to the origin */
5197 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5198 checkGLcall("glCopyTexSubImage2D");
5200 if(drawBuffer == GL_BACK) {
5201 /* Write the back buffer backup back */
5203 if(texture_target != GL_TEXTURE_2D) {
5204 glDisable(texture_target);
5205 glEnable(GL_TEXTURE_2D);
5206 texture_target = GL_TEXTURE_2D;
5208 context_bind_texture(context, GL_TEXTURE_2D, backup);
5212 if (texture_target != src_surface->texture_target)
5214 glDisable(texture_target);
5215 glEnable(src_surface->texture_target);
5216 texture_target = src_surface->texture_target;
5218 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5223 glTexCoord2f(0.0f, 0.0f);
5224 glVertex2i(0, fbheight);
5227 glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5231 glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5232 (float)fbheight / (float)src_surface->pow2Height);
5233 glVertex2i(fbwidth, 0);
5236 glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5237 glVertex2i(fbwidth, fbheight);
5240 glDisable(texture_target);
5241 checkGLcall("glDisable(texture_target)");
5244 if (src != src_surface->texture_name && src != backup)
5246 glDeleteTextures(1, &src);
5247 checkGLcall("glDeleteTextures(1, &src)");
5250 glDeleteTextures(1, &backup);
5251 checkGLcall("glDeleteTextures(1, &backup)");
5256 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5258 context_release(context);
5260 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5261 * path is never entered
5263 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5266 /* Front buffer coordinates are always full screen coordinates, but our GL
5267 * drawable is limited to the window's client area. The sysmem and texture
5268 * copies do have the full screen size. Note that GL has a bottom-left
5269 * origin, while D3D has a top-left origin. */
5270 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5272 UINT drawable_height;
5274 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5275 && surface == surface->container.u.swapchain->front_buffer)
5277 POINT offset = {0, 0};
5280 ScreenToClient(window, &offset);
5281 OffsetRect(rect, offset.x, offset.y);
5283 GetClientRect(window, &windowsize);
5284 drawable_height = windowsize.bottom - windowsize.top;
5288 drawable_height = surface->resource.height;
5291 rect->top = drawable_height - rect->top;
5292 rect->bottom = drawable_height - rect->bottom;
5295 static void surface_blt_to_drawable(const struct wined3d_device *device,
5296 enum wined3d_texture_filter_type filter, BOOL color_key,
5297 struct wined3d_surface *src_surface, const RECT *src_rect_in,
5298 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5300 struct wined3d_context *context;
5301 RECT src_rect, dst_rect;
5303 src_rect = *src_rect_in;
5304 dst_rect = *dst_rect_in;
5306 /* Make sure the surface is up-to-date. This should probably use
5307 * surface_load_location() and worry about the destination surface too,
5308 * unless we're overwriting it completely. */
5309 surface_internal_preload(src_surface, SRGB_RGB);
5311 /* Activate the destination context, set it up for blitting */
5312 context = context_acquire(device, dst_surface);
5313 context_apply_blit_state(context, device);
5315 if (!surface_is_offscreen(dst_surface))
5316 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5318 device->blitter->set_shader(device->blit_priv, context, src_surface);
5324 glEnable(GL_ALPHA_TEST);
5325 checkGLcall("glEnable(GL_ALPHA_TEST)");
5327 /* When the primary render target uses P8, the alpha component
5328 * contains the palette index. Which means that the colorkey is one of
5329 * the palette entries. In other cases pixels that should be masked
5330 * away have alpha set to 0. */
5331 if (primary_render_target_is_p8(device))
5332 glAlphaFunc(GL_NOTEQUAL, (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5334 glAlphaFunc(GL_NOTEQUAL, 0.0f);
5335 checkGLcall("glAlphaFunc");
5339 glDisable(GL_ALPHA_TEST);
5340 checkGLcall("glDisable(GL_ALPHA_TEST)");
5343 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5347 glDisable(GL_ALPHA_TEST);
5348 checkGLcall("glDisable(GL_ALPHA_TEST)");
5353 /* Leave the opengl state valid for blitting */
5354 device->blitter->unset_shader(context->gl_info);
5356 if (wined3d_settings.strict_draw_ordering
5357 || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5358 && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5359 wglFlush(); /* Flush to ensure ordering across contexts. */
5361 context_release(context);
5364 /* Do not call while under the GL lock. */
5365 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5367 struct wined3d_device *device = s->resource.device;
5368 const struct blit_shader *blitter;
5370 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5371 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5374 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5375 return WINED3DERR_INVALIDCALL;
5378 return blitter->color_fill(device, s, rect, color);
5381 /* Do not call while under the GL lock. */
5382 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5383 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5384 enum wined3d_texture_filter_type filter)
5386 struct wined3d_device *device = dst_surface->resource.device;
5387 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5388 struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5390 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5391 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5392 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5394 /* Get the swapchain. One of the surfaces has to be a primary surface */
5395 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5397 WARN("Destination is in sysmem, rejecting gl blt\n");
5398 return WINED3DERR_INVALIDCALL;
5401 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5402 dstSwapchain = dst_surface->container.u.swapchain;
5406 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5408 WARN("Src is in sysmem, rejecting gl blt\n");
5409 return WINED3DERR_INVALIDCALL;
5412 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5413 srcSwapchain = src_surface->container.u.swapchain;
5416 /* Early sort out of cases where no render target is used */
5417 if (!dstSwapchain && !srcSwapchain
5418 && src_surface != device->fb.render_targets[0]
5419 && dst_surface != device->fb.render_targets[0])
5421 TRACE("No surface is render target, not using hardware blit.\n");
5422 return WINED3DERR_INVALIDCALL;
5425 /* No destination color keying supported */
5426 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5428 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5429 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5430 return WINED3DERR_INVALIDCALL;
5433 if (dstSwapchain && dstSwapchain == srcSwapchain)
5435 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5436 return WINED3DERR_INVALIDCALL;
5439 if (dstSwapchain && srcSwapchain)
5441 FIXME("Implement hardware blit between two different swapchains\n");
5442 return WINED3DERR_INVALIDCALL;
5447 /* Handled with regular texture -> swapchain blit */
5448 if (src_surface == device->fb.render_targets[0])
5449 TRACE("Blit from active render target to a swapchain\n");
5451 else if (srcSwapchain && dst_surface == device->fb.render_targets[0])
5453 FIXME("Implement blit from a swapchain to the active render target\n");
5454 return WINED3DERR_INVALIDCALL;
5457 if ((srcSwapchain || src_surface == device->fb.render_targets[0]) && !dstSwapchain)
5459 /* Blit from render target to texture */
5462 /* P8 read back is not implemented */
5463 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5464 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5466 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5467 return WINED3DERR_INVALIDCALL;
5470 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5472 TRACE("Color keying not supported by frame buffer to texture blit\n");
5473 return WINED3DERR_INVALIDCALL;
5474 /* Destination color key is checked above */
5477 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5482 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5483 * flip the image nor scale it.
5485 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5486 * -> If the app wants a image width an unscaled width, copy it line per line
5487 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5488 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5489 * back buffer. This is slower than reading line per line, thus not used for flipping
5490 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5491 * pixel by pixel. */
5492 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5493 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5495 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5496 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5500 TRACE("Using hardware stretching to flip / stretch the texture.\n");
5501 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5504 if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5506 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5507 dst_surface->resource.allocatedMemory = NULL;
5508 dst_surface->resource.heapMemory = NULL;
5512 dst_surface->flags &= ~SFLAG_INSYSMEM;
5517 else if (src_surface)
5519 /* Blit from offscreen surface to render target */
5520 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5521 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5523 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5525 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5526 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5527 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5529 FIXME("Unsupported blit operation falling back to software\n");
5530 return WINED3DERR_INVALIDCALL;
5533 /* Color keying: Check if we have to do a color keyed blt,
5534 * and if not check if a color key is activated.
5536 * Just modify the color keying parameters in the surface and restore them afterwards
5537 * The surface keeps track of the color key last used to load the opengl surface.
5538 * PreLoad will catch the change to the flags and color key and reload if necessary.
5540 if (flags & WINEDDBLT_KEYSRC)
5542 /* Use color key from surface */
5544 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5546 /* Use color key from DDBltFx */
5547 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5548 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5552 /* Do not use color key */
5553 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5556 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5557 src_surface, src_rect, dst_surface, dst_rect);
5559 /* Restore the color key parameters */
5560 src_surface->CKeyFlags = oldCKeyFlags;
5561 src_surface->src_blt_color_key = old_blt_key;
5563 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5568 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5569 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5570 return WINED3DERR_INVALIDCALL;
5573 /* GL locking is done by the caller */
5574 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5575 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5577 struct wined3d_device *device = surface->resource.device;
5578 const struct wined3d_gl_info *gl_info = context->gl_info;
5579 GLint compare_mode = GL_NONE;
5580 struct blt_info info;
5581 GLint old_binding = 0;
5584 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5586 glDisable(GL_CULL_FACE);
5587 glDisable(GL_BLEND);
5588 glDisable(GL_ALPHA_TEST);
5589 glDisable(GL_SCISSOR_TEST);
5590 glDisable(GL_STENCIL_TEST);
5591 glEnable(GL_DEPTH_TEST);
5592 glDepthFunc(GL_ALWAYS);
5593 glDepthMask(GL_TRUE);
5594 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5595 glViewport(x, y, w, h);
5596 glDepthRange(0.0, 1.0);
5598 SetRect(&rect, 0, h, w, 0);
5599 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5600 context_active_texture(context, context->gl_info, 0);
5601 glGetIntegerv(info.binding, &old_binding);
5602 glBindTexture(info.bind_target, texture);
5603 if (gl_info->supported[ARB_SHADOW])
5605 glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5606 if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5609 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5610 gl_info, info.tex_type, &surface->ds_current_size);
5612 glBegin(GL_TRIANGLE_STRIP);
5613 glTexCoord3fv(info.coords[0]);
5614 glVertex2f(-1.0f, -1.0f);
5615 glTexCoord3fv(info.coords[1]);
5616 glVertex2f(1.0f, -1.0f);
5617 glTexCoord3fv(info.coords[2]);
5618 glVertex2f(-1.0f, 1.0f);
5619 glTexCoord3fv(info.coords[3]);
5620 glVertex2f(1.0f, 1.0f);
5623 if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5624 glBindTexture(info.bind_target, old_binding);
5628 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5631 void surface_modify_ds_location(struct wined3d_surface *surface,
5632 DWORD location, UINT w, UINT h)
5634 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5636 if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5637 FIXME("Invalid location (%#x) specified.\n", location);
5639 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5640 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5642 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5644 TRACE("Passing to container.\n");
5645 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5649 surface->ds_current_size.cx = w;
5650 surface->ds_current_size.cy = h;
5651 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5652 surface->flags |= location;
5655 /* Context activation is done by the caller. */
5656 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5658 struct wined3d_device *device = surface->resource.device;
5661 TRACE("surface %p, new location %#x.\n", surface, location);
5663 /* TODO: Make this work for modes other than FBO */
5664 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5666 if (!(surface->flags & location))
5668 w = surface->ds_current_size.cx;
5669 h = surface->ds_current_size.cy;
5670 surface->ds_current_size.cx = 0;
5671 surface->ds_current_size.cy = 0;
5675 w = surface->resource.width;
5676 h = surface->resource.height;
5679 if (surface->ds_current_size.cx == surface->resource.width
5680 && surface->ds_current_size.cy == surface->resource.height)
5682 TRACE("Location (%#x) is already up to date.\n", location);
5686 if (surface->current_renderbuffer)
5688 FIXME("Not supported with fixed up depth stencil.\n");
5692 if (surface->flags & SFLAG_DISCARDED)
5694 TRACE("Surface was discarded, no need copy data.\n");
5697 case SFLAG_INTEXTURE:
5698 surface_prepare_texture(surface, context, FALSE);
5700 case SFLAG_INRB_MULTISAMPLE:
5701 surface_prepare_rb(surface, context->gl_info, TRUE);
5703 case SFLAG_INDRAWABLE:
5707 FIXME("Unhandled location %#x\n", location);
5709 surface->flags &= ~SFLAG_DISCARDED;
5710 surface->flags |= location;
5711 surface->ds_current_size.cx = surface->resource.width;
5712 surface->ds_current_size.cy = surface->resource.height;
5716 if (!(surface->flags & SFLAG_LOCATIONS))
5718 FIXME("No up to date depth stencil location.\n");
5719 surface->flags |= location;
5720 surface->ds_current_size.cx = surface->resource.width;
5721 surface->ds_current_size.cy = surface->resource.height;
5725 if (location == SFLAG_INTEXTURE)
5727 GLint old_binding = 0;
5730 /* The render target is allowed to be smaller than the depth/stencil
5731 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5732 * than the offscreen surface. Don't overwrite the offscreen surface
5733 * with undefined data. */
5734 w = min(w, context->swapchain->desc.backbuffer_width);
5735 h = min(h, context->swapchain->desc.backbuffer_height);
5737 TRACE("Copying onscreen depth buffer to depth texture.\n");
5741 if (!device->depth_blt_texture)
5743 glGenTextures(1, &device->depth_blt_texture);
5746 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5747 * directly on the FBO texture. That's because we need to flip. */
5748 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5749 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5750 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
5752 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5753 bind_target = GL_TEXTURE_RECTANGLE_ARB;
5757 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5758 bind_target = GL_TEXTURE_2D;
5760 glBindTexture(bind_target, device->depth_blt_texture);
5761 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5762 * internal format, because the internal format might include stencil
5763 * data. In principle we should copy stencil data as well, but unless
5764 * the driver supports stencil export it's hard to do, and doesn't
5765 * seem to be needed in practice. If the hardware doesn't support
5766 * writing stencil data, the glCopyTexImage2D() call might trigger
5767 * software fallbacks. */
5768 glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
5769 glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5770 glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5771 glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5772 glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5773 glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
5774 glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5775 glBindTexture(bind_target, old_binding);
5777 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5778 NULL, surface, SFLAG_INTEXTURE);
5779 context_set_draw_buffer(context, GL_NONE);
5780 glReadBuffer(GL_NONE);
5782 /* Do the actual blit */
5783 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
5784 checkGLcall("depth_blt");
5786 context_invalidate_state(context, STATE_FRAMEBUFFER);
5790 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5792 else if (location == SFLAG_INDRAWABLE)
5794 TRACE("Copying depth texture to onscreen depth buffer.\n");
5798 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5799 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5800 surface_depth_blt(surface, context, surface->texture_name,
5801 0, surface->pow2Height - h, w, h, surface->texture_target);
5802 checkGLcall("depth_blt");
5804 context_invalidate_state(context, STATE_FRAMEBUFFER);
5808 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5812 ERR("Invalid location (%#x) specified.\n", location);
5815 surface->flags |= location;
5816 surface->ds_current_size.cx = surface->resource.width;
5817 surface->ds_current_size.cy = surface->resource.height;
5820 void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
5822 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
5823 struct wined3d_surface *overlay;
5825 TRACE("surface %p, location %s, persistent %#x.\n",
5826 surface, debug_surflocation(location), persistent);
5828 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
5829 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
5830 && (location & SFLAG_INDRAWABLE))
5831 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5833 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
5834 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
5835 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
5839 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5840 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
5842 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5844 TRACE("Passing to container.\n");
5845 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5848 surface->flags &= ~SFLAG_LOCATIONS;
5849 surface->flags |= location;
5851 /* Redraw emulated overlays, if any */
5852 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
5854 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
5856 surface_draw_overlay(overlay);
5862 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
5864 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5866 TRACE("Passing to container\n");
5867 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5870 surface->flags &= ~location;
5873 if (!(surface->flags & SFLAG_LOCATIONS))
5875 ERR("Surface %p does not have any up to date location.\n", surface);
5879 static DWORD resource_access_from_location(DWORD location)
5883 case SFLAG_INSYSMEM:
5884 return WINED3D_RESOURCE_ACCESS_CPU;
5886 case SFLAG_INDRAWABLE:
5887 case SFLAG_INSRGBTEX:
5888 case SFLAG_INTEXTURE:
5889 case SFLAG_INRB_MULTISAMPLE:
5890 case SFLAG_INRB_RESOLVED:
5891 return WINED3D_RESOURCE_ACCESS_GPU;
5894 FIXME("Unhandled location %#x.\n", location);
5899 static void surface_load_sysmem(struct wined3d_surface *surface,
5900 const struct wined3d_gl_info *gl_info, const RECT *rect)
5902 surface_prepare_system_memory(surface);
5904 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
5905 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5907 /* Download the surface to system memory. */
5908 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
5910 struct wined3d_device *device = surface->resource.device;
5911 struct wined3d_context *context;
5913 /* TODO: Use already acquired context when possible. */
5914 context = context_acquire(device, NULL);
5916 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
5917 surface_download_data(surface, gl_info);
5919 context_release(context);
5924 if (surface->flags & SFLAG_INDRAWABLE)
5926 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
5927 wined3d_surface_get_pitch(surface));
5931 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
5932 surface, surface->flags & SFLAG_LOCATIONS);
5935 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
5936 const struct wined3d_gl_info *gl_info, const RECT *rect)
5938 struct wined3d_device *device = surface->resource.device;
5939 enum wined3d_conversion_type convert;
5940 struct wined3d_format format;
5944 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
5946 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5947 return WINED3DERR_INVALIDCALL;
5950 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
5951 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5953 if (surface->flags & SFLAG_INTEXTURE)
5957 surface_get_rect(surface, rect, &r);
5958 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
5963 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
5965 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5966 * path through sysmem. */
5967 surface_load_location(surface, SFLAG_INSYSMEM, rect);
5970 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
5972 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
5973 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
5975 if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
5977 struct wined3d_context *context;
5979 TRACE("Removing the pbo attached to surface %p.\n", surface);
5981 /* TODO: Use already acquired context when possible. */
5982 context = context_acquire(device, NULL);
5984 surface_remove_pbo(surface, gl_info);
5986 context_release(context);
5989 if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
5991 UINT height = surface->resource.height;
5992 UINT width = surface->resource.width;
5993 UINT src_pitch, dst_pitch;
5995 byte_count = format.conv_byte_count;
5996 src_pitch = wined3d_surface_get_pitch(surface);
5998 /* Stick to the alignment for the converted surface too, makes it
5999 * easier to load the surface. */
6000 dst_pitch = width * byte_count;
6001 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6003 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6005 ERR("Out of memory (%u).\n", dst_pitch * height);
6006 return E_OUTOFMEMORY;
6009 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6010 src_pitch, width, height, dst_pitch, convert, surface);
6012 surface->flags |= SFLAG_CONVERTED;
6016 surface->flags &= ~SFLAG_CONVERTED;
6017 mem = surface->resource.allocatedMemory;
6018 byte_count = format.byte_count;
6021 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6023 /* Don't delete PBO memory. */
6024 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6025 HeapFree(GetProcessHeap(), 0, mem);
6030 static HRESULT surface_load_texture(struct wined3d_surface *surface,
6031 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6033 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6034 struct wined3d_device *device = surface->resource.device;
6035 enum wined3d_conversion_type convert;
6036 struct wined3d_context *context;
6037 UINT width, src_pitch, dst_pitch;
6038 struct wined3d_bo_address data;
6039 struct wined3d_format format;
6040 POINT dst_point = {0, 0};
6043 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6044 && surface_is_offscreen(surface)
6045 && (surface->flags & SFLAG_INDRAWABLE))
6047 surface_load_fb_texture(surface, srgb);
6052 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6053 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6054 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6055 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6056 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6059 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6060 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6062 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6063 &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6068 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6069 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6070 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6071 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6072 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6074 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6075 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6076 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6078 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6079 &rect, surface, dst_location, &rect);
6084 /* Upload from system memory */
6086 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6087 TRUE /* We will use textures */, &format, &convert);
6091 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6093 /* Performance warning... */
6094 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6095 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6100 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6102 /* Performance warning... */
6103 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6104 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6108 if (!(surface->flags & SFLAG_INSYSMEM))
6110 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6111 /* Lets hope we get it from somewhere... */
6112 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6115 /* TODO: Use already acquired context when possible. */
6116 context = context_acquire(device, NULL);
6118 surface_prepare_texture(surface, context, srgb);
6119 surface_bind_and_dirtify(surface, context, srgb);
6121 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6123 surface->flags |= SFLAG_GLCKEY;
6124 surface->gl_color_key = surface->src_blt_color_key;
6126 else surface->flags &= ~SFLAG_GLCKEY;
6128 width = surface->resource.width;
6129 src_pitch = wined3d_surface_get_pitch(surface);
6131 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6132 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6134 if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6136 TRACE("Removing the pbo attached to surface %p.\n", surface);
6137 surface_remove_pbo(surface, gl_info);
6142 /* This code is entered for texture formats which need a fixup. */
6143 UINT height = surface->resource.height;
6145 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6146 dst_pitch = width * format.conv_byte_count;
6147 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6149 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6151 ERR("Out of memory (%u).\n", dst_pitch * height);
6152 context_release(context);
6153 return E_OUTOFMEMORY;
6155 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6156 format.byte_count = format.conv_byte_count;
6157 src_pitch = dst_pitch;
6159 else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6161 /* This code is only entered for color keying fixups */
6162 UINT height = surface->resource.height;
6164 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6165 dst_pitch = width * format.conv_byte_count;
6166 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6168 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6170 ERR("Out of memory (%u).\n", dst_pitch * height);
6171 context_release(context);
6172 return E_OUTOFMEMORY;
6174 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6175 width, height, dst_pitch, convert, surface);
6176 format.byte_count = format.conv_byte_count;
6177 src_pitch = dst_pitch;
6181 mem = surface->resource.allocatedMemory;
6184 data.buffer_object = surface->pbo;
6186 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6188 context_release(context);
6190 /* Don't delete PBO memory. */
6191 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6192 HeapFree(GetProcessHeap(), 0, mem);
6197 static void surface_multisample_resolve(struct wined3d_surface *surface)
6199 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6201 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6202 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6204 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6205 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6208 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6210 struct wined3d_device *device = surface->resource.device;
6211 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6214 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6216 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6218 if (location == SFLAG_INTEXTURE)
6220 struct wined3d_context *context = context_acquire(device, NULL);
6221 surface_load_ds_location(surface, context, location);
6222 context_release(context);
6227 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location));
6228 return WINED3DERR_INVALIDCALL;
6232 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6233 location = SFLAG_INTEXTURE;
6235 if (surface->flags & location)
6237 TRACE("Location already up to date.\n");
6239 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6240 && surface_need_pbo(surface, gl_info))
6241 surface_load_pbo(surface, gl_info);
6246 if (WARN_ON(d3d_surface))
6248 DWORD required_access = resource_access_from_location(location);
6249 if ((surface->resource.access_flags & required_access) != required_access)
6250 WARN("Operation requires %#x access, but surface only has %#x.\n",
6251 required_access, surface->resource.access_flags);
6254 if (!(surface->flags & SFLAG_LOCATIONS))
6256 ERR("Surface %p does not have any up to date location.\n", surface);
6257 surface->flags |= SFLAG_LOST;
6258 return WINED3DERR_DEVICELOST;
6263 case SFLAG_INSYSMEM:
6264 surface_load_sysmem(surface, gl_info, rect);
6267 case SFLAG_INDRAWABLE:
6268 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6272 case SFLAG_INRB_RESOLVED:
6273 surface_multisample_resolve(surface);
6276 case SFLAG_INTEXTURE:
6277 case SFLAG_INSRGBTEX:
6278 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6283 ERR("Don't know how to handle location %#x.\n", location);
6289 surface->flags |= location;
6291 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6292 surface_evict_sysmem(surface);
6295 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6296 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6298 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6304 BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6306 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6308 /* Not on a swapchain - must be offscreen */
6309 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6311 /* The front buffer is always onscreen */
6312 if (surface == swapchain->front_buffer) return FALSE;
6314 /* If the swapchain is rendered to an FBO, the backbuffer is
6315 * offscreen, otherwise onscreen */
6316 return swapchain->render_to_fbo;
6319 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6320 /* Context activation is done by the caller. */
6321 static void ffp_blit_free(struct wined3d_device *device) { }
6323 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6324 /* Context activation is done by the caller. */
6325 static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6328 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
6330 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6332 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6334 GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6338 /* Context activation is done by the caller. */
6339 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6341 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6343 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6344 * else the surface is converted in software at upload time in LoadLocation.
6346 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6347 && context->gl_info->supported[EXT_PALETTED_TEXTURE])
6348 ffp_blit_p8_upload_palette(surface, context->gl_info);
6351 glEnable(surface->texture_target);
6352 checkGLcall("glEnable(surface->texture_target)");
6357 /* Context activation is done by the caller. */
6358 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6361 glDisable(GL_TEXTURE_2D);
6362 checkGLcall("glDisable(GL_TEXTURE_2D)");
6363 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6365 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6366 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6368 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6370 glDisable(GL_TEXTURE_RECTANGLE_ARB);
6371 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6376 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6377 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6378 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6380 enum complex_fixup src_fixup;
6384 case WINED3D_BLIT_OP_COLOR_BLIT:
6385 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6388 src_fixup = get_complex_fixup(src_format->color_fixup);
6389 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6391 TRACE("Checking support for fixup:\n");
6392 dump_color_fixup_desc(src_format->color_fixup);
6395 if (!is_identity_fixup(dst_format->color_fixup))
6397 TRACE("Destination fixups are not supported\n");
6401 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6403 TRACE("P8 fixup supported\n");
6407 /* We only support identity conversions. */
6408 if (is_identity_fixup(src_format->color_fixup))
6414 TRACE("[FAILED]\n");
6417 case WINED3D_BLIT_OP_COLOR_FILL:
6418 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6421 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6423 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6426 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6428 TRACE("Color fill not supported\n");
6432 /* FIXME: We should reject color fills on formats with fixups,
6433 * but this would break P8 color fills for example. */
6437 case WINED3D_BLIT_OP_DEPTH_FILL:
6441 TRACE("Unsupported blit_op=%d\n", blit_op);
6446 /* Do not call while under the GL lock. */
6447 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6448 const RECT *dst_rect, const struct wined3d_color *color)
6450 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6451 struct wined3d_fb_state fb = {&dst_surface, NULL};
6453 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6458 /* Do not call while under the GL lock. */
6459 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6460 struct wined3d_surface *surface, const RECT *rect, float depth)
6462 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6463 struct wined3d_fb_state fb = {NULL, surface};
6465 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6470 const struct blit_shader ffp_blit = {
6476 ffp_blit_color_fill,
6477 ffp_blit_depth_fill,
6480 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6485 /* Context activation is done by the caller. */
6486 static void cpu_blit_free(struct wined3d_device *device)
6490 /* Context activation is done by the caller. */
6491 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6496 /* Context activation is done by the caller. */
6497 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6501 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6502 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6503 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6505 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6513 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6514 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6515 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6517 UINT row_block_count;
6518 const BYTE *src_row;
6525 row_block_count = (update_w + format->block_width - 1) / format->block_width;
6529 for (y = 0; y < update_h; y += format->block_height)
6531 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6532 src_row += src_pitch;
6533 dst_row += dst_pitch;
6539 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6541 src_row += (((update_h / format->block_height) - 1) * src_pitch);
6545 case WINED3DFMT_DXT1:
6546 for (y = 0; y < update_h; y += format->block_height)
6551 BYTE control_row[4];
6554 const struct block *s = (const struct block *)src_row;
6555 struct block *d = (struct block *)dst_row;
6557 for (x = 0; x < row_block_count; ++x)
6559 d[x].color[0] = s[x].color[0];
6560 d[x].color[1] = s[x].color[1];
6561 d[x].control_row[0] = s[x].control_row[3];
6562 d[x].control_row[1] = s[x].control_row[2];
6563 d[x].control_row[2] = s[x].control_row[1];
6564 d[x].control_row[3] = s[x].control_row[0];
6566 src_row -= src_pitch;
6567 dst_row += dst_pitch;
6571 case WINED3DFMT_DXT3:
6572 for (y = 0; y < update_h; y += format->block_height)
6578 BYTE control_row[4];
6581 const struct block *s = (const struct block *)src_row;
6582 struct block *d = (struct block *)dst_row;
6584 for (x = 0; x < row_block_count; ++x)
6586 d[x].alpha_row[0] = s[x].alpha_row[3];
6587 d[x].alpha_row[1] = s[x].alpha_row[2];
6588 d[x].alpha_row[2] = s[x].alpha_row[1];
6589 d[x].alpha_row[3] = s[x].alpha_row[0];
6590 d[x].color[0] = s[x].color[0];
6591 d[x].color[1] = s[x].color[1];
6592 d[x].control_row[0] = s[x].control_row[3];
6593 d[x].control_row[1] = s[x].control_row[2];
6594 d[x].control_row[2] = s[x].control_row[1];
6595 d[x].control_row[3] = s[x].control_row[0];
6597 src_row -= src_pitch;
6598 dst_row += dst_pitch;
6603 FIXME("Compressed flip not implemented for format %s.\n",
6604 debug_d3dformat(format->id));
6609 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
6610 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
6615 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
6616 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
6617 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
6619 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
6620 const struct wined3d_format *src_format, *dst_format;
6621 struct wined3d_surface *orig_src = src_surface;
6622 struct wined3d_map_desc dst_map, src_map;
6623 const BYTE *sbase = NULL;
6624 HRESULT hr = WINED3D_OK;
6629 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6630 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
6631 flags, fx, debug_d3dtexturefiltertype(filter));
6633 if (src_surface == dst_surface)
6635 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
6637 src_format = dst_surface->resource.format;
6638 dst_format = src_format;
6642 dst_format = dst_surface->resource.format;
6645 if (dst_surface->resource.format->id != src_surface->resource.format->id)
6647 src_surface = surface_convert_format(src_surface, dst_format->id);
6650 /* The conv function writes a FIXME */
6651 WARN("Cannot convert source surface format to dest format.\n");
6655 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
6656 src_format = src_surface->resource.format;
6660 src_format = dst_format;
6663 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
6666 bpp = dst_surface->resource.format->byte_count;
6667 srcheight = src_rect->bottom - src_rect->top;
6668 srcwidth = src_rect->right - src_rect->left;
6669 dstheight = dst_rect->bottom - dst_rect->top;
6670 dstwidth = dst_rect->right - dst_rect->left;
6671 width = (dst_rect->right - dst_rect->left) * bpp;
6674 sbase = (BYTE *)src_map.data
6675 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
6676 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
6677 if (src_surface != dst_surface)
6678 dbuf = dst_map.data;
6680 dbuf = (BYTE *)dst_map.data
6681 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
6682 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
6684 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
6686 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
6688 if (src_surface == dst_surface)
6690 FIXME("Only plain blits supported on compressed surfaces.\n");
6695 if (srcheight != dstheight || srcwidth != dstwidth)
6697 WARN("Stretching not supported on compressed surfaces.\n");
6698 hr = WINED3DERR_INVALIDCALL;
6702 if (!surface_check_block_align(src_surface, src_rect))
6704 WARN("Source rectangle not block-aligned.\n");
6705 hr = WINED3DERR_INVALIDCALL;
6709 if (!surface_check_block_align(dst_surface, dst_rect))
6711 WARN("Destination rectangle not block-aligned.\n");
6712 hr = WINED3DERR_INVALIDCALL;
6716 hr = surface_cpu_blt_compressed(sbase, dbuf,
6717 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
6718 src_format, flags, fx);
6722 /* First, all the 'source-less' blits */
6723 if (flags & WINEDDBLT_COLORFILL)
6725 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
6726 flags &= ~WINEDDBLT_COLORFILL;
6729 if (flags & WINEDDBLT_DEPTHFILL)
6731 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6733 if (flags & WINEDDBLT_ROP)
6735 /* Catch some degenerate cases here. */
6739 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
6741 case 0xAA0029: /* No-op */
6744 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
6746 case SRCCOPY: /* Well, we do that below? */
6749 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
6752 flags &= ~WINEDDBLT_ROP;
6754 if (flags & WINEDDBLT_DDROPS)
6756 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
6758 /* Now the 'with source' blits. */
6761 int sx, xinc, sy, yinc;
6763 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
6766 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
6767 && (srcwidth != dstwidth || srcheight != dstheight))
6769 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6770 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
6773 xinc = (srcwidth << 16) / dstwidth;
6774 yinc = (srcheight << 16) / dstheight;
6778 /* No effects, we can cheat here. */
6779 if (dstwidth == srcwidth)
6781 if (dstheight == srcheight)
6783 /* No stretching in either direction. This needs to be as
6784 * fast as possible. */
6787 /* Check for overlapping surfaces. */
6788 if (src_surface != dst_surface || dst_rect->top < src_rect->top
6789 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
6791 /* No overlap, or dst above src, so copy from top downwards. */
6792 for (y = 0; y < dstheight; ++y)
6794 memcpy(dbuf, sbuf, width);
6795 sbuf += src_map.row_pitch;
6796 dbuf += dst_map.row_pitch;
6799 else if (dst_rect->top > src_rect->top)
6801 /* Copy from bottom upwards. */
6802 sbuf += src_map.row_pitch * dstheight;
6803 dbuf += dst_map.row_pitch * dstheight;
6804 for (y = 0; y < dstheight; ++y)
6806 sbuf -= src_map.row_pitch;
6807 dbuf -= dst_map.row_pitch;
6808 memcpy(dbuf, sbuf, width);
6813 /* Src and dst overlapping on the same line, use memmove. */
6814 for (y = 0; y < dstheight; ++y)
6816 memmove(dbuf, sbuf, width);
6817 sbuf += src_map.row_pitch;
6818 dbuf += dst_map.row_pitch;
6824 /* Stretching in y direction only. */
6825 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6827 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6828 memcpy(dbuf, sbuf, width);
6829 dbuf += dst_map.row_pitch;
6835 /* Stretching in X direction. */
6837 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6839 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6841 if ((sy >> 16) == (last_sy >> 16))
6843 /* This source row is the same as last source row -
6844 * Copy the already stretched row. */
6845 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
6849 #define STRETCH_ROW(type) \
6851 const type *s = (const type *)sbuf; \
6852 type *d = (type *)dbuf; \
6853 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6854 d[x] = s[sx >> 16]; \
6872 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
6876 s = sbuf + 3 * (sx >> 16);
6877 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
6878 d[0] = (pixel ) & 0xff;
6879 d[1] = (pixel >> 8) & 0xff;
6880 d[2] = (pixel >> 16) & 0xff;
6886 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
6887 hr = WINED3DERR_NOTAVAILABLE;
6892 dbuf += dst_map.row_pitch;
6899 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
6900 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
6901 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
6902 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
6904 /* The color keying flags are checked for correctness in ddraw */
6905 if (flags & WINEDDBLT_KEYSRC)
6907 keylow = src_surface->src_blt_color_key.color_space_low_value;
6908 keyhigh = src_surface->src_blt_color_key.color_space_high_value;
6910 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6912 keylow = fx->ddckSrcColorkey.color_space_low_value;
6913 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
6916 if (flags & WINEDDBLT_KEYDEST)
6918 /* Destination color keys are taken from the source surface! */
6919 destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
6920 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
6922 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
6924 destkeylow = fx->ddckDestColorkey.color_space_low_value;
6925 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
6934 keymask = src_format->red_mask
6935 | src_format->green_mask
6936 | src_format->blue_mask;
6938 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
6941 if (flags & WINEDDBLT_DDFX)
6943 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
6946 dTopRight = dbuf + ((dstwidth - 1) * bpp);
6947 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
6948 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
6950 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
6952 /* I don't think we need to do anything about this flag */
6953 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6955 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
6958 dTopRight = dTopLeft;
6961 dBottomRight = dBottomLeft;
6963 dstxinc = dstxinc * -1;
6965 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
6968 dTopLeft = dBottomLeft;
6971 dTopRight = dBottomRight;
6973 dstyinc = dstyinc * -1;
6975 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
6977 /* I don't think we need to do anything about this flag */
6978 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
6980 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
6983 dBottomRight = dTopLeft;
6986 dBottomLeft = dTopRight;
6988 dstxinc = dstxinc * -1;
6989 dstyinc = dstyinc * -1;
6991 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
6994 dTopLeft = dBottomLeft;
6995 dBottomLeft = dBottomRight;
6996 dBottomRight = dTopRight;
7001 dstxinc = dstxinc * -1;
7003 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7006 dTopLeft = dTopRight;
7007 dTopRight = dBottomRight;
7008 dBottomRight = dBottomLeft;
7013 dstyinc = dstyinc * -1;
7015 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7017 /* I don't think we need to do anything about this flag */
7018 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7021 flags &= ~(WINEDDBLT_DDFX);
7024 #define COPY_COLORKEY_FX(type) \
7027 type *d = (type *)dbuf, *dx, tmp; \
7028 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7030 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7032 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7034 tmp = s[sx >> 16]; \
7035 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7036 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7040 dx = (type *)(((BYTE *)dx) + dstxinc); \
7042 d = (type *)(((BYTE *)d) + dstyinc); \
7049 COPY_COLORKEY_FX(BYTE);
7052 COPY_COLORKEY_FX(WORD);
7055 COPY_COLORKEY_FX(DWORD);
7060 BYTE *d = dbuf, *dx;
7061 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7063 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7065 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7067 DWORD pixel, dpixel = 0;
7068 s = sbuf + 3 * (sx>>16);
7069 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7070 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7071 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7072 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7074 dx[0] = (pixel ) & 0xff;
7075 dx[1] = (pixel >> 8) & 0xff;
7076 dx[2] = (pixel >> 16) & 0xff;
7085 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7086 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7087 hr = WINED3DERR_NOTAVAILABLE;
7089 #undef COPY_COLORKEY_FX
7095 if (flags && FIXME_ON(d3d_surface))
7097 FIXME("\tUnsupported flags: %#x.\n", flags);
7101 wined3d_surface_unmap(dst_surface);
7102 if (src_surface && src_surface != dst_surface)
7103 wined3d_surface_unmap(src_surface);
7104 /* Release the converted surface, if any. */
7105 if (src_surface && src_surface != orig_src)
7106 wined3d_surface_decref(src_surface);
7111 /* Do not call while under the GL lock. */
7112 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7113 const RECT *dst_rect, const struct wined3d_color *color)
7115 static const RECT src_rect;
7118 memset(&BltFx, 0, sizeof(BltFx));
7119 BltFx.dwSize = sizeof(BltFx);
7120 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7121 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7122 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7125 /* Do not call while under the GL lock. */
7126 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7127 struct wined3d_surface *surface, const RECT *rect, float depth)
7129 FIXME("Depth filling not implemented by cpu_blit.\n");
7130 return WINED3DERR_INVALIDCALL;
7133 const struct blit_shader cpu_blit = {
7139 cpu_blit_color_fill,
7140 cpu_blit_depth_fill,
7143 static HRESULT surface_init(struct wined3d_surface *surface, enum wined3d_surface_type surface_type, UINT alignment,
7144 UINT width, UINT height, UINT level, enum wined3d_multisample_type multisample_type,
7145 UINT multisample_quality, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7146 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops)
7148 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7149 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7150 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7151 unsigned int resource_size;
7154 if (multisample_quality > 0)
7156 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7157 multisample_quality = 0;
7160 /* Quick lockable sanity check.
7161 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7162 * this function is too deep to need to care about things like this.
7163 * Levels need to be checked too, since they all affect what can be done. */
7166 case WINED3D_POOL_SCRATCH:
7169 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7170 "which are mutually exclusive, setting lockable to TRUE.\n");
7175 case WINED3D_POOL_SYSTEM_MEM:
7177 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7180 case WINED3D_POOL_MANAGED:
7181 if (usage & WINED3DUSAGE_DYNAMIC)
7182 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7185 case WINED3D_POOL_DEFAULT:
7186 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7187 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7191 FIXME("Unknown pool %#x.\n", pool);
7195 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7196 FIXME("Trying to create a render target that isn't in the default pool.\n");
7198 /* FIXME: Check that the format is supported by the device. */
7200 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7202 return WINED3DERR_INVALIDCALL;
7204 surface->surface_type = surface_type;
7206 switch (surface_type)
7208 case WINED3D_SURFACE_TYPE_OPENGL:
7209 surface->surface_ops = &surface_ops;
7212 case WINED3D_SURFACE_TYPE_GDI:
7213 surface->surface_ops = &gdi_surface_ops;
7217 ERR("Requested unknown surface implementation %#x.\n", surface_type);
7218 return WINED3DERR_INVALIDCALL;
7221 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7222 multisample_type, multisample_quality, usage, pool, width, height, 1,
7223 resource_size, parent, parent_ops, &surface_resource_ops);
7226 WARN("Failed to initialize resource, returning %#x.\n", hr);
7230 /* "Standalone" surface. */
7231 surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7233 surface->texture_level = level;
7234 list_init(&surface->overlays);
7237 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7238 if (flags & WINED3D_SURFACE_DISCARD)
7239 surface->flags |= SFLAG_DISCARD;
7240 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7241 surface->flags |= SFLAG_PIN_SYSMEM;
7242 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7243 surface->flags |= SFLAG_LOCKABLE;
7244 /* I'm not sure if this qualifies as a hack or as an optimization. It
7245 * seems reasonable to assume that lockable render targets will get
7246 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7247 * creation. However, the other reason we want to do this is that several
7248 * ddraw applications access surface memory while the surface isn't
7249 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7250 * future locks prevents these from crashing. */
7251 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7252 surface->flags |= SFLAG_DYNLOCK;
7254 /* Mark the texture as dirty so that it gets loaded first time around. */
7255 surface_add_dirty_rect(surface, NULL);
7256 list_init(&surface->renderbuffers);
7258 TRACE("surface %p, memory %p, size %u\n",
7259 surface, surface->resource.allocatedMemory, surface->resource.size);
7261 /* Call the private setup routine */
7262 hr = surface->surface_ops->surface_private_setup(surface);
7265 ERR("Private setup failed, returning %#x\n", hr);
7266 surface_cleanup(surface);
7270 /* Similar to lockable rendertargets above, creating the DIB section
7271 * during surface initialization prevents the sysmem pointer from changing
7272 * after a wined3d_surface_getdc() call. */
7273 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7274 && SUCCEEDED(surface_create_dib_section(surface)))
7276 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7277 surface->resource.heapMemory = NULL;
7278 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7284 HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
7285 enum wined3d_format_id format_id, UINT level, DWORD usage, enum wined3d_pool pool,
7286 enum wined3d_multisample_type multisample_type, DWORD multisample_quality,
7287 enum wined3d_surface_type surface_type, DWORD flags, void *parent,
7288 const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface)
7290 struct wined3d_surface *object;
7293 TRACE("device %p, width %u, height %u, format %s, level %u\n",
7294 device, width, height, debug_d3dformat(format_id), level);
7295 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7296 surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
7297 TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type, flags, parent, parent_ops);
7299 if (surface_type == WINED3D_SURFACE_TYPE_OPENGL && !device->adapter)
7301 ERR("OpenGL surfaces are not available without OpenGL.\n");
7302 return WINED3DERR_NOTAVAILABLE;
7305 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
7308 ERR("Failed to allocate surface memory.\n");
7309 return WINED3DERR_OUTOFVIDEOMEMORY;
7312 hr = surface_init(object, surface_type, device->surface_alignment, width, height, level,
7313 multisample_type, multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops);
7316 WARN("Failed to initialize surface, returning %#x.\n", hr);
7317 HeapFree(GetProcessHeap(), 0, object);
7321 TRACE("Created surface %p.\n", object);