2 * IWineD3DSurface Implementation
4 * Copyright 1997-2000 Marcus Meissner
5 * Copyright 1998-2000 Lionel Ulmer
6 * Copyright 2000-2001 TransGaming Technologies Inc.
7 * Copyright 2002-2005 Jason Edmeades
8 * Copyright 2002-2003 Raphael Junqueira
9 * Copyright 2004 Christian Costa
10 * Copyright 2005 Oliver Stieber
11 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
12 * Copyright 2007-2008 Henri Verbeet
13 * Copyright 2006-2008 Roderick Colenbrander
14 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wine/port.h"
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 WINE_DECLARE_DEBUG_CHANNEL(d3d);
38 static void surface_cleanup(IWineD3DSurfaceImpl *This)
40 TRACE("(%p) : Cleaning up.\n", This);
42 if (This->texture_name || (This->flags & SFLAG_PBO) || !list_empty(&This->renderbuffers))
44 const struct wined3d_gl_info *gl_info;
45 renderbuffer_entry_t *entry, *entry2;
46 struct wined3d_context *context;
48 context = context_acquire(This->resource.device, NULL);
49 gl_info = context->gl_info;
53 if (This->texture_name)
55 TRACE("Deleting texture %u.\n", This->texture_name);
56 glDeleteTextures(1, &This->texture_name);
59 if (This->flags & SFLAG_PBO)
61 TRACE("Deleting PBO %u.\n", This->pbo);
62 GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
65 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry)
67 TRACE("Deleting renderbuffer %u.\n", entry->id);
68 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
69 HeapFree(GetProcessHeap(), 0, entry);
74 context_release(context);
77 if (This->flags & SFLAG_DIBSECTION)
80 SelectObject(This->hDC, This->dib.holdbitmap);
82 /* Release the DIB section. */
83 DeleteObject(This->dib.DIBsection);
84 This->dib.bitmap_data = NULL;
85 This->resource.allocatedMemory = NULL;
88 if (This->flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
89 if (This->overlay_dest) list_remove(&This->overlay_entry);
91 HeapFree(GetProcessHeap(), 0, This->palette9);
93 resource_cleanup(&This->resource);
96 void surface_set_container(IWineD3DSurfaceImpl *surface, enum wined3d_container_type type, void *container)
98 TRACE("surface %p, container %p.\n", surface, container);
100 if (!container && type != WINED3D_CONTAINER_NONE)
101 ERR("Setting NULL container of type %#x.\n", type);
103 if (type == WINED3D_CONTAINER_SWAPCHAIN)
105 surface->get_drawable_size = get_drawable_size_swapchain;
109 switch (wined3d_settings.offscreen_rendering_mode)
112 surface->get_drawable_size = get_drawable_size_fbo;
116 surface->get_drawable_size = get_drawable_size_backbuffer;
120 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
125 surface->container.type = type;
126 surface->container.u.base = container;
133 enum tex_types tex_type;
134 GLfloat coords[4][3];
145 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
147 f->l = ((r->left * 2.0f) / w) - 1.0f;
148 f->t = ((r->top * 2.0f) / h) - 1.0f;
149 f->r = ((r->right * 2.0f) / w) - 1.0f;
150 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
153 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
155 GLfloat (*coords)[3] = info->coords;
161 FIXME("Unsupported texture target %#x\n", target);
162 /* Fall back to GL_TEXTURE_2D */
164 info->binding = GL_TEXTURE_BINDING_2D;
165 info->bind_target = GL_TEXTURE_2D;
166 info->tex_type = tex_2d;
167 coords[0][0] = (float)rect->left / w;
168 coords[0][1] = (float)rect->top / h;
171 coords[1][0] = (float)rect->right / w;
172 coords[1][1] = (float)rect->top / h;
175 coords[2][0] = (float)rect->left / w;
176 coords[2][1] = (float)rect->bottom / h;
179 coords[3][0] = (float)rect->right / w;
180 coords[3][1] = (float)rect->bottom / h;
184 case GL_TEXTURE_RECTANGLE_ARB:
185 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
186 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
187 info->tex_type = tex_rect;
188 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
189 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
190 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
191 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
194 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
195 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
196 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
197 info->tex_type = tex_cube;
198 cube_coords_float(rect, w, h, &f);
200 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
201 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
202 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
203 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
206 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
207 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
208 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
209 info->tex_type = tex_cube;
210 cube_coords_float(rect, w, h, &f);
212 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
213 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
214 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
215 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
218 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
219 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
220 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
221 info->tex_type = tex_cube;
222 cube_coords_float(rect, w, h, &f);
224 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
225 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
226 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
227 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
230 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
231 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
232 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
233 info->tex_type = tex_cube;
234 cube_coords_float(rect, w, h, &f);
236 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
237 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
238 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
239 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
242 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
243 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
244 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
245 info->tex_type = tex_cube;
246 cube_coords_float(rect, w, h, &f);
248 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
249 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
250 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
251 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
254 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
255 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
256 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
257 info->tex_type = tex_cube;
258 cube_coords_float(rect, w, h, &f);
260 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
261 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
262 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
263 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
268 static inline void surface_get_rect(IWineD3DSurfaceImpl *This, const RECT *rect_in, RECT *rect_out)
271 *rect_out = *rect_in;
276 rect_out->right = This->resource.width;
277 rect_out->bottom = This->resource.height;
281 /* GL locking and context activation is done by the caller */
282 void draw_textured_quad(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, const RECT *dst_rect, WINED3DTEXTUREFILTERTYPE Filter)
284 struct blt_info info;
286 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
288 glEnable(info.bind_target);
289 checkGLcall("glEnable(bind_target)");
291 /* Bind the texture */
292 glBindTexture(info.bind_target, src_surface->texture_name);
293 checkGLcall("glBindTexture");
295 /* Filtering for StretchRect */
296 glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
297 wined3d_gl_mag_filter(magLookup, Filter));
298 checkGLcall("glTexParameteri");
299 glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
300 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
301 checkGLcall("glTexParameteri");
302 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
303 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
304 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
305 checkGLcall("glTexEnvi");
308 glBegin(GL_TRIANGLE_STRIP);
309 glTexCoord3fv(info.coords[0]);
310 glVertex2i(dst_rect->left, dst_rect->top);
312 glTexCoord3fv(info.coords[1]);
313 glVertex2i(dst_rect->right, dst_rect->top);
315 glTexCoord3fv(info.coords[2]);
316 glVertex2i(dst_rect->left, dst_rect->bottom);
318 glTexCoord3fv(info.coords[3]);
319 glVertex2i(dst_rect->right, dst_rect->bottom);
322 /* Unbind the texture */
323 glBindTexture(info.bind_target, 0);
324 checkGLcall("glBindTexture(info->bind_target, 0)");
326 /* We changed the filtering settings on the texture. Inform the
327 * container about this to get the filters reset properly next draw. */
328 if (src_surface->container.type == WINED3D_CONTAINER_TEXTURE)
330 struct wined3d_texture *texture = src_surface->container.u.texture;
331 texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
332 texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
333 texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
337 static HRESULT surface_create_dib_section(IWineD3DSurfaceImpl *surface)
339 const struct wined3d_format *format = surface->resource.format;
347 TRACE("surface %p.\n", surface);
349 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
351 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
352 return WINED3DERR_INVALIDCALL;
355 switch (format->byte_count)
359 /* Allocate extra space to store the RGB bit masks. */
360 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
364 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
368 /* Allocate extra space for a palette. */
369 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
370 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
375 return E_OUTOFMEMORY;
377 /* Some applications access the surface in via DWORDs, and do not take
378 * the necessary care at the end of the surface. So we need at least
379 * 4 extra bytes at the end of the surface. Check against the page size,
380 * if the last page used for the surface has at least 4 spare bytes we're
381 * safe, otherwise add an extra line to the DIB section. */
382 GetSystemInfo(&sysInfo);
383 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
386 TRACE("Adding an extra line to the DIB section.\n");
389 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
390 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
391 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface) / format->byte_count;
392 b_info->bmiHeader.biHeight = -surface->resource.height - extraline;
393 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
394 * IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
395 b_info->bmiHeader.biPlanes = 1;
396 b_info->bmiHeader.biBitCount = format->byte_count * 8;
398 b_info->bmiHeader.biXPelsPerMeter = 0;
399 b_info->bmiHeader.biYPelsPerMeter = 0;
400 b_info->bmiHeader.biClrUsed = 0;
401 b_info->bmiHeader.biClrImportant = 0;
403 /* Get the bit masks */
404 masks = (DWORD *)b_info->bmiColors;
405 switch (surface->resource.format->id)
407 case WINED3DFMT_B8G8R8_UNORM:
408 usage = DIB_RGB_COLORS;
409 b_info->bmiHeader.biCompression = BI_RGB;
412 case WINED3DFMT_B5G5R5X1_UNORM:
413 case WINED3DFMT_B5G5R5A1_UNORM:
414 case WINED3DFMT_B4G4R4A4_UNORM:
415 case WINED3DFMT_B4G4R4X4_UNORM:
416 case WINED3DFMT_B2G3R3_UNORM:
417 case WINED3DFMT_B2G3R3A8_UNORM:
418 case WINED3DFMT_R10G10B10A2_UNORM:
419 case WINED3DFMT_R8G8B8A8_UNORM:
420 case WINED3DFMT_R8G8B8X8_UNORM:
421 case WINED3DFMT_B10G10R10A2_UNORM:
422 case WINED3DFMT_B5G6R5_UNORM:
423 case WINED3DFMT_R16G16B16A16_UNORM:
425 b_info->bmiHeader.biCompression = BI_BITFIELDS;
426 masks[0] = format->red_mask;
427 masks[1] = format->green_mask;
428 masks[2] = format->blue_mask;
432 /* Don't know palette */
433 b_info->bmiHeader.biCompression = BI_RGB;
438 if (!(dc = GetDC(0)))
440 HeapFree(GetProcessHeap(), 0, b_info);
441 return HRESULT_FROM_WIN32(GetLastError());
444 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
445 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
446 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
447 surface->dib.DIBsection = CreateDIBSection(dc, b_info, usage, &surface->dib.bitmap_data, 0, 0);
450 if (!surface->dib.DIBsection)
452 ERR("Failed to create DIB section.\n");
453 HeapFree(GetProcessHeap(), 0, b_info);
454 return HRESULT_FROM_WIN32(GetLastError());
457 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
458 /* Copy the existing surface to the dib section. */
459 if (surface->resource.allocatedMemory)
461 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
462 surface->resource.height * IWineD3DSurface_GetPitch((IWineD3DSurface *)surface));
466 /* This is to make maps read the GL texture although memory is allocated. */
467 surface->flags &= ~SFLAG_INSYSMEM;
469 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
471 HeapFree(GetProcessHeap(), 0, b_info);
473 /* Now allocate a DC. */
474 surface->hDC = CreateCompatibleDC(0);
475 surface->dib.holdbitmap = SelectObject(surface->hDC, surface->dib.DIBsection);
476 TRACE("Using wined3d palette %p.\n", surface->palette);
477 SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
479 surface->flags |= SFLAG_DIBSECTION;
481 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
482 surface->resource.heapMemory = NULL;
488 static HRESULT surface_private_setup(struct IWineD3DSurfaceImpl *surface)
490 /* TODO: Check against the maximum texture sizes supported by the video card. */
491 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
492 unsigned int pow2Width, pow2Height;
494 TRACE("surface %p.\n", surface);
496 surface->texture_name = 0;
497 surface->texture_target = GL_TEXTURE_2D;
499 /* Non-power2 support */
500 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
502 pow2Width = surface->resource.width;
503 pow2Height = surface->resource.height;
507 /* Find the nearest pow2 match */
508 pow2Width = pow2Height = 1;
509 while (pow2Width < surface->resource.width)
511 while (pow2Height < surface->resource.height)
514 surface->pow2Width = pow2Width;
515 surface->pow2Height = pow2Height;
517 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
519 /* TODO: Add support for non power two compressed textures. */
520 if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
522 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
523 surface, surface->resource.width, surface->resource.height);
524 return WINED3DERR_NOTAVAILABLE;
528 if (pow2Width != surface->resource.width
529 || pow2Height != surface->resource.height)
531 surface->flags |= SFLAG_NONPOW2;
534 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
535 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
537 /* One of three options:
538 * 1: Do the same as we do with NPOT and scale the texture, (any
539 * texture ops would require the texture to be scaled which is
541 * 2: Set the texture to the maximum size (bad idea).
542 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
543 * 4: Create the surface, but allow it to be used only for DirectDraw
544 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
545 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
546 * the render target. */
547 if (surface->resource.pool == WINED3DPOOL_DEFAULT || surface->resource.pool == WINED3DPOOL_MANAGED)
549 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
550 return WINED3DERR_NOTAVAILABLE;
553 /* We should never use this surface in combination with OpenGL! */
554 TRACE("Creating an oversized surface: %ux%u.\n",
555 surface->pow2Width, surface->pow2Height);
559 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
560 * and EXT_PALETTED_TEXTURE is used in combination with texture
561 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
562 * EXT_PALETTED_TEXTURE doesn't work in combination with
563 * ARB_TEXTURE_RECTANGLE. */
564 if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
565 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
566 && gl_info->supported[EXT_PALETTED_TEXTURE]
567 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
569 surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
570 surface->pow2Width = surface->resource.width;
571 surface->pow2Height = surface->resource.height;
572 surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
576 switch (wined3d_settings.offscreen_rendering_mode)
579 surface->get_drawable_size = get_drawable_size_fbo;
583 surface->get_drawable_size = get_drawable_size_backbuffer;
587 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
588 return WINED3DERR_INVALIDCALL;
591 surface->flags |= SFLAG_INSYSMEM;
596 static void surface_realize_palette(IWineD3DSurfaceImpl *surface)
598 struct wined3d_palette *palette = surface->palette;
600 TRACE("surface %p.\n", surface);
602 if (!palette) return;
604 if (surface->resource.format->id == WINED3DFMT_P8_UINT
605 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
607 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
609 /* Make sure the texture is up to date. This call doesn't do
610 * anything if the texture is already up to date. */
611 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
613 /* We want to force a palette refresh, so mark the drawable as not being up to date */
614 if (!surface_is_offscreen(surface))
615 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
619 if (!(surface->flags & SFLAG_INSYSMEM))
621 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
622 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
624 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
628 if (surface->flags & SFLAG_DIBSECTION)
633 TRACE("Updating the DC's palette.\n");
635 for (i = 0; i < 256; ++i)
637 col[i].rgbRed = palette->palents[i].peRed;
638 col[i].rgbGreen = palette->palents[i].peGreen;
639 col[i].rgbBlue = palette->palents[i].peBlue;
640 col[i].rgbReserved = 0;
642 SetDIBColorTable(surface->hDC, 0, 256, col);
645 /* Propagate the changes to the drawable when we have a palette. */
646 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
647 surface_load_location(surface, SFLAG_INDRAWABLE, NULL);
650 static HRESULT surface_draw_overlay(IWineD3DSurfaceImpl *surface)
654 /* If there's no destination surface there is nothing to do. */
655 if (!surface->overlay_dest)
658 /* Blt calls ModifyLocation on the dest surface, which in turn calls
659 * DrawOverlay to update the overlay. Prevent an endless recursion. */
660 if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
663 surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
664 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface->overlay_dest,
665 &surface->overlay_destrect, (IWineD3DSurface *)surface, &surface->overlay_srcrect,
666 WINEDDBLT_WAIT, NULL, WINED3DTEXF_LINEAR);
667 surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
672 /* Context activation is done by the caller. */
673 static void surface_remove_pbo(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
675 if (!surface->resource.heapMemory)
677 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
678 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
679 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
683 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
684 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
685 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
686 surface->resource.size, surface->resource.allocatedMemory));
687 checkGLcall("glGetBufferSubDataARB");
688 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
689 checkGLcall("glDeleteBuffersARB");
693 surface->flags &= ~SFLAG_PBO;
696 /* Do not call while under the GL lock. */
697 static void surface_unload(struct wined3d_resource *resource)
699 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
700 IWineD3DDeviceImpl *device = resource->device;
701 const struct wined3d_gl_info *gl_info;
702 renderbuffer_entry_t *entry, *entry2;
703 struct wined3d_context *context;
705 TRACE("surface %p.\n", surface);
707 if (resource->pool == WINED3DPOOL_DEFAULT)
709 /* Default pool resources are supposed to be destroyed before Reset is called.
710 * Implicit resources stay however. So this means we have an implicit render target
711 * or depth stencil. The content may be destroyed, but we still have to tear down
712 * opengl resources, so we cannot leave early.
714 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
715 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
716 * or the depth stencil into an FBO the texture or render buffer will be removed
717 * and all flags get lost
719 surface_init_sysmem(surface);
723 /* Load the surface into system memory */
724 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
725 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
727 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
728 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
729 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
731 context = context_acquire(device, NULL);
732 gl_info = context->gl_info;
734 /* Destroy PBOs, but load them into real sysmem before */
735 if (surface->flags & SFLAG_PBO)
736 surface_remove_pbo(surface, gl_info);
738 /* Destroy fbo render buffers. This is needed for implicit render targets, for
739 * all application-created targets the application has to release the surface
740 * before calling _Reset
742 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, renderbuffer_entry_t, entry)
745 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
747 list_remove(&entry->entry);
748 HeapFree(GetProcessHeap(), 0, entry);
750 list_init(&surface->renderbuffers);
751 surface->current_renderbuffer = NULL;
753 /* If we're in a texture, the texture name belongs to the texture.
754 * Otherwise, destroy it. */
755 if (surface->container.type != WINED3D_CONTAINER_TEXTURE)
758 glDeleteTextures(1, &surface->texture_name);
759 surface->texture_name = 0;
760 glDeleteTextures(1, &surface->texture_name_srgb);
761 surface->texture_name_srgb = 0;
765 context_release(context);
767 resource_unload(resource);
770 static const struct wined3d_resource_ops surface_resource_ops =
775 static const struct wined3d_surface_ops surface_ops =
777 surface_private_setup,
778 surface_realize_palette,
779 surface_draw_overlay,
782 /*****************************************************************************
783 * Initializes the GDI surface, aka creates the DIB section we render to
784 * The DIB section creation is done by calling GetDC, which will create the
785 * section and releasing the dc to allow the app to use it. The dib section
786 * will stay until the surface is released
788 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
789 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
790 * avoid confusion in the shared surface code.
793 * WINED3D_OK on success
794 * The return values of called methods on failure
796 *****************************************************************************/
797 static HRESULT gdi_surface_private_setup(IWineD3DSurfaceImpl *surface)
801 TRACE("surface %p.\n", surface);
803 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
805 ERR("Overlays not yet supported by GDI surfaces.\n");
806 return WINED3DERR_INVALIDCALL;
809 /* Sysmem textures have memory already allocated - release it,
810 * this avoids an unnecessary memcpy. */
811 hr = surface_create_dib_section(surface);
814 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
815 surface->resource.heapMemory = NULL;
816 surface->resource.allocatedMemory = surface->dib.bitmap_data;
819 /* We don't mind the nonpow2 stuff in GDI. */
820 surface->pow2Width = surface->resource.width;
821 surface->pow2Height = surface->resource.height;
826 static void surface_gdi_cleanup(IWineD3DSurfaceImpl *surface)
828 TRACE("surface %p.\n", surface);
830 if (surface->flags & SFLAG_DIBSECTION)
832 /* Release the DC. */
833 SelectObject(surface->hDC, surface->dib.holdbitmap);
834 DeleteDC(surface->hDC);
835 /* Release the DIB section. */
836 DeleteObject(surface->dib.DIBsection);
837 surface->dib.bitmap_data = NULL;
838 surface->resource.allocatedMemory = NULL;
841 if (surface->flags & SFLAG_USERPTR)
842 IWineD3DSurface_SetMem((IWineD3DSurface *)surface, NULL);
843 if (surface->overlay_dest)
844 list_remove(&surface->overlay_entry);
846 HeapFree(GetProcessHeap(), 0, surface->palette9);
848 resource_cleanup(&surface->resource);
851 static void gdi_surface_realize_palette(IWineD3DSurfaceImpl *surface)
853 struct wined3d_palette *palette = surface->palette;
855 TRACE("surface %p.\n", surface);
857 if (!palette) return;
859 if (surface->flags & SFLAG_DIBSECTION)
864 TRACE("Updating the DC's palette.\n");
866 for (i = 0; i < 256; ++i)
868 col[i].rgbRed = palette->palents[i].peRed;
869 col[i].rgbGreen = palette->palents[i].peGreen;
870 col[i].rgbBlue = palette->palents[i].peBlue;
871 col[i].rgbReserved = 0;
873 SetDIBColorTable(surface->hDC, 0, 256, col);
876 /* Update the image because of the palette change. Some games like e.g.
877 * Red Alert call SetEntries a lot to implement fading. */
878 /* Tell the swapchain to update the screen. */
879 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
881 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
882 if (surface == swapchain->front_buffer)
884 x11_copy_to_screen(swapchain, NULL);
889 static HRESULT gdi_surface_draw_overlay(IWineD3DSurfaceImpl *surface)
891 FIXME("GDI surfaces can't draw overlays yet.\n");
895 static const struct wined3d_surface_ops gdi_surface_ops =
897 gdi_surface_private_setup,
898 gdi_surface_realize_palette,
899 gdi_surface_draw_overlay,
902 static void surface_force_reload(IWineD3DSurfaceImpl *surface)
904 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
907 void surface_set_texture_name(IWineD3DSurfaceImpl *surface, GLuint new_name, BOOL srgb)
912 TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
916 name = &surface->texture_name_srgb;
917 flag = SFLAG_INSRGBTEX;
921 name = &surface->texture_name;
922 flag = SFLAG_INTEXTURE;
925 if (!*name && new_name)
927 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
928 * surface has no texture name yet. See if we can get rid of this. */
929 if (surface->flags & flag)
930 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
931 surface_modify_location(surface, flag, FALSE);
935 surface_force_reload(surface);
938 void surface_set_texture_target(IWineD3DSurfaceImpl *surface, GLenum target)
940 TRACE("surface %p, target %#x.\n", surface, target);
942 if (surface->texture_target != target)
944 if (target == GL_TEXTURE_RECTANGLE_ARB)
946 surface->flags &= ~SFLAG_NORMCOORD;
948 else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
950 surface->flags |= SFLAG_NORMCOORD;
953 surface->texture_target = target;
954 surface_force_reload(surface);
957 /* Context activation is done by the caller. */
958 void surface_bind(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
960 TRACE("surface %p, gl_info %p, srgb %#x.\n", surface, gl_info, srgb);
962 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
964 struct wined3d_texture *texture = surface->container.u.texture;
966 TRACE("Passing to container (%p).\n", texture);
967 texture->texture_ops->texture_bind(texture, gl_info, srgb);
971 if (surface->texture_level)
973 ERR("Standalone surface %p is non-zero texture level %u.\n",
974 surface, surface->texture_level);
978 ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
982 if (!surface->texture_name)
984 glGenTextures(1, &surface->texture_name);
985 checkGLcall("glGenTextures");
987 TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
989 glBindTexture(surface->texture_target, surface->texture_name);
990 checkGLcall("glBindTexture");
991 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
992 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
993 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
994 glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
995 glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
996 checkGLcall("glTexParameteri");
1000 glBindTexture(surface->texture_target, surface->texture_name);
1001 checkGLcall("glBindTexture");
1008 /* Context activation is done by the caller. */
1009 static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *surface,
1010 const struct wined3d_gl_info *gl_info, BOOL srgb)
1012 IWineD3DDeviceImpl *device = surface->resource.device;
1013 DWORD active_sampler;
1015 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
1016 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
1017 * gl states. The current texture unit should always be a valid one.
1019 * To be more specific, this is tricky because we can implicitly be called
1020 * from sampler() in state.c. This means we can't touch anything other than
1021 * whatever happens to be the currently active texture, or we would risk
1022 * marking already applied sampler states dirty again.
1024 * TODO: Track the current active texture per GL context instead of using glGet
1026 GLint active_texture;
1028 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
1030 active_sampler = device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
1032 if (active_sampler != WINED3D_UNMAPPED_STAGE)
1034 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(active_sampler));
1036 surface_bind(surface, gl_info, srgb);
1039 /* This function checks if the primary render target uses the 8bit paletted format. */
1040 static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device)
1042 if (device->render_targets && device->render_targets[0])
1044 IWineD3DSurfaceImpl *render_target = device->render_targets[0];
1045 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
1046 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
1052 /* This call just downloads data, the caller is responsible for binding the
1053 * correct texture. */
1054 /* Context activation is done by the caller. */
1055 static void surface_download_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
1057 const struct wined3d_format *format = This->resource.format;
1059 /* Only support read back of converted P8 surfaces */
1060 if (This->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
1062 FIXME("Readback conversion not supported for format %s.\n", debug_d3dformat(format->id));
1068 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
1070 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1071 This, This->texture_level, format->glFormat, format->glType,
1072 This->resource.allocatedMemory);
1074 if (This->flags & SFLAG_PBO)
1076 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1077 checkGLcall("glBindBufferARB");
1078 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target, This->texture_level, NULL));
1079 checkGLcall("glGetCompressedTexImageARB");
1080 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1081 checkGLcall("glBindBufferARB");
1085 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target,
1086 This->texture_level, This->resource.allocatedMemory));
1087 checkGLcall("glGetCompressedTexImageARB");
1093 GLenum gl_format = format->glFormat;
1094 GLenum gl_type = format->glType;
1098 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
1099 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(This->resource.device))
1101 gl_format = GL_ALPHA;
1102 gl_type = GL_UNSIGNED_BYTE;
1105 if (This->flags & SFLAG_NONPOW2)
1107 unsigned char alignment = This->resource.device->surface_alignment;
1108 src_pitch = format->byte_count * This->pow2Width;
1109 dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
1110 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
1111 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
1113 mem = This->resource.allocatedMemory;
1116 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1117 This, This->texture_level, gl_format, gl_type, mem);
1119 if (This->flags & SFLAG_PBO)
1121 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1122 checkGLcall("glBindBufferARB");
1124 glGetTexImage(This->texture_target, This->texture_level, gl_format, gl_type, NULL);
1125 checkGLcall("glGetTexImage");
1127 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1128 checkGLcall("glBindBufferARB");
1130 glGetTexImage(This->texture_target, This->texture_level, gl_format, gl_type, mem);
1131 checkGLcall("glGetTexImage");
1135 if (This->flags & SFLAG_NONPOW2)
1137 const BYTE *src_data;
1141 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1142 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1143 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1145 * We're doing this...
1147 * instead of boxing the texture :
1148 * |<-texture width ->| -->pow2width| /\
1149 * |111111111111111111| | |
1150 * |222 Texture 222222| boxed empty | texture height
1151 * |3333 Data 33333333| | |
1152 * |444444444444444444| | \/
1153 * ----------------------------------- |
1154 * | boxed empty | boxed empty | pow2height
1156 * -----------------------------------
1159 * we're repacking the data to the expected texture width
1161 * |<-texture width ->| -->pow2width| /\
1162 * |111111111111111111222222222222222| |
1163 * |222333333333333333333444444444444| texture height
1167 * | empty | pow2height
1169 * -----------------------------------
1173 * |<-texture width ->| /\
1174 * |111111111111111111|
1175 * |222222222222222222|texture height
1176 * |333333333333333333|
1177 * |444444444444444444| \/
1178 * --------------------
1180 * this also means that any references to allocatedMemory should work with the data as if were a
1181 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
1183 * internally the texture is still stored in a boxed format so any references to textureName will
1184 * get a boxed texture with width pow2width and not a texture of width resource.width.
1186 * Performance should not be an issue, because applications normally do not lock the surfaces when
1187 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
1188 * and doesn't have to be re-read.
1191 dst_data = This->resource.allocatedMemory;
1192 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
1193 for (y = 1; y < This->resource.height; ++y)
1195 /* skip the first row */
1196 src_data += src_pitch;
1197 dst_data += dst_pitch;
1198 memcpy(dst_data, src_data, dst_pitch);
1201 HeapFree(GetProcessHeap(), 0, mem);
1205 /* Surface has now been downloaded */
1206 This->flags |= SFLAG_INSYSMEM;
1209 /* This call just uploads data, the caller is responsible for binding the
1210 * correct texture. */
1211 /* Context activation is done by the caller. */
1212 static void surface_upload_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
1213 const struct wined3d_format *format, BOOL srgb, const GLvoid *data)
1215 GLsizei width = This->resource.width;
1216 GLsizei height = This->resource.height;
1221 internal = format->glGammaInternal;
1223 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(This))
1225 internal = format->rtInternal;
1229 internal = format->glInternal;
1232 TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
1233 This, internal, width, height, format->glFormat, format->glType, data);
1234 TRACE("target %#x, level %u, resource size %u.\n",
1235 This->texture_target, This->texture_level, This->resource.size);
1237 if (format->heightscale != 1.0f && format->heightscale != 0.0f) height *= format->heightscale;
1241 if (This->flags & SFLAG_PBO)
1243 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1244 checkGLcall("glBindBufferARB");
1246 TRACE("(%p) pbo: %#x, data: %p.\n", This, This->pbo, data);
1250 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
1252 TRACE("Calling glCompressedTexSubImage2DARB.\n");
1254 GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
1255 0, 0, width, height, internal, This->resource.size, data));
1256 checkGLcall("glCompressedTexSubImage2DARB");
1260 TRACE("Calling glTexSubImage2D.\n");
1262 glTexSubImage2D(This->texture_target, This->texture_level,
1263 0, 0, width, height, format->glFormat, format->glType, data);
1264 checkGLcall("glTexSubImage2D");
1267 if (This->flags & SFLAG_PBO)
1269 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1270 checkGLcall("glBindBufferARB");
1275 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1277 IWineD3DDeviceImpl *device = This->resource.device;
1280 for (i = 0; i < device->context_count; ++i)
1282 context_surface_update(device->contexts[i], This);
1287 /* This call just allocates the texture, the caller is responsible for binding
1288 * the correct texture. */
1289 /* Context activation is done by the caller. */
1290 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
1291 const struct wined3d_format *format, BOOL srgb)
1293 BOOL enable_client_storage = FALSE;
1294 GLsizei width = This->pow2Width;
1295 GLsizei height = This->pow2Height;
1296 const BYTE *mem = NULL;
1301 internal = format->glGammaInternal;
1303 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(This))
1305 internal = format->rtInternal;
1309 internal = format->glInternal;
1312 if (format->heightscale != 1.0f && format->heightscale != 0.0f) height *= format->heightscale;
1314 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",
1315 This, This->texture_target, This->texture_level, debug_d3dformat(format->id),
1316 internal, width, height, format->glFormat, format->glType);
1320 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1322 if (This->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
1323 || !This->resource.allocatedMemory)
1325 /* In some cases we want to disable client storage.
1326 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
1327 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
1328 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
1329 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
1331 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1332 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1333 This->flags &= ~SFLAG_CLIENT;
1334 enable_client_storage = TRUE;
1338 This->flags |= SFLAG_CLIENT;
1340 /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
1341 * it might point into a pbo. Instead use heapMemory, but get the alignment right.
1343 mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1347 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
1349 GL_EXTCALL(glCompressedTexImage2DARB(This->texture_target, This->texture_level,
1350 internal, width, height, 0, This->resource.size, mem));
1351 checkGLcall("glCompressedTexImage2DARB");
1355 glTexImage2D(This->texture_target, This->texture_level,
1356 internal, width, height, 0, format->glFormat, format->glType, mem);
1357 checkGLcall("glTexImage2D");
1360 if(enable_client_storage) {
1361 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1362 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1367 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1368 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1369 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1370 /* GL locking is done by the caller */
1371 void surface_set_compatible_renderbuffer(IWineD3DSurfaceImpl *surface, IWineD3DSurfaceImpl *rt)
1373 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
1374 renderbuffer_entry_t *entry;
1375 GLuint renderbuffer = 0;
1376 unsigned int src_width, src_height;
1377 unsigned int width, height;
1379 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
1381 width = rt->pow2Width;
1382 height = rt->pow2Height;
1386 width = surface->pow2Width;
1387 height = surface->pow2Height;
1390 src_width = surface->pow2Width;
1391 src_height = surface->pow2Height;
1393 /* A depth stencil smaller than the render target is not valid */
1394 if (width > src_width || height > src_height) return;
1396 /* Remove any renderbuffer set if the sizes match */
1397 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1398 || (width == src_width && height == src_height))
1400 surface->current_renderbuffer = NULL;
1404 /* Look if we've already got a renderbuffer of the correct dimensions */
1405 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, renderbuffer_entry_t, entry)
1407 if (entry->width == width && entry->height == height)
1409 renderbuffer = entry->id;
1410 surface->current_renderbuffer = entry;
1417 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1418 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1419 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1420 surface->resource.format->glInternal, width, height);
1422 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
1423 entry->width = width;
1424 entry->height = height;
1425 entry->id = renderbuffer;
1426 list_add_head(&surface->renderbuffers, &entry->entry);
1428 surface->current_renderbuffer = entry;
1431 checkGLcall("set_compatible_renderbuffer");
1434 GLenum surface_get_gl_buffer(IWineD3DSurfaceImpl *surface)
1436 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
1438 TRACE("surface %p.\n", surface);
1440 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
1442 ERR("Surface %p is not on a swapchain.\n", surface);
1446 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
1448 if (swapchain->render_to_fbo)
1450 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1451 return GL_COLOR_ATTACHMENT0;
1453 TRACE("Returning GL_BACK\n");
1456 else if (surface == swapchain->front_buffer)
1458 TRACE("Returning GL_FRONT\n");
1462 FIXME("Higher back buffer, returning GL_BACK\n");
1466 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
1467 void surface_add_dirty_rect(IWineD3DSurfaceImpl *surface, const WINED3DBOX *dirty_rect)
1469 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
1471 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
1472 /* No partial locking for textures yet. */
1473 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1475 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1478 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->Left);
1479 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->Top);
1480 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->Right);
1481 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->Bottom);
1485 surface->dirtyRect.left = 0;
1486 surface->dirtyRect.top = 0;
1487 surface->dirtyRect.right = surface->resource.width;
1488 surface->dirtyRect.bottom = surface->resource.height;
1491 /* if the container is a texture then mark it dirty. */
1492 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
1494 TRACE("Passing to container.\n");
1495 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
1499 static BOOL surface_convert_color_to_float(IWineD3DSurfaceImpl *surface, DWORD color, WINED3DCOLORVALUE *float_color)
1501 const struct wined3d_format *format = surface->resource.format;
1502 IWineD3DDeviceImpl *device = surface->resource.device;
1506 case WINED3DFMT_P8_UINT:
1507 if (surface->palette)
1509 float_color->r = surface->palette->palents[color].peRed / 255.0f;
1510 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
1511 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
1515 float_color->r = 0.0f;
1516 float_color->g = 0.0f;
1517 float_color->b = 0.0f;
1519 float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
1522 case WINED3DFMT_B5G6R5_UNORM:
1523 float_color->r = ((color >> 11) & 0x1f) / 31.0f;
1524 float_color->g = ((color >> 5) & 0x3f) / 63.0f;
1525 float_color->b = (color & 0x1f) / 31.0f;
1526 float_color->a = 1.0f;
1529 case WINED3DFMT_B8G8R8_UNORM:
1530 case WINED3DFMT_B8G8R8X8_UNORM:
1531 float_color->r = D3DCOLOR_R(color);
1532 float_color->g = D3DCOLOR_G(color);
1533 float_color->b = D3DCOLOR_B(color);
1534 float_color->a = 1.0f;
1537 case WINED3DFMT_B8G8R8A8_UNORM:
1538 float_color->r = D3DCOLOR_R(color);
1539 float_color->g = D3DCOLOR_G(color);
1540 float_color->b = D3DCOLOR_B(color);
1541 float_color->a = D3DCOLOR_A(color);
1545 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1552 static BOOL surface_convert_depth_to_float(IWineD3DSurfaceImpl *surface, DWORD depth, float *float_depth)
1554 const struct wined3d_format *format = surface->resource.format;
1558 case WINED3DFMT_S1_UINT_D15_UNORM:
1559 *float_depth = depth / (float)0x00007fff;
1562 case WINED3DFMT_D16_UNORM:
1563 *float_depth = depth / (float)0x0000ffff;
1566 case WINED3DFMT_D24_UNORM_S8_UINT:
1567 case WINED3DFMT_X8D24_UNORM:
1568 *float_depth = depth / (float)0x00ffffff;
1571 case WINED3DFMT_D32_UNORM:
1572 *float_depth = depth / (float)0xffffffff;
1576 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1583 static void surface_evict_sysmem(IWineD3DSurfaceImpl *surface)
1585 if (surface->flags & SFLAG_DONOTFREE)
1588 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
1589 surface->resource.allocatedMemory = NULL;
1590 surface->resource.heapMemory = NULL;
1591 surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
1594 HRESULT surface_load(IWineD3DSurfaceImpl *surface, BOOL srgb)
1596 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
1598 TRACE("surface %p, srgb %#x.\n", surface, srgb);
1600 if (surface->resource.pool == WINED3DPOOL_SCRATCH)
1602 ERR("Not supported on scratch surfaces.\n");
1603 return WINED3DERR_INVALIDCALL;
1606 if (!(surface->flags & flag))
1608 TRACE("Reloading because surface is dirty\n");
1610 /* Reload if either the texture and sysmem have different ideas about the
1611 * color key, or the actual key values changed. */
1612 else if (!(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT)
1613 || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
1614 && (surface->glCKey.dwColorSpaceLowValue != surface->SrcBltCKey.dwColorSpaceLowValue
1615 || surface->glCKey.dwColorSpaceHighValue != surface->SrcBltCKey.dwColorSpaceHighValue)))
1617 TRACE("Reloading because of color keying\n");
1618 /* To perform the color key conversion we need a sysmem copy of
1619 * the surface. Make sure we have it. */
1621 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1622 /* Make sure the texture is reloaded because of the color key change,
1623 * this kills performance though :( */
1624 /* TODO: This is not necessarily needed with hw palettized texture support. */
1625 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1629 TRACE("surface is already in texture\n");
1633 /* No partial locking for textures yet. */
1634 surface_load_location(surface, flag, NULL);
1635 surface_evict_sysmem(surface);
1640 /* See also float_16_to_32() in wined3d_private.h */
1641 static inline unsigned short float_32_to_16(const float *in)
1644 float tmp = fabs(*in);
1645 unsigned int mantissa;
1648 /* Deal with special numbers */
1654 return (*in < 0.0f ? 0xfc00 : 0x7c00);
1656 if (tmp < powf(2, 10))
1662 } while (tmp < powf(2, 10));
1664 else if (tmp >= powf(2, 11))
1670 } while (tmp >= powf(2, 11));
1673 mantissa = (unsigned int)tmp;
1674 if (tmp - mantissa >= 0.5f)
1675 ++mantissa; /* Round to nearest, away from zero. */
1677 exp += 10; /* Normalize the mantissa. */
1678 exp += 15; /* Exponent is encoded with excess 15. */
1680 if (exp > 30) /* too big */
1682 ret = 0x7c00; /* INF */
1686 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1689 mantissa = mantissa >> 1;
1692 ret = mantissa & 0x3ff;
1696 ret = (exp << 10) | (mantissa & 0x3ff);
1699 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
1703 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface,
1704 REFIID riid, void **object)
1706 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
1708 if (IsEqualGUID(riid, &IID_IWineD3DSurface)
1709 || IsEqualGUID(riid, &IID_IUnknown))
1711 IUnknown_AddRef(iface);
1716 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
1719 return E_NOINTERFACE;
1722 static ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface)
1724 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1727 TRACE("Surface %p, container %p of type %#x.\n",
1728 surface, surface->container.u.base, surface->container.type);
1730 switch (surface->container.type)
1732 case WINED3D_CONTAINER_TEXTURE:
1733 return wined3d_texture_incref(surface->container.u.texture);
1735 case WINED3D_CONTAINER_SWAPCHAIN:
1736 return wined3d_swapchain_incref(surface->container.u.swapchain);
1739 ERR("Unhandled container type %#x.\n", surface->container.type);
1740 case WINED3D_CONTAINER_NONE:
1744 refcount = InterlockedIncrement(&surface->resource.ref);
1745 TRACE("%p increasing refcount to %u.\n", surface, refcount);
1750 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface,
1751 REFGUID riid, const void *data, DWORD data_size, DWORD flags)
1753 return resource_set_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, riid, data, data_size, flags);
1756 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface,
1757 REFGUID guid, void *data, DWORD *data_size)
1759 return resource_get_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, guid, data, data_size);
1762 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
1764 return resource_free_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, refguid);
1767 static DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
1769 return resource_set_priority(&((IWineD3DSurfaceImpl *)iface)->resource, priority);
1772 static DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
1774 return resource_get_priority(&((IWineD3DSurfaceImpl *)iface)->resource);
1777 static void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
1779 TRACE("iface %p.\n", iface);
1781 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
1784 static struct wined3d_resource * WINAPI IWineD3DBaseSurfaceImpl_GetResource(IWineD3DSurface *iface)
1786 TRACE("iface %p.\n", iface);
1788 return &((IWineD3DSurfaceImpl *)iface)->resource;
1791 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
1793 TRACE("iface %p, flags %#x.\n", iface, flags);
1797 case WINEDDGBS_CANBLT:
1798 case WINEDDGBS_ISBLTDONE:
1802 return WINED3DERR_INVALIDCALL;
1806 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
1808 /* XXX: DDERR_INVALIDSURFACETYPE */
1810 TRACE("iface %p, flags %#x.\n", iface, flags);
1814 case WINEDDGFS_CANFLIP:
1815 case WINEDDGFS_ISFLIPDONE:
1819 return WINED3DERR_INVALIDCALL;
1823 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface)
1825 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1827 TRACE("iface %p.\n", iface);
1829 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
1830 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
1833 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface)
1835 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1837 TRACE("iface %p.\n", iface);
1839 /* So far we don't lose anything :) */
1840 surface->flags &= ~SFLAG_LOST;
1844 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
1846 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1848 TRACE("iface %p, palette %p.\n", iface, palette);
1850 if (surface->palette == palette)
1852 TRACE("Nop palette change.\n");
1856 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
1857 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
1859 surface->palette = palette;
1863 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1864 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
1866 surface->surface_ops->surface_realize_palette(surface);
1872 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface,
1873 DWORD flags, const WINEDDCOLORKEY *color_key)
1875 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1877 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, color_key);
1879 if (flags & WINEDDCKEY_COLORSPACE)
1881 FIXME(" colorkey value not supported (%08x) !\n", flags);
1882 return WINED3DERR_INVALIDCALL;
1885 /* Dirtify the surface, but only if a key was changed. */
1888 switch (flags & ~WINEDDCKEY_COLORSPACE)
1890 case WINEDDCKEY_DESTBLT:
1891 surface->DestBltCKey = *color_key;
1892 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
1895 case WINEDDCKEY_DESTOVERLAY:
1896 surface->DestOverlayCKey = *color_key;
1897 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
1900 case WINEDDCKEY_SRCOVERLAY:
1901 surface->SrcOverlayCKey = *color_key;
1902 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
1905 case WINEDDCKEY_SRCBLT:
1906 surface->SrcBltCKey = *color_key;
1907 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
1913 switch (flags & ~WINEDDCKEY_COLORSPACE)
1915 case WINEDDCKEY_DESTBLT:
1916 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
1919 case WINEDDCKEY_DESTOVERLAY:
1920 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
1923 case WINEDDCKEY_SRCOVERLAY:
1924 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
1927 case WINEDDCKEY_SRCBLT:
1928 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
1936 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
1938 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) iface;
1940 TRACE("iface %p, palette %p.\n", iface, palette);
1942 *palette = surface->palette;
1947 static DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
1949 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1950 const struct wined3d_format *format = surface->resource.format;
1953 TRACE("iface %p.\n", iface);
1955 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1957 /* Since compressed formats are block based, pitch means the amount of
1958 * bytes to the next row of block rather than the next row of pixels. */
1959 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
1960 pitch = row_block_count * format->block_byte_count;
1964 unsigned char alignment = surface->resource.device->surface_alignment;
1965 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
1966 pitch = (pitch + alignment - 1) & ~(alignment - 1);
1969 TRACE("Returning %u.\n", pitch);
1974 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG x, LONG y)
1976 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1979 TRACE("iface %p, x %d, y %d.\n", iface, x, y);
1981 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
1983 WARN("Not an overlay surface.\n");
1984 return WINEDDERR_NOTAOVERLAYSURFACE;
1987 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
1988 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
1989 surface->overlay_destrect.left = x;
1990 surface->overlay_destrect.top = y;
1991 surface->overlay_destrect.right = x + w;
1992 surface->overlay_destrect.bottom = y + h;
1994 surface->surface_ops->surface_draw_overlay(surface);
1999 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *x, LONG *y)
2001 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2003 TRACE("iface %p, x %p, y %p.\n", iface, x, y);
2005 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2007 TRACE("Not an overlay surface.\n");
2008 return WINEDDERR_NOTAOVERLAYSURFACE;
2011 if (!surface->overlay_dest)
2013 TRACE("Overlay not visible.\n");
2016 return WINEDDERR_OVERLAYNOTVISIBLE;
2019 *x = surface->overlay_destrect.left;
2020 *y = surface->overlay_destrect.top;
2022 TRACE("Returning position %d, %d.\n", *x, *y);
2027 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface,
2028 DWORD flags, IWineD3DSurface *ref)
2030 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2032 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, ref);
2034 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2036 TRACE("Not an overlay surface.\n");
2037 return WINEDDERR_NOTAOVERLAYSURFACE;
2043 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *src_rect,
2044 IWineD3DSurface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
2046 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2047 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *)dst_surface;
2049 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2050 iface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
2052 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2054 WARN("Not an overlay surface.\n");
2055 return WINEDDERR_NOTAOVERLAYSURFACE;
2057 else if (!dst_surface)
2059 WARN("Dest surface is NULL.\n");
2060 return WINED3DERR_INVALIDCALL;
2065 surface->overlay_srcrect = *src_rect;
2069 surface->overlay_srcrect.left = 0;
2070 surface->overlay_srcrect.top = 0;
2071 surface->overlay_srcrect.right = surface->resource.width;
2072 surface->overlay_srcrect.bottom = surface->resource.height;
2077 surface->overlay_destrect = *dst_rect;
2081 surface->overlay_destrect.left = 0;
2082 surface->overlay_destrect.top = 0;
2083 surface->overlay_destrect.right = Dst ? Dst->resource.width : 0;
2084 surface->overlay_destrect.bottom = Dst ? Dst->resource.height : 0;
2087 if (surface->overlay_dest && (surface->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
2089 list_remove(&surface->overlay_entry);
2092 if (flags & WINEDDOVER_SHOW)
2094 if (surface->overlay_dest != Dst)
2096 surface->overlay_dest = Dst;
2097 list_add_tail(&Dst->overlays, &surface->overlay_entry);
2100 else if (flags & WINEDDOVER_HIDE)
2102 /* tests show that the rectangles are erased on hide */
2103 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
2104 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
2105 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
2106 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
2107 surface->overlay_dest = NULL;
2110 surface->surface_ops->surface_draw_overlay(surface);
2115 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
2117 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2119 TRACE("iface %p, clipper %p.\n", iface, clipper);
2121 surface->clipper = clipper;
2126 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
2128 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2130 TRACE("iface %p, clipper %p.\n", iface, clipper);
2132 *clipper = surface->clipper;
2134 wined3d_clipper_incref(*clipper);
2139 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
2141 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2142 const struct wined3d_format *format = wined3d_get_format(&surface->resource.device->adapter->gl_info, format_id);
2144 TRACE("iface %p, format %s.\n", iface, debug_d3dformat(format_id));
2146 if (surface->resource.format->id != WINED3DFMT_UNKNOWN)
2148 FIXME("The format of the surface must be WINED3DFORMAT_UNKNOWN.\n");
2149 return WINED3DERR_INVALIDCALL;
2152 surface->resource.size = wined3d_format_calculate_size(format, surface->resource.device->surface_alignment,
2153 surface->pow2Width, surface->pow2Height);
2154 surface->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
2155 surface->resource.format = format;
2157 TRACE("size %u, byte_count %u\n", surface->resource.size, format->byte_count);
2162 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
2163 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2165 unsigned short *dst_s;
2169 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2171 for (y = 0; y < h; ++y)
2173 src_f = (const float *)(src + y * pitch_in);
2174 dst_s = (unsigned short *) (dst + y * pitch_out);
2175 for (x = 0; x < w; ++x)
2177 dst_s[x] = float_32_to_16(src_f + x);
2182 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
2183 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2185 static const unsigned char convert_5to8[] =
2187 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2188 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2189 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2190 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2192 static const unsigned char convert_6to8[] =
2194 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2195 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2196 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2197 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2198 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2199 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2200 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2201 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2205 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2207 for (y = 0; y < h; ++y)
2209 const WORD *src_line = (const WORD *)(src + y * pitch_in);
2210 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2211 for (x = 0; x < w; ++x)
2213 WORD pixel = src_line[x];
2214 dst_line[x] = 0xff000000
2215 | convert_5to8[(pixel & 0xf800) >> 11] << 16
2216 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
2217 | convert_5to8[(pixel & 0x001f)];
2222 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
2223 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2227 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2229 for (y = 0; y < h; ++y)
2231 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
2232 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2234 for (x = 0; x < w; ++x)
2236 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
2241 static inline BYTE cliptobyte(int x)
2243 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
2246 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
2247 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2249 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
2252 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2254 for (y = 0; y < h; ++y)
2256 const BYTE *src_line = src + y * pitch_in;
2257 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2258 for (x = 0; x < w; ++x)
2260 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2261 * C = Y - 16; D = U - 128; E = V - 128;
2262 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2263 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2264 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2265 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2266 * U and V are shared between the pixels. */
2267 if (!(x & 1)) /* For every even pixel, read new U and V. */
2269 d = (int) src_line[1] - 128;
2270 e = (int) src_line[3] - 128;
2272 g2 = - 100 * d - 208 * e + 128;
2275 c2 = 298 * ((int) src_line[0] - 16);
2276 dst_line[x] = 0xff000000
2277 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
2278 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
2279 | cliptobyte((c2 + b2) >> 8); /* blue */
2280 /* Scale RGB values to 0..255 range,
2281 * then clip them if still not in range (may be negative),
2282 * then shift them within DWORD if necessary. */
2288 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
2289 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2292 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
2294 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
2296 for (y = 0; y < h; ++y)
2298 const BYTE *src_line = src + y * pitch_in;
2299 WORD *dst_line = (WORD *)(dst + y * pitch_out);
2300 for (x = 0; x < w; ++x)
2302 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2303 * C = Y - 16; D = U - 128; E = V - 128;
2304 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2305 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2306 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2307 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2308 * U and V are shared between the pixels. */
2309 if (!(x & 1)) /* For every even pixel, read new U and V. */
2311 d = (int) src_line[1] - 128;
2312 e = (int) src_line[3] - 128;
2314 g2 = - 100 * d - 208 * e + 128;
2317 c2 = 298 * ((int) src_line[0] - 16);
2318 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
2319 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
2320 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
2321 /* Scale RGB values to 0..255 range,
2322 * then clip them if still not in range (may be negative),
2323 * then shift them within DWORD if necessary. */
2329 struct d3dfmt_convertor_desc
2331 enum wined3d_format_id from, to;
2332 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
2335 static const struct d3dfmt_convertor_desc convertors[] =
2337 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
2338 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
2339 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
2340 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
2341 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
2344 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from,
2345 enum wined3d_format_id to)
2349 for (i = 0; i < (sizeof(convertors) / sizeof(*convertors)); ++i)
2351 if (convertors[i].from == from && convertors[i].to == to)
2352 return &convertors[i];
2358 /*****************************************************************************
2359 * surface_convert_format
2361 * Creates a duplicate of a surface in a different format. Is used by Blt to
2362 * blit between surfaces with different formats.
2365 * source: Source surface
2366 * fmt: Requested destination format
2368 *****************************************************************************/
2369 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
2371 const struct d3dfmt_convertor_desc *conv;
2372 WINED3DLOCKED_RECT lock_src, lock_dst;
2373 IWineD3DSurface *ret = NULL;
2376 conv = find_convertor(source->resource.format->id, to_fmt);
2379 FIXME("Cannot find a conversion function from format %s to %s.\n",
2380 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
2384 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->resource.width,
2385 source->resource.height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
2386 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
2387 0 /* MultiSampleQuality */, source->surface_type, NULL /* parent */, &wined3d_null_parent_ops, &ret);
2390 ERR("Failed to create a destination surface for conversion.\n");
2394 memset(&lock_src, 0, sizeof(lock_src));
2395 memset(&lock_dst, 0, sizeof(lock_dst));
2397 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
2400 ERR("Failed to lock the source surface.\n");
2401 IWineD3DSurface_Release(ret);
2404 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
2407 ERR("Failed to lock the destination surface.\n");
2408 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
2409 IWineD3DSurface_Release(ret);
2413 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
2414 source->resource.width, source->resource.height);
2416 IWineD3DSurface_Unmap(ret);
2417 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
2419 return (IWineD3DSurfaceImpl *)ret;
2422 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
2423 unsigned int bpp, UINT pitch, DWORD color)
2430 #define COLORFILL_ROW(type) \
2432 type *d = (type *)buf; \
2433 for (x = 0; x < width; ++x) \
2434 d[x] = (type)color; \
2440 COLORFILL_ROW(BYTE);
2444 COLORFILL_ROW(WORD);
2450 for (x = 0; x < width; ++x, d += 3)
2452 d[0] = (color ) & 0xFF;
2453 d[1] = (color >> 8) & 0xFF;
2454 d[2] = (color >> 16) & 0xFF;
2459 COLORFILL_ROW(DWORD);
2463 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
2464 return WINED3DERR_NOTAVAILABLE;
2467 #undef COLORFILL_ROW
2469 /* Now copy first row. */
2471 for (y = 1; y < height; ++y)
2474 memcpy(buf, first, width * bpp);
2480 /*****************************************************************************
2481 * IWineD3DSurface::Blt, SW emulation version
2483 * Performs a blit to a surface, with or without a source surface.
2484 * This is the main functionality of DirectDraw
2485 *****************************************************************************/
2486 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface,
2487 const RECT *dst_rect, IWineD3DSurface *src_surface, const RECT *src_rect,
2488 DWORD flags, const WINEDDBLTFX *fx, WINED3DTEXTUREFILTERTYPE filter)
2490 IWineD3DSurfaceImpl *dst_surface = (IWineD3DSurfaceImpl *)iface;
2491 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
2492 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
2493 const struct wined3d_format *src_format, *dst_format;
2494 WINED3DLOCKED_RECT dlock, slock;
2495 HRESULT ret = WINED3D_OK;
2501 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2502 iface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2503 flags, fx, debug_d3dtexturefiltertype(filter));
2505 if ((dst_surface->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
2507 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
2508 return WINEDDERR_SURFACEBUSY;
2511 /* First check for the validity of source / destination rectangles.
2512 * This was verified using a test application and by MSDN. */
2517 if (src_rect->right < src_rect->left || src_rect->bottom < src_rect->top
2518 || src_rect->left > src->resource.width || src_rect->left < 0
2519 || src_rect->top > src->resource.height || src_rect->top < 0
2520 || src_rect->right > src->resource.width || src_rect->right < 0
2521 || src_rect->bottom > src->resource.height || src_rect->bottom < 0)
2523 WARN("Application gave us bad source rectangle for Blt.\n");
2524 return WINEDDERR_INVALIDRECT;
2527 if (!src_rect->right || !src_rect->bottom
2528 || src_rect->left == (int)src->resource.width
2529 || src_rect->top == (int)src->resource.height)
2531 TRACE("Nothing to be done.\n");
2542 xsrc.right = src->resource.width;
2543 xsrc.bottom = src->resource.height;
2547 memset(&xsrc, 0, sizeof(xsrc));
2552 /* For the Destination rect, it can be out of bounds on the condition
2553 * that a clipper is set for the given surface. */
2554 if (!dst_surface->clipper && (dst_rect->right < dst_rect->left || dst_rect->bottom < dst_rect->top
2555 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
2556 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
2557 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
2558 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0))
2560 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
2561 return WINEDDERR_INVALIDRECT;
2564 if (dst_rect->right <= 0 || dst_rect->bottom <= 0
2565 || dst_rect->left >= (int)dst_surface->resource.width
2566 || dst_rect->top >= (int)dst_surface->resource.height)
2568 TRACE("Nothing to be done.\n");
2578 full_rect.right = dst_surface->resource.width;
2579 full_rect.bottom = dst_surface->resource.height;
2580 IntersectRect(&xdst, &full_rect, dst_rect);
2584 BOOL clip_horiz, clip_vert;
2587 clip_horiz = xdst.left < 0 || xdst.right > (int)dst_surface->resource.width;
2588 clip_vert = xdst.top < 0 || xdst.bottom > (int)dst_surface->resource.height;
2590 if (clip_vert || clip_horiz)
2592 /* Now check if this is a special case or not... */
2593 if ((flags & WINEDDBLT_DDFX)
2594 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
2595 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
2597 WARN("Out of screen rectangle in special case. Not handled right now.\n");
2605 xsrc.left -= xdst.left;
2608 if (xdst.right > dst_surface->resource.width)
2610 xsrc.right -= (xdst.right - (int)dst_surface->resource.width);
2611 xdst.right = (int)dst_surface->resource.width;
2619 xsrc.top -= xdst.top;
2622 if (xdst.bottom > dst_surface->resource.height)
2624 xsrc.bottom -= (xdst.bottom - (int)dst_surface->resource.height);
2625 xdst.bottom = (int)dst_surface->resource.height;
2629 /* And check if after clipping something is still to be done... */
2630 if ((xdst.right <= 0) || (xdst.bottom <= 0)
2631 || (xdst.left >= (int)dst_surface->resource.width)
2632 || (xdst.top >= (int)dst_surface->resource.height)
2633 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
2634 || (xsrc.left >= (int)src->resource.width)
2635 || (xsrc.top >= (int)src->resource.height))
2637 TRACE("Nothing to be done after clipping.\n");
2647 xdst.right = dst_surface->resource.width;
2648 xdst.bottom = dst_surface->resource.height;
2651 if (src == dst_surface)
2653 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
2655 src_format = dst_surface->resource.format;
2656 dst_format = src_format;
2660 dst_format = dst_surface->resource.format;
2663 if (dst_surface->resource.format->id != src->resource.format->id)
2665 src = surface_convert_format(src, dst_format->id);
2668 /* The conv function writes a FIXME */
2669 WARN("Cannot convert source surface format to dest format\n");
2673 IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
2674 src_format = src->resource.format;
2678 src_format = dst_format;
2681 IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
2683 IWineD3DSurface_Map(iface, &dlock, NULL, 0);
2686 if (!fx || !(fx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
2688 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_FOURCC)
2690 if (!dst_rect || src == dst_surface)
2692 memcpy(dlock.pBits, slock.pBits, dst_surface->resource.size);
2697 bpp = dst_surface->resource.format->byte_count;
2698 srcheight = xsrc.bottom - xsrc.top;
2699 srcwidth = xsrc.right - xsrc.left;
2700 dstheight = xdst.bottom - xdst.top;
2701 dstwidth = xdst.right - xdst.left;
2702 width = (xdst.right - xdst.left) * bpp;
2704 if (dst_rect && src != dst_surface)
2707 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
2709 if (flags & WINEDDBLT_WAIT)
2711 flags &= ~WINEDDBLT_WAIT;
2713 if (flags & WINEDDBLT_ASYNC)
2715 static BOOL displayed = FALSE;
2717 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
2719 flags &= ~WINEDDBLT_ASYNC;
2721 if (flags & WINEDDBLT_DONOTWAIT)
2723 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
2724 static BOOL displayed = FALSE;
2726 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
2728 flags &= ~WINEDDBLT_DONOTWAIT;
2731 /* First, all the 'source-less' blits */
2732 if (flags & WINEDDBLT_COLORFILL)
2734 ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dlock.Pitch, fx->u5.dwFillColor);
2735 flags &= ~WINEDDBLT_COLORFILL;
2738 if (flags & WINEDDBLT_DEPTHFILL)
2740 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
2742 if (flags & WINEDDBLT_ROP)
2744 /* Catch some degenerate cases here. */
2748 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
2750 case 0xAA0029: /* No-op */
2753 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
2755 case SRCCOPY: /* Well, we do that below? */
2758 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
2761 flags &= ~WINEDDBLT_ROP;
2763 if (flags & WINEDDBLT_DDROPS)
2765 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
2767 /* Now the 'with source' blits. */
2771 int sx, xinc, sy, yinc;
2773 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
2776 if (filter != WINED3DTEXF_NONE && filter != WINED3DTEXF_POINT
2777 && (srcwidth != dstwidth || srcheight != dstheight))
2779 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
2780 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
2783 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
2784 xinc = (srcwidth << 16) / dstwidth;
2785 yinc = (srcheight << 16) / dstheight;
2789 /* No effects, we can cheat here. */
2790 if (dstwidth == srcwidth)
2792 if (dstheight == srcheight)
2794 /* No stretching in either direction. This needs to be as
2795 * fast as possible. */
2798 /* Check for overlapping surfaces. */
2799 if (src != dst_surface || xdst.top < xsrc.top
2800 || xdst.right <= xsrc.left || xsrc.right <= xdst.left)
2802 /* No overlap, or dst above src, so copy from top downwards. */
2803 for (y = 0; y < dstheight; ++y)
2805 memcpy(dbuf, sbuf, width);
2806 sbuf += slock.Pitch;
2807 dbuf += dlock.Pitch;
2810 else if (xdst.top > xsrc.top)
2812 /* Copy from bottom upwards. */
2813 sbuf += (slock.Pitch*dstheight);
2814 dbuf += (dlock.Pitch*dstheight);
2815 for (y = 0; y < dstheight; ++y)
2817 sbuf -= slock.Pitch;
2818 dbuf -= dlock.Pitch;
2819 memcpy(dbuf, sbuf, width);
2824 /* Src and dst overlapping on the same line, use memmove. */
2825 for (y = 0; y < dstheight; ++y)
2827 memmove(dbuf, sbuf, width);
2828 sbuf += slock.Pitch;
2829 dbuf += dlock.Pitch;
2835 /* Stretching in y direction only. */
2836 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
2838 sbuf = sbase + (sy >> 16) * slock.Pitch;
2839 memcpy(dbuf, sbuf, width);
2840 dbuf += dlock.Pitch;
2846 /* Stretching in X direction. */
2848 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
2850 sbuf = sbase + (sy >> 16) * slock.Pitch;
2852 if ((sy >> 16) == (last_sy >> 16))
2854 /* This source row is the same as last source row -
2855 * Copy the already stretched row. */
2856 memcpy(dbuf, dbuf - dlock.Pitch, width);
2860 #define STRETCH_ROW(type) \
2862 const type *s = (const type *)sbuf; \
2863 type *d = (type *)dbuf; \
2864 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
2865 d[x] = s[sx >> 16]; \
2883 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
2887 s = sbuf + 3 * (sx >> 16);
2888 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
2889 d[0] = (pixel ) & 0xff;
2890 d[1] = (pixel >> 8) & 0xff;
2891 d[2] = (pixel >> 16) & 0xff;
2897 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
2898 ret = WINED3DERR_NOTAVAILABLE;
2903 dbuf += dlock.Pitch;
2910 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
2911 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
2912 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
2913 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
2915 /* The color keying flags are checked for correctness in ddraw */
2916 if (flags & WINEDDBLT_KEYSRC)
2918 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
2919 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
2921 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
2923 keylow = fx->ddckSrcColorkey.dwColorSpaceLowValue;
2924 keyhigh = fx->ddckSrcColorkey.dwColorSpaceHighValue;
2927 if (flags & WINEDDBLT_KEYDEST)
2929 /* Destination color keys are taken from the source surface! */
2930 destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
2931 destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
2933 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
2935 destkeylow = fx->ddckDestColorkey.dwColorSpaceLowValue;
2936 destkeyhigh = fx->ddckDestColorkey.dwColorSpaceHighValue;
2945 keymask = src_format->red_mask
2946 | src_format->green_mask
2947 | src_format->blue_mask;
2949 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
2952 if (flags & WINEDDBLT_DDFX)
2954 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
2957 dTopRight = dbuf + ((dstwidth - 1) * bpp);
2958 dBottomLeft = dTopLeft + ((dstheight - 1) * dlock.Pitch);
2959 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
2961 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
2963 /* I don't think we need to do anything about this flag */
2964 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
2966 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
2969 dTopRight = dTopLeft;
2972 dBottomRight = dBottomLeft;
2974 dstxinc = dstxinc * -1;
2976 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
2979 dTopLeft = dBottomLeft;
2982 dTopRight = dBottomRight;
2984 dstyinc = dstyinc * -1;
2986 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
2988 /* I don't think we need to do anything about this flag */
2989 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
2991 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
2994 dBottomRight = dTopLeft;
2997 dBottomLeft = dTopRight;
2999 dstxinc = dstxinc * -1;
3000 dstyinc = dstyinc * -1;
3002 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
3005 dTopLeft = dBottomLeft;
3006 dBottomLeft = dBottomRight;
3007 dBottomRight = dTopRight;
3012 dstxinc = dstxinc * -1;
3014 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
3017 dTopLeft = dTopRight;
3018 dTopRight = dBottomRight;
3019 dBottomRight = dBottomLeft;
3024 dstyinc = dstyinc * -1;
3026 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
3028 /* I don't think we need to do anything about this flag */
3029 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
3032 flags &= ~(WINEDDBLT_DDFX);
3035 #define COPY_COLORKEY_FX(type) \
3038 type *d = (type *)dbuf, *dx, tmp; \
3039 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
3041 s = (const type *)(sbase + (sy >> 16) * slock.Pitch); \
3043 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
3045 tmp = s[sx >> 16]; \
3046 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
3047 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
3051 dx = (type *)(((BYTE *)dx) + dstxinc); \
3053 d = (type *)(((BYTE *)d) + dstyinc); \
3060 COPY_COLORKEY_FX(BYTE);
3063 COPY_COLORKEY_FX(WORD);
3066 COPY_COLORKEY_FX(DWORD);
3071 BYTE *d = dbuf, *dx;
3072 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
3074 sbuf = sbase + (sy >> 16) * slock.Pitch;
3076 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
3078 DWORD pixel, dpixel = 0;
3079 s = sbuf + 3 * (sx>>16);
3080 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3081 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
3082 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
3083 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
3085 dx[0] = (pixel ) & 0xff;
3086 dx[1] = (pixel >> 8) & 0xff;
3087 dx[2] = (pixel >> 16) & 0xff;
3096 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
3097 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
3098 ret = WINED3DERR_NOTAVAILABLE;
3100 #undef COPY_COLORKEY_FX
3106 if (flags && FIXME_ON(d3d_surface))
3108 FIXME("\tUnsupported flags: %#x.\n", flags);
3112 IWineD3DSurface_Unmap(iface);
3113 if (src && src != dst_surface)
3114 IWineD3DSurface_Unmap((IWineD3DSurface *)src);
3115 /* Release the converted surface, if any. */
3116 if (src && src_surface != (IWineD3DSurface *)src)
3117 IWineD3DSurface_Release((IWineD3DSurface *)src);
3121 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface,
3122 DWORD dstx, DWORD dsty, IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
3124 IWineD3DSurfaceImpl *dst_surface = (IWineD3DSurfaceImpl *)iface;
3125 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
3126 const struct wined3d_format *src_format, *dst_format;
3127 RECT lock_src, lock_dst, lock_union;
3128 WINED3DLOCKED_RECT dlock, slock;
3129 HRESULT ret = WINED3D_OK;
3130 int bpp, w, h, x, y;
3135 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
3136 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
3138 if ((dst_surface->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
3140 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3141 return WINEDDERR_SURFACEBUSY;
3146 WARN("rsrc is NULL!\n");
3149 rsrc2.right = src->resource.width;
3150 rsrc2.bottom = src->resource.height;
3154 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate. */
3155 if ((rsrc->bottom > src->resource.height) || (rsrc->bottom < 0)
3156 || (rsrc->top > src->resource.height) || (rsrc->top < 0)
3157 || (rsrc->left > src->resource.width) || (rsrc->left < 0)
3158 || (rsrc->right > src->resource.width) || (rsrc->right < 0)
3159 || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
3161 WARN("Application gave us bad source rectangle for BltFast.\n");
3162 return WINEDDERR_INVALIDRECT;
3165 h = rsrc->bottom - rsrc->top;
3166 if (h > dst_surface->resource.height-dsty)
3167 h = dst_surface->resource.height-dsty;
3168 if (h > src->resource.height-rsrc->top)
3169 h = src->resource.height-rsrc->top;
3171 return WINEDDERR_INVALIDRECT;
3173 w = rsrc->right - rsrc->left;
3174 if (w > dst_surface->resource.width-dstx)
3175 w = dst_surface->resource.width-dstx;
3176 if (w > src->resource.width-rsrc->left)
3177 w = src->resource.width-rsrc->left;
3179 return WINEDDERR_INVALIDRECT;
3181 /* Now compute the locking rectangle... */
3182 lock_src.left = rsrc->left;
3183 lock_src.top = rsrc->top;
3184 lock_src.right = lock_src.left + w;
3185 lock_src.bottom = lock_src.top + h;
3187 lock_dst.left = dstx;
3188 lock_dst.top = dsty;
3189 lock_dst.right = dstx + w;
3190 lock_dst.bottom = dsty + h;
3192 bpp = dst_surface->resource.format->byte_count;
3194 /* We need to lock the surfaces, or we won't get refreshes when done. */
3195 if (src == dst_surface)
3199 UnionRect(&lock_union, &lock_src, &lock_dst);
3201 /* Lock the union of the two rectangles */
3202 ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
3206 pitch = dlock.Pitch;
3207 slock.Pitch = dlock.Pitch;
3209 /* Since slock was originally copied from this surface's description, we can just reuse it. */
3210 sbuf = dst_surface->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
3211 dbuf = dst_surface->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
3212 src_format = src->resource.format;
3213 dst_format = src_format;
3217 ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
3220 ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
3226 TRACE("Dst is at %p, Src is at %p.\n", dbuf, sbuf);
3228 src_format = src->resource.format;
3229 dst_format = dst_surface->resource.format;
3232 /* Handle compressed surfaces first... */
3233 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
3235 UINT row_block_count;
3237 TRACE("compressed -> compressed copy\n");
3239 FIXME("trans arg not supported when a compressed surface is involved\n");
3241 FIXME("offset for destination surface is not supported\n");
3242 if (src->resource.format->id != dst_surface->resource.format->id)
3244 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
3245 ret = WINED3DERR_WRONGTEXTUREFORMAT;
3249 row_block_count = (w + dst_format->block_width - 1) / dst_format->block_width;
3250 for (y = 0; y < h; y += dst_format->block_height)
3252 memcpy(dbuf, sbuf, row_block_count * dst_format->block_byte_count);
3253 dbuf += dlock.Pitch;
3254 sbuf += slock.Pitch;
3259 if ((src_format->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dst_format->flags & WINED3DFMT_FLAG_COMPRESSED))
3261 /* TODO: Use the libtxc_dxtn.so shared library to do software
3263 ERR("Software decompression not supported.\n");
3267 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
3269 DWORD keylow, keyhigh;
3270 DWORD mask = src->resource.format->red_mask
3271 | src->resource.format->green_mask
3272 | src->resource.format->blue_mask;
3274 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
3275 if (!mask && bpp == 1)
3278 TRACE("Color keyed copy.\n");
3279 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
3281 keylow = src->SrcBltCKey.dwColorSpaceLowValue;
3282 keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
3286 /* I'm not sure if this is correct. */
3287 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
3288 keylow = dst_surface->DestBltCKey.dwColorSpaceLowValue;
3289 keyhigh = dst_surface->DestBltCKey.dwColorSpaceHighValue;
3292 #define COPYBOX_COLORKEY(type) \
3294 const type *s = (const type *)sbuf; \
3295 type *d = (type *)dbuf; \
3297 for (y = 0; y < h; y++) \
3299 for (x = 0; x < w; x++) \
3302 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
3304 s = (const type *)((const BYTE *)s + slock.Pitch); \
3305 d = (type *)((BYTE *)d + dlock.Pitch); \
3312 COPYBOX_COLORKEY(BYTE);
3315 COPYBOX_COLORKEY(WORD);
3318 COPYBOX_COLORKEY(DWORD);
3327 for (y = 0; y < h; ++y)
3329 for (x = 0; x < w * 3; x += 3)
3331 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
3332 if (tmp < keylow || tmp > keyhigh)
3334 d[x + 0] = s[x + 0];
3335 d[x + 1] = s[x + 1];
3336 d[x + 2] = s[x + 2];
3345 FIXME("Source color key blitting not supported for bpp %u.\n", bpp * 8);
3346 ret = WINED3DERR_NOTAVAILABLE;
3349 #undef COPYBOX_COLORKEY
3350 TRACE("Copy done.\n");
3354 int width = w * bpp;
3355 INT sbufpitch, dbufpitch;
3357 TRACE("No color key copy.\n");
3358 /* Handle overlapping surfaces. */
3361 sbuf += (h - 1) * slock.Pitch;
3362 dbuf += (h - 1) * dlock.Pitch;
3363 sbufpitch = -slock.Pitch;
3364 dbufpitch = -dlock.Pitch;
3368 sbufpitch = slock.Pitch;
3369 dbufpitch = dlock.Pitch;
3371 for (y = 0; y < h; ++y)
3373 /* This is pretty easy, a line for line memcpy. */
3374 memmove(dbuf, sbuf, width);
3378 TRACE("Copy done.\n");
3382 if (src == dst_surface)
3384 IWineD3DSurface_Unmap(iface);
3388 IWineD3DSurface_Unmap(iface);
3389 IWineD3DSurface_Unmap(src_surface);
3395 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
3396 WINED3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
3398 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3400 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
3401 iface, locked_rect, wine_dbgstr_rect(rect), flags);
3403 locked_rect->Pitch = IWineD3DSurface_GetPitch(iface);
3407 locked_rect->pBits = surface->resource.allocatedMemory;
3408 surface->lockedRect.left = 0;
3409 surface->lockedRect.top = 0;
3410 surface->lockedRect.right = surface->resource.width;
3411 surface->lockedRect.bottom = surface->resource.height;
3415 const struct wined3d_format *format = surface->resource.format;
3417 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
3419 /* Compressed textures are block based, so calculate the offset of
3420 * the block that contains the top-left pixel of the locked rectangle. */
3421 locked_rect->pBits = surface->resource.allocatedMemory
3422 + ((rect->top / format->block_height) * locked_rect->Pitch)
3423 + ((rect->left / format->block_width) * format->block_byte_count);
3427 locked_rect->pBits = surface->resource.allocatedMemory
3428 + (locked_rect->Pitch * rect->top)
3429 + (rect->left * format->byte_count);
3431 surface->lockedRect.left = rect->left;
3432 surface->lockedRect.top = rect->top;
3433 surface->lockedRect.right = rect->right;
3434 surface->lockedRect.bottom = rect->bottom;
3437 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3438 TRACE("Returning memory %p, pitch %u.\n", locked_rect->pBits, locked_rect->Pitch);
3442 /* Do not call while under the GL lock. */
3443 static ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface)
3445 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3448 TRACE("Surface %p, container %p of type %#x.\n",
3449 surface, surface->container.u.base, surface->container.type);
3451 switch (surface->container.type)
3453 case WINED3D_CONTAINER_TEXTURE:
3454 return wined3d_texture_decref(surface->container.u.texture);
3456 case WINED3D_CONTAINER_SWAPCHAIN:
3457 return wined3d_swapchain_decref(surface->container.u.swapchain);
3460 ERR("Unhandled container type %#x.\n", surface->container.type);
3461 case WINED3D_CONTAINER_NONE:
3465 refcount = InterlockedDecrement(&surface->resource.ref);
3466 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3470 surface_cleanup(surface);
3471 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3473 TRACE("Destroyed surface %p.\n", surface);
3474 HeapFree(GetProcessHeap(), 0, surface);
3480 /* ****************************************************
3481 IWineD3DSurface IWineD3DResource parts follow
3482 **************************************************** */
3484 /* Do not call while under the GL lock. */
3485 void surface_internal_preload(IWineD3DSurfaceImpl *surface, enum WINED3DSRGB srgb)
3487 IWineD3DDeviceImpl *device = surface->resource.device;
3489 TRACE("iface %p, srgb %#x.\n", surface, srgb);
3491 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
3493 struct wined3d_texture *texture = surface->container.u.texture;
3495 TRACE("Passing to container (%p).\n", texture);
3496 texture->texture_ops->texture_preload(texture, srgb);
3500 struct wined3d_context *context = NULL;
3502 TRACE("(%p) : About to load surface\n", surface);
3504 if (!device->isInDraw) context = context_acquire(device, NULL);
3506 if (surface->resource.format->id == WINED3DFMT_P8_UINT
3507 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
3509 if (palette9_changed(surface))
3511 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
3512 /* TODO: This is not necessarily needed with hw palettized texture support */
3513 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3514 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
3515 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
3519 surface_load(surface, srgb == SRGB_SRGB ? TRUE : FALSE);
3521 if (surface->resource.pool == WINED3DPOOL_DEFAULT)
3523 /* Tell opengl to try and keep this texture in video ram (well mostly) */
3527 glPrioritizeTextures(1, &surface->texture_name, &tmp);
3531 if (context) context_release(context);
3535 static void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface)
3537 surface_internal_preload((IWineD3DSurfaceImpl *)iface, SRGB_ANY);
3540 BOOL surface_init_sysmem(IWineD3DSurfaceImpl *surface)
3542 if (!surface->resource.allocatedMemory)
3544 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3545 surface->resource.size + RESOURCE_ALIGNMENT);
3546 if (!surface->resource.heapMemory)
3548 ERR("Out of memory\n");
3551 surface->resource.allocatedMemory =
3552 (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
3556 memset(surface->resource.allocatedMemory, 0, surface->resource.size);
3559 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3564 /* ******************************************************
3565 IWineD3DSurface IWineD3DSurface parts follow
3566 ****************************************************** */
3568 /* Read the framebuffer back into the surface */
3569 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, const RECT *rect, void *dest, UINT pitch)
3571 IWineD3DDeviceImpl *device = This->resource.device;
3572 const struct wined3d_gl_info *gl_info;
3573 struct wined3d_context *context;
3577 BYTE *row, *top, *bottom;
3581 BOOL srcIsUpsideDown;
3586 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
3587 static BOOL warned = FALSE;
3589 ERR("The application tries to lock the render target, but render target locking is disabled\n");
3595 context = context_acquire(device, This);
3596 context_apply_blit_state(context, device);
3597 gl_info = context->gl_info;
3601 /* Select the correct read buffer, and give some debug output.
3602 * There is no need to keep track of the current read buffer or reset it, every part of the code
3603 * that reads sets the read buffer as desired.
3605 if (surface_is_offscreen(This))
3607 /* Mapping the primary render target which is not on a swapchain.
3608 * Read from the back buffer. */
3609 TRACE("Mapping offscreen render target.\n");
3610 glReadBuffer(device->offscreenBuffer);
3611 srcIsUpsideDown = TRUE;
3615 /* Onscreen surfaces are always part of a swapchain */
3616 GLenum buffer = surface_get_gl_buffer(This);
3617 TRACE("Mapping %#x buffer.\n", buffer);
3618 glReadBuffer(buffer);
3619 checkGLcall("glReadBuffer");
3620 srcIsUpsideDown = FALSE;
3623 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
3625 local_rect.left = 0;
3627 local_rect.right = This->resource.width;
3628 local_rect.bottom = This->resource.height;
3634 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
3636 switch (This->resource.format->id)
3638 case WINED3DFMT_P8_UINT:
3640 if (primary_render_target_is_p8(device))
3642 /* In case of P8 render targets the index is stored in the alpha component */
3644 type = GL_UNSIGNED_BYTE;
3646 bpp = This->resource.format->byte_count;
3648 /* GL can't return palettized data, so read ARGB pixels into a
3649 * separate block of memory and convert them into palettized format
3650 * in software. Slow, but if the app means to use palettized render
3651 * targets and locks it...
3653 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
3654 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
3655 * for the color channels when palettizing the colors.
3658 type = GL_UNSIGNED_BYTE;
3660 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
3662 ERR("Out of memory\n");
3666 bpp = This->resource.format->byte_count * 3;
3673 fmt = This->resource.format->glFormat;
3674 type = This->resource.format->glType;
3675 bpp = This->resource.format->byte_count;
3678 if (This->flags & SFLAG_PBO)
3680 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
3681 checkGLcall("glBindBufferARB");
3684 ERR("mem not null for pbo -- unexpected\n");
3689 /* Save old pixel store pack state */
3690 glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
3691 checkGLcall("glGetIntegerv");
3692 glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
3693 checkGLcall("glGetIntegerv");
3694 glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
3695 checkGLcall("glGetIntegerv");
3697 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3698 glPixelStorei(GL_PACK_ROW_LENGTH, This->resource.width);
3699 checkGLcall("glPixelStorei");
3700 glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
3701 checkGLcall("glPixelStorei");
3702 glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
3703 checkGLcall("glPixelStorei");
3705 glReadPixels(local_rect.left, !srcIsUpsideDown ? (This->resource.height - local_rect.bottom) : local_rect.top,
3706 local_rect.right - local_rect.left,
3707 local_rect.bottom - local_rect.top,
3709 checkGLcall("glReadPixels");
3711 /* Reset previous pixel store pack state */
3712 glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
3713 checkGLcall("glPixelStorei");
3714 glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
3715 checkGLcall("glPixelStorei");
3716 glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
3717 checkGLcall("glPixelStorei");
3719 if (This->flags & SFLAG_PBO)
3721 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
3722 checkGLcall("glBindBufferARB");
3724 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
3725 * to get a pointer to it and perform the flipping in software. This is a lot
3726 * faster than calling glReadPixels for each line. In case we want more speed
3727 * we should rerender it flipped in a FBO and read the data back from the FBO. */
3728 if(!srcIsUpsideDown) {
3729 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
3730 checkGLcall("glBindBufferARB");
3732 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
3733 checkGLcall("glMapBufferARB");
3737 /* TODO: Merge this with the palettization loop below for P8 targets */
3738 if(!srcIsUpsideDown) {
3740 /* glReadPixels returns the image upside down, and there is no way to prevent this.
3741 Flip the lines in software */
3742 len = (local_rect.right - local_rect.left) * bpp;
3743 off = local_rect.left * bpp;
3745 row = HeapAlloc(GetProcessHeap(), 0, len);
3747 ERR("Out of memory\n");
3748 if (This->resource.format->id == WINED3DFMT_P8_UINT) HeapFree(GetProcessHeap(), 0, mem);
3753 top = mem + pitch * local_rect.top;
3754 bottom = mem + pitch * (local_rect.bottom - 1);
3755 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
3756 memcpy(row, top + off, len);
3757 memcpy(top + off, bottom + off, len);
3758 memcpy(bottom + off, row, len);
3762 HeapFree(GetProcessHeap(), 0, row);
3764 /* Unmap the temp PBO buffer */
3765 if (This->flags & SFLAG_PBO)
3767 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
3768 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
3773 context_release(context);
3775 /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
3776 * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
3777 * the same color but we have no choice.
3778 * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
3780 if (This->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
3782 const PALETTEENTRY *pal = NULL;
3783 DWORD width = pitch / 3;
3787 pal = This->palette->palents;
3789 ERR("Palette is missing, cannot perform inverse palette lookup\n");
3790 HeapFree(GetProcessHeap(), 0, mem);
3794 for(y = local_rect.top; y < local_rect.bottom; y++) {
3795 for(x = local_rect.left; x < local_rect.right; x++) {
3796 /* start lines pixels */
3797 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
3798 const BYTE *green = blue + 1;
3799 const BYTE *red = green + 1;
3801 for(c = 0; c < 256; c++) {
3802 if(*red == pal[c].peRed &&
3803 *green == pal[c].peGreen &&
3804 *blue == pal[c].peBlue)
3806 *((BYTE *) dest + y * width + x) = c;
3812 HeapFree(GetProcessHeap(), 0, mem);
3816 /* Read the framebuffer contents into a texture */
3817 static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb)
3819 IWineD3DDeviceImpl *device = This->resource.device;
3820 const struct wined3d_gl_info *gl_info;
3821 struct wined3d_context *context;
3823 if (!surface_is_offscreen(This))
3825 /* We would need to flip onscreen surfaces, but there's no efficient
3826 * way to do that here. It makes more sense for the caller to
3827 * explicitly go through sysmem. */
3828 ERR("Not supported for onscreen targets.\n");
3832 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
3833 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
3834 * states in the stateblock, and no driver was found yet that had bugs in that regard.
3836 context = context_acquire(device, This);
3837 gl_info = context->gl_info;
3839 surface_prepare_texture(This, gl_info, srgb);
3840 surface_bind_and_dirtify(This, gl_info, srgb);
3842 TRACE("Reading back offscreen render target %p.\n", This);
3846 glReadBuffer(device->offscreenBuffer);
3847 checkGLcall("glReadBuffer");
3849 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3850 0, 0, 0, 0, This->resource.width, This->resource.height);
3851 checkGLcall("glCopyTexSubImage2D");
3855 context_release(context);
3858 /* Context activation is done by the caller. */
3859 static void surface_prepare_texture_internal(IWineD3DSurfaceImpl *surface,
3860 const struct wined3d_gl_info *gl_info, BOOL srgb)
3862 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
3863 CONVERT_TYPES convert;
3864 struct wined3d_format format;
3866 if (surface->flags & alloc_flag) return;
3868 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
3869 if (convert != NO_CONVERSION || format.convert) surface->flags |= SFLAG_CONVERTED;
3870 else surface->flags &= ~SFLAG_CONVERTED;
3872 surface_bind_and_dirtify(surface, gl_info, srgb);
3873 surface_allocate_surface(surface, gl_info, &format, srgb);
3874 surface->flags |= alloc_flag;
3877 /* Context activation is done by the caller. */
3878 void surface_prepare_texture(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
3880 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
3882 struct wined3d_texture *texture = surface->container.u.texture;
3883 UINT sub_count = texture->level_count * texture->layer_count;
3886 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
3888 for (i = 0; i < sub_count; ++i)
3890 IWineD3DSurfaceImpl *s = surface_from_resource(texture->sub_resources[i]);
3891 surface_prepare_texture_internal(s, gl_info, srgb);
3897 surface_prepare_texture_internal(surface, gl_info, srgb);
3900 static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This)
3902 IWineD3DDeviceImpl *device = This->resource.device;
3903 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3905 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
3906 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
3909 if (!(This->flags & SFLAG_DYNLOCK))
3912 /* MAXLOCKCOUNT is defined in wined3d_private.h */
3913 if(This->lockCount > MAXLOCKCOUNT) {
3914 TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
3915 This->flags |= SFLAG_DYNLOCK;
3919 /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
3920 * Also don't create a PBO for systemmem surfaces.
3922 if (gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && (This->flags & SFLAG_DYNLOCK)
3923 && !(This->flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2))
3924 && (This->resource.pool != WINED3DPOOL_SYSTEMMEM))
3927 struct wined3d_context *context;
3929 context = context_acquire(device, NULL);
3932 GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
3933 error = glGetError();
3934 if (!This->pbo || error != GL_NO_ERROR)
3935 ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
3937 TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
3939 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
3940 checkGLcall("glBindBufferARB");
3942 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
3943 checkGLcall("glBufferDataARB");
3945 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
3946 checkGLcall("glBindBufferARB");
3948 /* We don't need the system memory anymore and we can't even use it for PBOs */
3949 if (!(This->flags & SFLAG_CLIENT))
3951 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
3952 This->resource.heapMemory = NULL;
3954 This->resource.allocatedMemory = NULL;
3955 This->flags |= SFLAG_PBO;
3957 context_release(context);
3959 else if (!(This->resource.allocatedMemory || This->flags & SFLAG_PBO))
3961 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
3964 if(!This->resource.heapMemory) {
3965 This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
3967 This->resource.allocatedMemory =
3968 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
3969 if (This->flags & SFLAG_INSYSMEM)
3971 ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
3976 static HRESULT WINAPI IWineD3DSurfaceImpl_Map(IWineD3DSurface *iface,
3977 WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
3979 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3980 IWineD3DDeviceImpl *device = This->resource.device;
3981 const RECT *pass_rect = pRect;
3983 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
3984 iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
3986 /* This is also done in the base class, but we have to verify this before loading any data from
3987 * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
3988 * may interfere, and all other bad things may happen
3990 if (This->flags & SFLAG_LOCKED)
3992 WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
3993 return WINED3DERR_INVALIDCALL;
3995 This->flags |= SFLAG_LOCKED;
3997 if (!(This->flags & SFLAG_LOCKABLE))
3999 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
4002 if (flags & WINED3DLOCK_DISCARD)
4004 TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n");
4005 surface_prepare_system_memory(This);
4006 surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
4010 /* surface_load_location() does not check if the rectangle specifies
4011 * the full surface. Most callers don't need that, so do it here. */
4012 if (pRect && !pRect->top && !pRect->left
4013 && pRect->right == This->resource.width
4014 && pRect->bottom == This->resource.height)
4019 if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
4020 && ((This->container.type == WINED3D_CONTAINER_SWAPCHAIN) || This == device->render_targets[0])))
4022 surface_load_location(This, SFLAG_INSYSMEM, pass_rect);
4026 if (This->flags & SFLAG_PBO)
4028 const struct wined3d_gl_info *gl_info;
4029 struct wined3d_context *context;
4031 context = context_acquire(device, NULL);
4032 gl_info = context->gl_info;
4035 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
4036 checkGLcall("glBindBufferARB");
4038 /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
4039 if(This->resource.allocatedMemory) {
4040 ERR("The surface already has PBO memory allocated!\n");
4043 This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4044 checkGLcall("glMapBufferARB");
4046 /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
4047 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4048 checkGLcall("glBindBufferARB");
4051 context_release(context);
4054 if (!(flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)))
4057 surface_add_dirty_rect(This, NULL);
4062 b.Left = pRect->left;
4064 b.Right = pRect->right;
4065 b.Bottom = pRect->bottom;
4068 surface_add_dirty_rect(This, &b);
4072 return IWineD3DBaseSurfaceImpl_Map(iface, pLockedRect, pRect, flags);
4075 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *surface,
4076 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4078 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface); /* target is argb, 4 byte */
4079 IWineD3DDeviceImpl *device = surface->resource.device;
4080 const struct wined3d_gl_info *gl_info;
4081 struct wined3d_context *context;
4085 surface_get_rect(surface, rect, &local_rect);
4087 mem += local_rect.top * pitch + local_rect.left * bpp;
4088 w = local_rect.right - local_rect.left;
4089 h = local_rect.bottom - local_rect.top;
4091 /* Activate the correct context for the render target */
4092 context = context_acquire(device, surface);
4093 context_apply_blit_state(context, device);
4094 gl_info = context->gl_info;
4098 if (!surface_is_offscreen(surface))
4100 GLenum buffer = surface_get_gl_buffer(surface);
4101 TRACE("Unlocking %#x buffer.\n", buffer);
4102 context_set_draw_buffer(context, buffer);
4104 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4105 glPixelZoom(1.0f, -1.0f);
4109 /* Primary offscreen render target */
4110 TRACE("Offscreen render target.\n");
4111 context_set_draw_buffer(context, device->offscreenBuffer);
4113 glPixelZoom(1.0f, 1.0f);
4116 glRasterPos3i(local_rect.left, local_rect.top, 1);
4117 checkGLcall("glRasterPos3i");
4119 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4120 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4122 if (surface->flags & SFLAG_PBO)
4124 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4125 checkGLcall("glBindBufferARB");
4128 glDrawPixels(w, h, fmt, type, mem);
4129 checkGLcall("glDrawPixels");
4131 if (surface->flags & SFLAG_PBO)
4133 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4134 checkGLcall("glBindBufferARB");
4137 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4138 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4142 if (wined3d_settings.strict_draw_ordering
4143 || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4144 && surface->container.u.swapchain->front_buffer == surface))
4147 context_release(context);
4150 static HRESULT WINAPI IWineD3DSurfaceImpl_Unmap(IWineD3DSurface *iface)
4152 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4153 IWineD3DDeviceImpl *device = This->resource.device;
4156 if (!(This->flags & SFLAG_LOCKED))
4158 WARN("trying to Unlock an unlocked surf@%p\n", This);
4159 return WINEDDERR_NOTLOCKED;
4162 This->flags &= ~SFLAG_LOCKED;
4163 memset(&This->lockedRect, 0, sizeof(This->lockedRect));
4165 if (This->flags & SFLAG_PBO)
4167 const struct wined3d_gl_info *gl_info;
4168 struct wined3d_context *context;
4170 TRACE("Freeing PBO memory\n");
4172 context = context_acquire(device, NULL);
4173 gl_info = context->gl_info;
4176 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
4177 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4178 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4179 checkGLcall("glUnmapBufferARB");
4181 context_release(context);
4183 This->resource.allocatedMemory = NULL;
4186 TRACE("(%p) : dirtyfied(%d)\n", This, This->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
4188 if (This->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
4190 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
4194 if (This->container.type == WINED3D_CONTAINER_SWAPCHAIN
4195 || (device->render_targets && This == device->render_targets[0]))
4197 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
4198 static BOOL warned = FALSE;
4200 ERR("The application tries to write to the render target, but render target locking is disabled\n");
4206 if (!This->dirtyRect.left && !This->dirtyRect.top
4207 && This->dirtyRect.right == This->resource.width
4208 && This->dirtyRect.bottom == This->resource.height)
4212 /* TODO: Proper partial rectangle tracking */
4213 fullsurface = FALSE;
4214 This->flags |= SFLAG_INSYSMEM;
4217 surface_load_location(This, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
4219 /* Partial rectangle tracking is not commonly implemented, it is only
4220 * done for render targets. INSYSMEM was set before to tell
4221 * surface_load_location() where to read the rectangle from.
4222 * Indrawable is set because all modifications from the partial
4223 * sysmem copy are written back to the drawable, thus the surface is
4224 * merged again in the drawable. The sysmem copy is not fully up to
4225 * date because only a subrectangle was read in Map(). */
4228 surface_modify_location(This, SFLAG_INDRAWABLE, TRUE);
4229 surface_evict_sysmem(This);
4232 This->dirtyRect.left = This->resource.width;
4233 This->dirtyRect.top = This->resource.height;
4234 This->dirtyRect.right = 0;
4235 This->dirtyRect.bottom = 0;
4237 else if (This->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
4239 FIXME("Depth Stencil buffer locking is not implemented\n");
4243 /* Overlays have to be redrawn manually after changes with the GL implementation */
4244 if (This->overlay_dest)
4245 This->surface_ops->surface_draw_overlay(This);
4250 static void surface_release_client_storage(IWineD3DSurfaceImpl *surface)
4252 struct wined3d_context *context;
4254 context = context_acquire(surface->resource.device, NULL);
4257 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
4258 if (surface->texture_name)
4260 surface_bind_and_dirtify(surface, context->gl_info, FALSE);
4261 glTexImage2D(surface->texture_target, surface->texture_level,
4262 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
4264 if (surface->texture_name_srgb)
4266 surface_bind_and_dirtify(surface, context->gl_info, TRUE);
4267 glTexImage2D(surface->texture_target, surface->texture_level,
4268 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
4270 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
4273 context_release(context);
4275 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
4276 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
4277 surface_force_reload(surface);
4280 static HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC)
4282 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4283 WINED3DLOCKED_RECT lock;
4287 TRACE("(%p)->(%p)\n",This,pHDC);
4289 if (This->flags & SFLAG_USERPTR)
4291 ERR("Not supported on surfaces with an application-provided surfaces\n");
4292 return WINEDDERR_NODC;
4295 /* Give more detailed info for ddraw */
4296 if (This->flags & SFLAG_DCINUSE)
4297 return WINEDDERR_DCALREADYCREATED;
4299 /* Can't GetDC if the surface is locked */
4300 if (This->flags & SFLAG_LOCKED)
4301 return WINED3DERR_INVALIDCALL;
4303 memset(&lock, 0, sizeof(lock)); /* To be sure */
4305 /* Create a DIB section if there isn't a hdc yet */
4308 if (This->flags & SFLAG_CLIENT)
4310 surface_load_location(This, SFLAG_INSYSMEM, NULL);
4311 surface_release_client_storage(This);
4313 hr = surface_create_dib_section(This);
4314 if(FAILED(hr)) return WINED3DERR_INVALIDCALL;
4316 /* Use the dib section from now on if we are not using a PBO */
4317 if (!(This->flags & SFLAG_PBO))
4318 This->resource.allocatedMemory = This->dib.bitmap_data;
4321 /* Map the surface */
4322 hr = IWineD3DSurface_Map(iface, &lock, NULL, 0);
4324 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4325 * activates the allocatedMemory. */
4326 if (This->flags & SFLAG_PBO)
4327 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
4331 ERR("IWineD3DSurface_Map failed, hr %#x.\n", hr);
4332 /* keep the dib section */
4336 if (This->resource.format->id == WINED3DFMT_P8_UINT
4337 || This->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4339 /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
4340 D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
4342 const PALETTEENTRY *pal = NULL;
4345 pal = This->palette->palents;
4347 IWineD3DSurfaceImpl *dds_primary;
4348 struct wined3d_swapchain *swapchain;
4349 swapchain = This->resource.device->swapchains[0];
4350 dds_primary = swapchain->front_buffer;
4351 if (dds_primary && dds_primary->palette)
4352 pal = dds_primary->palette->palents;
4356 for (n=0; n<256; n++) {
4357 col[n].rgbRed = pal[n].peRed;
4358 col[n].rgbGreen = pal[n].peGreen;
4359 col[n].rgbBlue = pal[n].peBlue;
4360 col[n].rgbReserved = 0;
4362 SetDIBColorTable(This->hDC, 0, 256, col);
4367 TRACE("returning %p\n",*pHDC);
4368 This->flags |= SFLAG_DCINUSE;
4373 static HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC)
4375 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4377 TRACE("(%p)->(%p)\n",This,hDC);
4379 if (!(This->flags & SFLAG_DCINUSE))
4380 return WINEDDERR_NODC;
4382 if (This->hDC !=hDC) {
4383 WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
4384 return WINEDDERR_NODC;
4387 if ((This->flags & SFLAG_PBO) && This->resource.allocatedMemory)
4389 /* Copy the contents of the DIB over to the PBO */
4390 memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
4393 /* we locked first, so unlock now */
4394 IWineD3DSurface_Unmap(iface);
4396 This->flags &= ~SFLAG_DCINUSE;
4401 /* ******************************************************
4402 IWineD3DSurface Internal (No mapping to directx api) parts follow
4403 ****************************************************** */
4405 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck,
4406 BOOL use_texturing, struct wined3d_format *format, CONVERT_TYPES *convert)
4408 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
4409 IWineD3DDeviceImpl *device = This->resource.device;
4410 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4411 BOOL blit_supported = FALSE;
4413 /* Copy the default values from the surface. Below we might perform fixups */
4414 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
4415 *format = *This->resource.format;
4416 *convert = NO_CONVERSION;
4418 /* Ok, now look if we have to do any conversion */
4419 switch (This->resource.format->id)
4421 case WINED3DFMT_P8_UINT:
4422 /* Below the call to blit_supported is disabled for Wine 1.2
4423 * because the function isn't operating correctly yet. At the
4424 * moment 8-bit blits are handled in software and if certain GL
4425 * extensions are around, surface conversion is performed at
4426 * upload time. The blit_supported call recognizes it as a
4427 * destination fixup. This type of upload 'fixup' and 8-bit to
4428 * 8-bit blits need to be handled by the blit_shader.
4429 * TODO: get rid of this #if 0. */
4431 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4432 &rect, This->resource.usage, This->resource.pool, This->resource.format,
4433 &rect, This->resource.usage, This->resource.pool, This->resource.format);
4435 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
4437 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
4438 * texturing. Further also use conversion in case of color keying.
4439 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
4440 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
4441 * conflicts with this.
4443 if (!((blit_supported && device->render_targets && This == device->render_targets[0]))
4444 || colorkey_active || !use_texturing)
4446 format->glFormat = GL_RGBA;
4447 format->glInternal = GL_RGBA;
4448 format->glType = GL_UNSIGNED_BYTE;
4449 format->conv_byte_count = 4;
4450 if (colorkey_active)
4451 *convert = CONVERT_PALETTED_CK;
4453 *convert = CONVERT_PALETTED;
4457 case WINED3DFMT_B2G3R3_UNORM:
4458 /* **********************
4459 GL_UNSIGNED_BYTE_3_3_2
4460 ********************** */
4461 if (colorkey_active) {
4462 /* This texture format will never be used.. So do not care about color keying
4463 up until the point in time it will be needed :-) */
4464 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
4468 case WINED3DFMT_B5G6R5_UNORM:
4469 if (colorkey_active)
4471 *convert = CONVERT_CK_565;
4472 format->glFormat = GL_RGBA;
4473 format->glInternal = GL_RGB5_A1;
4474 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
4475 format->conv_byte_count = 2;
4479 case WINED3DFMT_B5G5R5X1_UNORM:
4480 if (colorkey_active)
4482 *convert = CONVERT_CK_5551;
4483 format->glFormat = GL_BGRA;
4484 format->glInternal = GL_RGB5_A1;
4485 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
4486 format->conv_byte_count = 2;
4490 case WINED3DFMT_B8G8R8_UNORM:
4491 if (colorkey_active)
4493 *convert = CONVERT_CK_RGB24;
4494 format->glFormat = GL_RGBA;
4495 format->glInternal = GL_RGBA8;
4496 format->glType = GL_UNSIGNED_INT_8_8_8_8;
4497 format->conv_byte_count = 4;
4501 case WINED3DFMT_B8G8R8X8_UNORM:
4502 if (colorkey_active)
4504 *convert = CONVERT_RGB32_888;
4505 format->glFormat = GL_RGBA;
4506 format->glInternal = GL_RGBA8;
4507 format->glType = GL_UNSIGNED_INT_8_8_8_8;
4508 format->conv_byte_count = 4;
4519 void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
4521 IWineD3DDeviceImpl *device = This->resource.device;
4522 struct wined3d_palette *pal = This->palette;
4523 BOOL index_in_alpha = FALSE;
4526 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4527 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4528 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4529 * duplicate entries. Store the color key in the unused alpha component to speed the
4530 * download up and to make conversion unneeded. */
4531 index_in_alpha = primary_render_target_is_p8(device);
4535 UINT dxVersion = device->wined3d->dxVersion;
4537 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
4540 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4543 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4544 * there's no palette at this time. */
4545 for (i = 0; i < 256; i++) table[i][3] = i;
4550 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
4551 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
4552 * capability flag is present (wine does advertise this capability) */
4553 for (i = 0; i < 256; ++i)
4555 table[i][0] = device->palettes[device->currentPalette][i].peRed;
4556 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
4557 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
4558 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
4564 TRACE("Using surface palette %p\n", pal);
4565 /* Get the surface's palette */
4566 for (i = 0; i < 256; ++i)
4568 table[i][0] = pal->palents[i].peRed;
4569 table[i][1] = pal->palents[i].peGreen;
4570 table[i][2] = pal->palents[i].peBlue;
4572 /* When index_in_alpha is set the palette index is stored in the
4573 * alpha component. In case of a readback we can then read
4574 * GL_ALPHA. Color keying is handled in BltOverride using a
4575 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4576 * color key itself is passed to glAlphaFunc in other cases the
4577 * alpha component of pixels that should be masked away is set to 0. */
4582 else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
4583 && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
4587 else if (pal->flags & WINEDDPCAPS_ALPHA)
4589 table[i][3] = pal->palents[i].peFlags;
4599 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
4600 UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
4604 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
4609 memcpy(dst, src, pitch * height);
4612 case CONVERT_PALETTED:
4613 case CONVERT_PALETTED_CK:
4618 d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
4620 for (y = 0; y < height; y++)
4622 source = src + pitch * y;
4623 dest = dst + outpitch * y;
4624 /* This is an 1 bpp format, using the width here is fine */
4625 for (x = 0; x < width; x++) {
4626 BYTE color = *source++;
4627 *dest++ = table[color][0];
4628 *dest++ = table[color][1];
4629 *dest++ = table[color][2];
4630 *dest++ = table[color][3];
4636 case CONVERT_CK_565:
4638 /* Converting the 565 format in 5551 packed to emulate color-keying.
4640 Note : in all these conversion, it would be best to average the averaging
4641 pixels to get the color of the pixel that will be color-keyed to
4642 prevent 'color bleeding'. This will be done later on if ever it is
4645 Note2: Nvidia documents say that their driver does not support alpha + color keying
4646 on the same surface and disables color keying in such a case
4652 TRACE("Color keyed 565\n");
4654 for (y = 0; y < height; y++) {
4655 Source = (const WORD *)(src + y * pitch);
4656 Dest = (WORD *) (dst + y * outpitch);
4657 for (x = 0; x < width; x++ ) {
4658 WORD color = *Source++;
4659 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
4660 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4661 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4670 case CONVERT_CK_5551:
4672 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4676 TRACE("Color keyed 5551\n");
4677 for (y = 0; y < height; y++) {
4678 Source = (const WORD *)(src + y * pitch);
4679 Dest = (WORD *) (dst + y * outpitch);
4680 for (x = 0; x < width; x++ ) {
4681 WORD color = *Source++;
4683 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4684 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4688 *Dest &= ~(1 << 15);
4696 case CONVERT_CK_RGB24:
4698 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4700 for (y = 0; y < height; y++)
4702 source = src + pitch * y;
4703 dest = dst + outpitch * y;
4704 for (x = 0; x < width; x++) {
4705 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4706 DWORD dstcolor = color << 8;
4707 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4708 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4711 *(DWORD*)dest = dstcolor;
4719 case CONVERT_RGB32_888:
4721 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4723 for (y = 0; y < height; y++)
4725 source = src + pitch * y;
4726 dest = dst + outpitch * y;
4727 for (x = 0; x < width; x++) {
4728 DWORD color = 0xffffff & *(const DWORD*)source;
4729 DWORD dstcolor = color << 8;
4730 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4731 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4734 *(DWORD*)dest = dstcolor;
4743 ERR("Unsupported conversion type %#x.\n", convert);
4748 BOOL palette9_changed(IWineD3DSurfaceImpl *This)
4750 IWineD3DDeviceImpl *device = This->resource.device;
4752 if (This->palette || (This->resource.format->id != WINED3DFMT_P8_UINT
4753 && This->resource.format->id != WINED3DFMT_P8_UINT_A8_UNORM))
4755 /* If a ddraw-style palette is attached assume no d3d9 palette change.
4756 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
4763 if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
4768 This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4770 memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
4774 static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format)
4776 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4779 TRACE("(%p) : Calling base function first\n", This);
4780 hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
4783 This->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
4784 TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This, This->resource.format->glFormat,
4785 This->resource.format->glInternal, This->resource.format->glType);
4790 static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
4791 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4793 TRACE("iface %p, mem %p.\n", iface, Mem);
4795 if (This->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
4797 WARN("Surface is locked or the HDC is in use\n");
4798 return WINED3DERR_INVALIDCALL;
4801 if(Mem && Mem != This->resource.allocatedMemory) {
4802 void *release = NULL;
4804 /* Do I have to copy the old surface content? */
4805 if (This->flags & SFLAG_DIBSECTION)
4807 SelectObject(This->hDC, This->dib.holdbitmap);
4808 DeleteDC(This->hDC);
4809 /* Release the DIB section */
4810 DeleteObject(This->dib.DIBsection);
4811 This->dib.bitmap_data = NULL;
4812 This->resource.allocatedMemory = NULL;
4814 This->flags &= ~SFLAG_DIBSECTION;
4816 else if (!(This->flags & SFLAG_USERPTR))
4818 release = This->resource.heapMemory;
4819 This->resource.heapMemory = NULL;
4821 This->resource.allocatedMemory = Mem;
4822 This->flags |= SFLAG_USERPTR;
4824 /* Now the surface memory is most up do date. Invalidate drawable and texture */
4825 surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
4827 /* For client textures opengl has to be notified */
4828 if (This->flags & SFLAG_CLIENT)
4829 surface_release_client_storage(This);
4831 /* Now free the old memory if any */
4832 HeapFree(GetProcessHeap(), 0, release);
4834 else if (This->flags & SFLAG_USERPTR)
4836 /* Map and GetDC will re-create the dib section and allocated memory. */
4837 This->resource.allocatedMemory = NULL;
4838 /* HeapMemory should be NULL already */
4839 if (This->resource.heapMemory)
4840 ERR("User pointer surface has heap memory allocated.\n");
4841 This->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
4843 if (This->flags & SFLAG_CLIENT)
4844 surface_release_client_storage(This);
4846 surface_prepare_system_memory(This);
4847 surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
4852 void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
4854 /* Flip the surface contents */
4859 front->hDC = back->hDC;
4863 /* Flip the DIBsection */
4866 BOOL hasDib = front->flags & SFLAG_DIBSECTION;
4867 tmp = front->dib.DIBsection;
4868 front->dib.DIBsection = back->dib.DIBsection;
4869 back->dib.DIBsection = tmp;
4871 if (back->flags & SFLAG_DIBSECTION) front->flags |= SFLAG_DIBSECTION;
4872 else front->flags &= ~SFLAG_DIBSECTION;
4873 if (hasDib) back->flags |= SFLAG_DIBSECTION;
4874 else back->flags &= ~SFLAG_DIBSECTION;
4877 /* Flip the surface data */
4881 tmp = front->dib.bitmap_data;
4882 front->dib.bitmap_data = back->dib.bitmap_data;
4883 back->dib.bitmap_data = tmp;
4885 tmp = front->resource.allocatedMemory;
4886 front->resource.allocatedMemory = back->resource.allocatedMemory;
4887 back->resource.allocatedMemory = tmp;
4889 tmp = front->resource.heapMemory;
4890 front->resource.heapMemory = back->resource.heapMemory;
4891 back->resource.heapMemory = tmp;
4896 GLuint tmp_pbo = front->pbo;
4897 front->pbo = back->pbo;
4898 back->pbo = tmp_pbo;
4901 /* client_memory should not be different, but just in case */
4904 tmp = front->dib.client_memory;
4905 front->dib.client_memory = back->dib.client_memory;
4906 back->dib.client_memory = tmp;
4909 /* Flip the opengl texture */
4913 tmp = back->texture_name;
4914 back->texture_name = front->texture_name;
4915 front->texture_name = tmp;
4917 tmp = back->texture_name_srgb;
4918 back->texture_name_srgb = front->texture_name_srgb;
4919 front->texture_name_srgb = tmp;
4921 resource_unload(&back->resource);
4922 resource_unload(&front->resource);
4926 DWORD tmp_flags = back->flags;
4927 back->flags = front->flags;
4928 front->flags = tmp_flags;
4932 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD flags)
4934 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4935 struct wined3d_swapchain *swapchain = NULL;
4937 TRACE("iface %p, override %p, flags %#x.\n", iface, override, flags);
4939 /* Flipping is only supported on RenderTargets and overlays*/
4940 if( !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)) ) {
4941 WARN("Tried to flip a non-render target, non-overlay surface\n");
4942 return WINEDDERR_NOTFLIPPABLE;
4945 if(This->resource.usage & WINED3DUSAGE_OVERLAY) {
4946 flip_surface(This, (IWineD3DSurfaceImpl *) override);
4948 /* Update the overlay if it is visible */
4949 if (This->overlay_dest)
4950 return This->surface_ops->surface_draw_overlay(This);
4956 /* DDraw sets this for the X11 surfaces, so don't confuse the user
4957 * FIXME("(%p) Target override is not supported by now\n", This);
4958 * Additionally, it isn't really possible to support triple-buffering
4959 * properly on opengl at all
4963 if (This->container.type != WINED3D_CONTAINER_SWAPCHAIN)
4965 ERR("Flipped surface is not on a swapchain\n");
4966 return WINEDDERR_NOTFLIPPABLE;
4968 swapchain = This->container.u.swapchain;
4970 /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
4971 * and only d3d8 and d3d9 apps specify the presentation interval
4973 if (!(flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)))
4974 /* Most common case first to avoid wasting time on all the other cases */
4975 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
4976 else if (flags & WINEDDFLIP_NOVSYNC)
4977 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
4978 else if (flags & WINEDDFLIP_INTERVAL2)
4979 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
4980 else if (flags & WINEDDFLIP_INTERVAL3)
4981 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
4983 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
4985 /* Flipping a OpenGL surface -> present. */
4986 return wined3d_swapchain_present(swapchain, NULL, NULL, swapchain->win_handle, NULL, 0);
4989 /* Does a direct frame buffer -> texture copy. Stretching is done
4990 * with single pixel copy calls
4992 static void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
4993 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
4995 IWineD3DDeviceImpl *device = dst_surface->resource.device;
4998 struct wined3d_context *context;
4999 BOOL upsidedown = FALSE;
5000 RECT dst_rect = *dst_rect_in;
5002 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5003 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5005 if(dst_rect.top > dst_rect.bottom) {
5006 UINT tmp = dst_rect.bottom;
5007 dst_rect.bottom = dst_rect.top;
5012 context = context_acquire(device, src_surface);
5013 context_apply_blit_state(context, device);
5014 surface_internal_preload(dst_surface, SRGB_RGB);
5017 /* Bind the target texture */
5018 glBindTexture(dst_surface->texture_target, dst_surface->texture_name);
5019 checkGLcall("glBindTexture");
5020 if (surface_is_offscreen(src_surface))
5022 TRACE("Reading from an offscreen target\n");
5023 upsidedown = !upsidedown;
5024 glReadBuffer(device->offscreenBuffer);
5028 glReadBuffer(surface_get_gl_buffer(src_surface));
5030 checkGLcall("glReadBuffer");
5032 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
5033 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
5035 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5037 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
5039 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
5040 ERR("Texture filtering not supported in direct blit\n");
5043 else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
5044 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5046 ERR("Texture filtering not supported in direct blit\n");
5050 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5051 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5053 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
5055 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5056 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
5057 src_rect->left, src_surface->resource.height - src_rect->bottom,
5058 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5062 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
5063 /* I have to process this row by row to swap the image,
5064 * otherwise it would be upside down, so stretching in y direction
5065 * doesn't cost extra time
5067 * However, stretching in x direction can be avoided if not necessary
5069 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
5070 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5072 /* Well, that stuff works, but it's very slow.
5073 * find a better way instead
5077 for (col = dst_rect.left; col < dst_rect.right; ++col)
5079 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5080 dst_rect.left + col /* x offset */, row /* y offset */,
5081 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
5086 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5087 dst_rect.left /* x offset */, row /* y offset */,
5088 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
5092 checkGLcall("glCopyTexSubImage2D");
5095 context_release(context);
5097 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5098 * path is never entered
5100 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5103 /* Uses the hardware to stretch and flip the image */
5104 static void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
5105 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
5107 IWineD3DDeviceImpl *device = dst_surface->resource.device;
5108 struct wined3d_swapchain *src_swapchain = NULL;
5109 GLuint src, backup = 0;
5110 float left, right, top, bottom; /* Texture coordinates */
5111 UINT fbwidth = src_surface->resource.width;
5112 UINT fbheight = src_surface->resource.height;
5113 struct wined3d_context *context;
5114 GLenum drawBuffer = GL_BACK;
5115 GLenum texture_target;
5116 BOOL noBackBufferBackup;
5118 BOOL upsidedown = FALSE;
5119 RECT dst_rect = *dst_rect_in;
5121 TRACE("Using hwstretch blit\n");
5122 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5123 context = context_acquire(device, src_surface);
5124 context_apply_blit_state(context, device);
5125 surface_internal_preload(dst_surface, SRGB_RGB);
5127 src_offscreen = surface_is_offscreen(src_surface);
5128 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5129 if (!noBackBufferBackup && !src_surface->texture_name)
5131 /* Get it a description */
5132 surface_internal_preload(src_surface, SRGB_RGB);
5136 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5137 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5139 if (context->aux_buffers >= 2)
5141 /* Got more than one aux buffer? Use the 2nd aux buffer */
5142 drawBuffer = GL_AUX1;
5144 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5146 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5147 drawBuffer = GL_AUX0;
5150 if(noBackBufferBackup) {
5151 glGenTextures(1, &backup);
5152 checkGLcall("glGenTextures");
5153 glBindTexture(GL_TEXTURE_2D, backup);
5154 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
5155 texture_target = GL_TEXTURE_2D;
5157 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5158 * we are reading from the back buffer, the backup can be used as source texture
5160 texture_target = src_surface->texture_target;
5161 glBindTexture(texture_target, src_surface->texture_name);
5162 checkGLcall("glBindTexture(texture_target, src_surface->texture_name)");
5163 glEnable(texture_target);
5164 checkGLcall("glEnable(texture_target)");
5166 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5167 src_surface->flags &= ~SFLAG_INTEXTURE;
5170 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5171 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5173 if(dst_rect.top > dst_rect.bottom) {
5174 UINT tmp = dst_rect.bottom;
5175 dst_rect.bottom = dst_rect.top;
5182 TRACE("Reading from an offscreen target\n");
5183 upsidedown = !upsidedown;
5184 glReadBuffer(device->offscreenBuffer);
5188 glReadBuffer(surface_get_gl_buffer(src_surface));
5191 /* TODO: Only back up the part that will be overwritten */
5192 glCopyTexSubImage2D(texture_target, 0,
5193 0, 0 /* read offsets */,
5198 checkGLcall("glCopyTexSubImage2D");
5200 /* No issue with overriding these - the sampler is dirty due to blit usage */
5201 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5202 wined3d_gl_mag_filter(magLookup, Filter));
5203 checkGLcall("glTexParameteri");
5204 glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5205 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
5206 checkGLcall("glTexParameteri");
5208 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5209 src_swapchain = src_surface->container.u.swapchain;
5210 if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
5212 src = backup ? backup : src_surface->texture_name;
5216 glReadBuffer(GL_FRONT);
5217 checkGLcall("glReadBuffer(GL_FRONT)");
5219 glGenTextures(1, &src);
5220 checkGLcall("glGenTextures(1, &src)");
5221 glBindTexture(GL_TEXTURE_2D, src);
5222 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
5224 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5225 * out for power of 2 sizes
5227 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5228 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5229 checkGLcall("glTexImage2D");
5230 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
5231 0, 0 /* read offsets */,
5236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5237 checkGLcall("glTexParameteri");
5238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5239 checkGLcall("glTexParameteri");
5241 glReadBuffer(GL_BACK);
5242 checkGLcall("glReadBuffer(GL_BACK)");
5244 if(texture_target != GL_TEXTURE_2D) {
5245 glDisable(texture_target);
5246 glEnable(GL_TEXTURE_2D);
5247 texture_target = GL_TEXTURE_2D;
5250 checkGLcall("glEnd and previous");
5252 left = src_rect->left;
5253 right = src_rect->right;
5257 top = src_surface->resource.height - src_rect->top;
5258 bottom = src_surface->resource.height - src_rect->bottom;
5262 top = src_surface->resource.height - src_rect->bottom;
5263 bottom = src_surface->resource.height - src_rect->top;
5266 if (src_surface->flags & SFLAG_NORMCOORD)
5268 left /= src_surface->pow2Width;
5269 right /= src_surface->pow2Width;
5270 top /= src_surface->pow2Height;
5271 bottom /= src_surface->pow2Height;
5274 /* draw the source texture stretched and upside down. The correct surface is bound already */
5275 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5276 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5278 context_set_draw_buffer(context, drawBuffer);
5279 glReadBuffer(drawBuffer);
5283 glTexCoord2f(left, bottom);
5287 glTexCoord2f(left, top);
5288 glVertex2i(0, dst_rect.bottom - dst_rect.top);
5291 glTexCoord2f(right, top);
5292 glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5295 glTexCoord2f(right, bottom);
5296 glVertex2i(dst_rect.right - dst_rect.left, 0);
5298 checkGLcall("glEnd and previous");
5300 if (texture_target != dst_surface->texture_target)
5302 glDisable(texture_target);
5303 glEnable(dst_surface->texture_target);
5304 texture_target = dst_surface->texture_target;
5307 /* Now read the stretched and upside down image into the destination texture */
5308 glBindTexture(texture_target, dst_surface->texture_name);
5309 checkGLcall("glBindTexture");
5310 glCopyTexSubImage2D(texture_target,
5312 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5313 0, 0, /* We blitted the image to the origin */
5314 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5315 checkGLcall("glCopyTexSubImage2D");
5317 if(drawBuffer == GL_BACK) {
5318 /* Write the back buffer backup back */
5320 if(texture_target != GL_TEXTURE_2D) {
5321 glDisable(texture_target);
5322 glEnable(GL_TEXTURE_2D);
5323 texture_target = GL_TEXTURE_2D;
5325 glBindTexture(GL_TEXTURE_2D, backup);
5326 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
5330 if (texture_target != src_surface->texture_target)
5332 glDisable(texture_target);
5333 glEnable(src_surface->texture_target);
5334 texture_target = src_surface->texture_target;
5336 glBindTexture(src_surface->texture_target, src_surface->texture_name);
5337 checkGLcall("glBindTexture(src_surface->texture_target, src_surface->texture_name)");
5342 glTexCoord2f(0.0f, 0.0f);
5343 glVertex2i(0, fbheight);
5346 glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5350 glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5351 (float)fbheight / (float)src_surface->pow2Height);
5352 glVertex2i(fbwidth, 0);
5355 glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5356 glVertex2i(fbwidth, fbheight);
5359 glDisable(texture_target);
5360 checkGLcall("glDisable(texture_target)");
5363 if (src != src_surface->texture_name && src != backup)
5365 glDeleteTextures(1, &src);
5366 checkGLcall("glDeleteTextures(1, &src)");
5369 glDeleteTextures(1, &backup);
5370 checkGLcall("glDeleteTextures(1, &backup)");
5375 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5377 context_release(context);
5379 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5380 * path is never entered
5382 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5385 /* Until the blit_shader is ready, define some prototypes here. */
5386 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
5387 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
5388 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format);
5390 /* Front buffer coordinates are always full screen coordinates, but our GL
5391 * drawable is limited to the window's client area. The sysmem and texture
5392 * copies do have the full screen size. Note that GL has a bottom-left
5393 * origin, while D3D has a top-left origin. */
5394 void surface_translate_drawable_coords(IWineD3DSurfaceImpl *surface, HWND window, RECT *rect)
5396 UINT drawable_height;
5398 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5399 && surface == surface->container.u.swapchain->front_buffer)
5401 POINT offset = {0, 0};
5404 ScreenToClient(window, &offset);
5405 OffsetRect(rect, offset.x, offset.y);
5407 GetClientRect(window, &windowsize);
5408 drawable_height = windowsize.bottom - windowsize.top;
5412 drawable_height = surface->resource.height;
5415 rect->top = drawable_height - rect->top;
5416 rect->bottom = drawable_height - rect->bottom;
5419 static BOOL surface_is_full_rect(IWineD3DSurfaceImpl *surface, const RECT *r)
5421 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
5423 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
5428 /* blit between surface locations. onscreen on different swapchains is not supported.
5429 * depth / stencil is not supported. */
5430 static void surface_blt_fbo(IWineD3DDeviceImpl *device, const WINED3DTEXTUREFILTERTYPE filter,
5431 IWineD3DSurfaceImpl *src_surface, DWORD src_location, const RECT *src_rect_in,
5432 IWineD3DSurfaceImpl *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
5434 const struct wined3d_gl_info *gl_info;
5435 struct wined3d_context *context;
5436 RECT src_rect, dst_rect;
5439 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
5440 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
5441 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
5442 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
5443 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
5445 src_rect = *src_rect_in;
5446 dst_rect = *dst_rect_in;
5450 case WINED3DTEXF_LINEAR:
5451 gl_filter = GL_LINEAR;
5455 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
5456 case WINED3DTEXF_NONE:
5457 case WINED3DTEXF_POINT:
5458 gl_filter = GL_NEAREST;
5462 if (src_location == SFLAG_INDRAWABLE && surface_is_offscreen(src_surface))
5463 src_location = SFLAG_INTEXTURE;
5464 if (dst_location == SFLAG_INDRAWABLE && surface_is_offscreen(dst_surface))
5465 dst_location = SFLAG_INTEXTURE;
5467 /* Make sure the locations are up-to-date. Loading the destination
5468 * surface isn't required if the entire surface is overwritten. (And is
5469 * in fact harmful if we're being called by surface_load_location() with
5470 * the purpose of loading the destination surface.) */
5471 surface_load_location(src_surface, src_location, NULL);
5472 if (!surface_is_full_rect(dst_surface, &dst_rect))
5473 surface_load_location(dst_surface, dst_location, NULL);
5475 if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
5476 else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
5477 else context = context_acquire(device, NULL);
5479 if (!context->valid)
5481 context_release(context);
5482 WARN("Invalid context, skipping blit.\n");
5486 gl_info = context->gl_info;
5488 if (src_location == SFLAG_INDRAWABLE)
5490 GLenum buffer = surface_get_gl_buffer(src_surface);
5492 TRACE("Source surface %p is onscreen.\n", src_surface);
5494 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
5497 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5498 glReadBuffer(buffer);
5499 checkGLcall("glReadBuffer()");
5503 TRACE("Source surface %p is offscreen.\n", src_surface);
5505 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
5506 glReadBuffer(GL_COLOR_ATTACHMENT0);
5507 checkGLcall("glReadBuffer()");
5509 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
5512 if (dst_location == SFLAG_INDRAWABLE)
5514 GLenum buffer = surface_get_gl_buffer(dst_surface);
5516 TRACE("Destination surface %p is onscreen.\n", dst_surface);
5518 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5521 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5522 context_set_draw_buffer(context, buffer);
5526 TRACE("Destination surface %p is offscreen.\n", dst_surface);
5529 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
5530 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5532 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
5534 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5535 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5536 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5537 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5538 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5540 glDisable(GL_SCISSOR_TEST);
5541 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5543 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5544 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
5545 checkGLcall("glBlitFramebuffer()");
5549 if (wined3d_settings.strict_draw_ordering
5550 || (dst_location == SFLAG_INDRAWABLE
5551 && dst_surface->container.u.swapchain->front_buffer == dst_surface))
5554 context_release(context);
5557 static void wined3d_surface_depth_blt_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface,
5558 const RECT *src_rect, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect)
5560 const struct wined3d_gl_info *gl_info;
5561 struct wined3d_context *context;
5562 DWORD src_mask, dst_mask;
5565 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
5566 device, src_surface, wine_dbgstr_rect(src_rect),
5567 dst_surface, wine_dbgstr_rect(dst_rect));
5569 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
5570 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
5572 if (src_mask != dst_mask)
5574 ERR("Incompatible formats %s and %s.\n",
5575 debug_d3dformat(src_surface->resource.format->id),
5576 debug_d3dformat(dst_surface->resource.format->id));
5582 ERR("Not a depth / stencil format: %s.\n",
5583 debug_d3dformat(src_surface->resource.format->id));
5588 if (src_mask & WINED3DFMT_FLAG_DEPTH)
5589 gl_mask |= GL_DEPTH_BUFFER_BIT;
5590 if (src_mask & WINED3DFMT_FLAG_STENCIL)
5591 gl_mask |= GL_STENCIL_BUFFER_BIT;
5593 /* Make sure the locations are up-to-date. Loading the destination
5594 * surface isn't required if the entire surface is overwritten. */
5595 surface_load_location(src_surface, SFLAG_INTEXTURE, NULL);
5596 if (!surface_is_full_rect(dst_surface, dst_rect))
5597 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
5599 context = context_acquire(device, NULL);
5600 if (!context->valid)
5602 context_release(context);
5603 WARN("Invalid context, skipping blit.\n");
5607 gl_info = context->gl_info;
5611 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, SFLAG_INTEXTURE);
5612 glReadBuffer(GL_NONE);
5613 checkGLcall("glReadBuffer()");
5614 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
5616 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, SFLAG_INTEXTURE);
5617 context_set_draw_buffer(context, GL_NONE);
5618 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
5620 if (gl_mask & GL_DEPTH_BUFFER_BIT)
5622 glDepthMask(GL_TRUE);
5623 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5625 if (gl_mask & GL_STENCIL_BUFFER_BIT)
5627 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
5629 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
5630 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
5633 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5636 glDisable(GL_SCISSOR_TEST);
5637 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5639 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
5640 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
5641 checkGLcall("glBlitFramebuffer()");
5645 if (wined3d_settings.strict_draw_ordering)
5646 wglFlush(); /* Flush to ensure ordering across contexts. */
5648 context_release(context);
5651 static void surface_blt_to_drawable(IWineD3DDeviceImpl *device,
5652 WINED3DTEXTUREFILTERTYPE filter, BOOL color_key,
5653 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5654 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in)
5656 struct wined3d_context *context;
5657 RECT src_rect, dst_rect;
5659 src_rect = *src_rect_in;
5660 dst_rect = *dst_rect_in;
5662 /* Make sure the surface is up-to-date. This should probably use
5663 * surface_load_location() and worry about the destination surface too,
5664 * unless we're overwriting it completely. */
5665 surface_internal_preload(src_surface, SRGB_RGB);
5667 /* Activate the destination context, set it up for blitting */
5668 context = context_acquire(device, dst_surface);
5669 context_apply_blit_state(context, device);
5671 if (!surface_is_offscreen(dst_surface))
5672 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5674 device->blitter->set_shader(device->blit_priv, context->gl_info, src_surface);
5680 glEnable(GL_ALPHA_TEST);
5681 checkGLcall("glEnable(GL_ALPHA_TEST)");
5683 /* When the primary render target uses P8, the alpha component
5684 * contains the palette index. Which means that the colorkey is one of
5685 * the palette entries. In other cases pixels that should be masked
5686 * away have alpha set to 0. */
5687 if (primary_render_target_is_p8(device))
5688 glAlphaFunc(GL_NOTEQUAL, (float)src_surface->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
5690 glAlphaFunc(GL_NOTEQUAL, 0.0f);
5691 checkGLcall("glAlphaFunc");
5695 glDisable(GL_ALPHA_TEST);
5696 checkGLcall("glDisable(GL_ALPHA_TEST)");
5699 draw_textured_quad(src_surface, &src_rect, &dst_rect, filter);
5703 glDisable(GL_ALPHA_TEST);
5704 checkGLcall("glDisable(GL_ALPHA_TEST)");
5709 /* Leave the opengl state valid for blitting */
5710 device->blitter->unset_shader(context->gl_info);
5712 if (wined3d_settings.strict_draw_ordering
5713 || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5714 && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5715 wglFlush(); /* Flush to ensure ordering across contexts. */
5717 context_release(context);
5720 /* Do not call while under the GL lock. */
5721 HRESULT surface_color_fill(IWineD3DSurfaceImpl *s, const RECT *rect, const WINED3DCOLORVALUE *color)
5723 IWineD3DDeviceImpl *device = s->resource.device;
5724 const struct blit_shader *blitter;
5726 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5727 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5730 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5731 return WINED3DERR_INVALIDCALL;
5734 return blitter->color_fill(device, s, rect, color);
5737 /* Not called from the VTable */
5738 /* Do not call while under the GL lock. */
5739 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *DestRect,
5740 IWineD3DSurfaceImpl *src_surface, const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5741 WINED3DTEXTUREFILTERTYPE Filter)
5743 IWineD3DDeviceImpl *device = dst_surface->resource.device;
5744 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5745 struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5746 RECT dst_rect, src_rect;
5748 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5749 dst_surface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
5750 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
5752 /* Get the swapchain. One of the surfaces has to be a primary surface */
5753 if (dst_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
5755 WARN("Destination is in sysmem, rejecting gl blt\n");
5756 return WINED3DERR_INVALIDCALL;
5759 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5760 dstSwapchain = dst_surface->container.u.swapchain;
5764 if (src_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
5766 WARN("Src is in sysmem, rejecting gl blt\n");
5767 return WINED3DERR_INVALIDCALL;
5770 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5771 srcSwapchain = src_surface->container.u.swapchain;
5774 /* Early sort out of cases where no render target is used */
5775 if (!dstSwapchain && !srcSwapchain
5776 && src_surface != device->render_targets[0]
5777 && dst_surface != device->render_targets[0])
5779 TRACE("No surface is render target, not using hardware blit.\n");
5780 return WINED3DERR_INVALIDCALL;
5783 /* No destination color keying supported */
5784 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5786 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5787 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5788 return WINED3DERR_INVALIDCALL;
5791 surface_get_rect(dst_surface, DestRect, &dst_rect);
5792 if (src_surface) surface_get_rect(src_surface, SrcRect, &src_rect);
5794 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
5795 if (dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->back_buffers
5796 && dst_surface == dstSwapchain->front_buffer
5797 && src_surface == dstSwapchain->back_buffers[0])
5799 /* Half-Life does a Blt from the back buffer to the front buffer,
5800 * Full surface size, no flags... Use present instead
5802 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
5805 /* Check rects - IWineD3DDevice_Present doesn't handle them */
5808 TRACE("Looking if a Present can be done...\n");
5809 /* Source Rectangle must be full surface */
5810 if (src_rect.left || src_rect.top
5811 || src_rect.right != src_surface->resource.width
5812 || src_rect.bottom != src_surface->resource.height)
5814 TRACE("No, Source rectangle doesn't match\n");
5818 /* No stretching may occur */
5819 if(src_rect.right != dst_rect.right - dst_rect.left ||
5820 src_rect.bottom != dst_rect.bottom - dst_rect.top) {
5821 TRACE("No, stretching is done\n");
5825 /* Destination must be full surface or match the clipping rectangle */
5826 if (dst_surface->clipper && dst_surface->clipper->hWnd)
5830 GetClientRect(dst_surface->clipper->hWnd, &cliprect);
5831 pos[0].x = dst_rect.left;
5832 pos[0].y = dst_rect.top;
5833 pos[1].x = dst_rect.right;
5834 pos[1].y = dst_rect.bottom;
5835 MapWindowPoints(GetDesktopWindow(), dst_surface->clipper->hWnd, pos, 2);
5837 if(pos[0].x != cliprect.left || pos[0].y != cliprect.top ||
5838 pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
5840 TRACE("No, dest rectangle doesn't match(clipper)\n");
5841 TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect));
5842 TRACE("Blt dest: %s\n", wine_dbgstr_rect(&dst_rect));
5846 else if (dst_rect.left || dst_rect.top
5847 || dst_rect.right != dst_surface->resource.width
5848 || dst_rect.bottom != dst_surface->resource.height)
5850 TRACE("No, dest rectangle doesn't match(surface size)\n");
5856 /* These flags are unimportant for the flag check, remove them */
5857 if (!(flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)))
5859 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
5861 /* The idea behind this is that a glReadPixels and a glDrawPixels call
5862 * take very long, while a flip is fast.
5863 * This applies to Half-Life, which does such Blts every time it finished
5864 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
5865 * menu. This is also used by all apps when they do windowed rendering
5867 * The problem is that flipping is not really the same as copying. After a
5868 * Blt the front buffer is a copy of the back buffer, and the back buffer is
5869 * untouched. Therefore it's necessary to override the swap effect
5870 * and to set it back after the flip.
5872 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
5876 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
5877 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
5879 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead.\n");
5880 wined3d_swapchain_present(dstSwapchain, NULL, NULL, dstSwapchain->win_handle, NULL, 0);
5882 dstSwapchain->presentParms.SwapEffect = orig_swap;
5889 TRACE("Unsupported blit between buffers on the same swapchain\n");
5890 return WINED3DERR_INVALIDCALL;
5891 } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
5892 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5893 return WINED3DERR_INVALIDCALL;
5894 } else if(dstSwapchain && srcSwapchain) {
5895 FIXME("Implement hardware blit between two different swapchains\n");
5896 return WINED3DERR_INVALIDCALL;
5898 else if (dstSwapchain)
5900 /* Handled with regular texture -> swapchain blit */
5901 if (src_surface == device->render_targets[0])
5902 TRACE("Blit from active render target to a swapchain\n");
5904 else if (srcSwapchain && dst_surface == device->render_targets[0])
5906 FIXME("Implement blit from a swapchain to the active render target\n");
5907 return WINED3DERR_INVALIDCALL;
5910 if ((srcSwapchain || src_surface == device->render_targets[0]) && !dstSwapchain)
5912 /* Blit from render target to texture */
5915 /* P8 read back is not implemented */
5916 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5917 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5919 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5920 return WINED3DERR_INVALIDCALL;
5923 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5925 TRACE("Color keying not supported by frame buffer to texture blit\n");
5926 return WINED3DERR_INVALIDCALL;
5927 /* Destination color key is checked above */
5930 if(dst_rect.right - dst_rect.left != src_rect.right - src_rect.left) {
5936 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5937 * flip the image nor scale it.
5939 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5940 * -> If the app wants a image width an unscaled width, copy it line per line
5941 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5942 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5943 * back buffer. This is slower than reading line per line, thus not used for flipping
5944 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5947 * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
5948 * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
5950 if (fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5951 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5952 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5954 surface_blt_fbo(device, Filter,
5955 src_surface, SFLAG_INDRAWABLE, &src_rect,
5956 dst_surface, SFLAG_INDRAWABLE, &dst_rect);
5957 surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
5959 else if (!stretchx || dst_rect.right - dst_rect.left > src_surface->resource.width
5960 || dst_rect.bottom - dst_rect.top > src_surface->resource.height)
5962 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
5963 fb_copy_to_texture_direct(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
5965 TRACE("Using hardware stretching to flip / stretch the texture\n");
5966 fb_copy_to_texture_hwstretch(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
5969 if (!(dst_surface->flags & SFLAG_DONOTFREE))
5971 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5972 dst_surface->resource.allocatedMemory = NULL;
5973 dst_surface->resource.heapMemory = NULL;
5977 dst_surface->flags &= ~SFLAG_INSYSMEM;
5982 else if (src_surface)
5984 /* Blit from offscreen surface to render target */
5985 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5986 WINEDDCOLORKEY oldBltCKey = src_surface->SrcBltCKey;
5988 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5990 if (!(flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5991 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5992 &src_rect, src_surface->resource.usage, src_surface->resource.pool,
5993 src_surface->resource.format,
5994 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
5995 dst_surface->resource.format))
5997 TRACE("Using surface_blt_fbo.\n");
5998 /* The source is always a texture, but never the currently active render target, and the texture
5999 * contents are never upside down. */
6000 surface_blt_fbo(device, Filter,
6001 src_surface, SFLAG_INDRAWABLE, &src_rect,
6002 dst_surface, SFLAG_INDRAWABLE, &dst_rect);
6003 surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
6007 if (!(flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
6008 && arbfp_blit.blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6009 &src_rect, src_surface->resource.usage, src_surface->resource.pool,
6010 src_surface->resource.format,
6011 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
6012 dst_surface->resource.format))
6014 return arbfp_blit_surface(device, src_surface, &src_rect, dst_surface, &dst_rect,
6015 WINED3D_BLIT_OP_COLOR_BLIT, Filter);
6018 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6019 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
6020 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
6022 FIXME("Unsupported blit operation falling back to software\n");
6023 return WINED3DERR_INVALIDCALL;
6026 /* Color keying: Check if we have to do a color keyed blt,
6027 * and if not check if a color key is activated.
6029 * Just modify the color keying parameters in the surface and restore them afterwards
6030 * The surface keeps track of the color key last used to load the opengl surface.
6031 * PreLoad will catch the change to the flags and color key and reload if necessary.
6033 if (flags & WINEDDBLT_KEYSRC)
6035 /* Use color key from surface */
6037 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6039 /* Use color key from DDBltFx */
6040 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
6041 src_surface->SrcBltCKey = DDBltFx->ddckSrcColorkey;
6045 /* Do not use color key */
6046 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
6049 surface_blt_to_drawable(device, Filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
6050 src_surface, &src_rect, dst_surface, &dst_rect);
6052 /* Restore the color key parameters */
6053 src_surface->CKeyFlags = oldCKeyFlags;
6054 src_surface->SrcBltCKey = oldBltCKey;
6056 surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
6062 /* Source-Less Blit to render target */
6063 if (flags & WINEDDBLT_COLORFILL)
6065 WINED3DCOLORVALUE color;
6067 TRACE("Colorfill\n");
6069 /* The color as given in the Blt function is in the surface format. */
6070 if (!surface_convert_color_to_float(dst_surface, DDBltFx->u5.dwFillColor, &color))
6071 return WINED3DERR_INVALIDCALL;
6073 return surface_color_fill(dst_surface, &dst_rect, &color);
6077 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
6078 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
6079 return WINED3DERR_INVALIDCALL;
6082 /* Do not call while under the GL lock. */
6083 static HRESULT wined3d_surface_depth_fill(IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
6085 const struct wined3d_resource *resource = &surface->resource;
6086 IWineD3DDeviceImpl *device = resource->device;
6087 const struct blit_shader *blitter;
6089 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
6090 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
6093 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
6094 return WINED3DERR_INVALIDCALL;
6097 return blitter->depth_fill(device, surface, rect, depth);
6100 static HRESULT wined3d_surface_depth_blt(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect,
6101 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect)
6103 IWineD3DDeviceImpl *device = src_surface->resource.device;
6105 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
6106 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
6107 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
6108 return WINED3DERR_INVALIDCALL;
6110 wined3d_surface_depth_blt_fbo(device, src_surface, src_rect, dst_surface, dst_rect);
6112 surface_modify_ds_location(dst_surface, SFLAG_DS_OFFSCREEN,
6113 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
6114 surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
6119 /* Do not call while under the GL lock. */
6120 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect,
6121 IWineD3DSurface *src_surface, const RECT *SrcRect, DWORD flags,
6122 const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
6124 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
6125 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
6126 IWineD3DDeviceImpl *device = This->resource.device;
6127 DWORD src_ds_flags, dst_ds_flags;
6129 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6130 iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
6131 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
6132 TRACE("Usage is %s.\n", debug_d3dusage(This->resource.usage));
6134 if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
6136 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
6137 return WINEDDERR_SURFACEBUSY;
6140 dst_ds_flags = This->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
6142 src_ds_flags = src->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
6146 if (src_ds_flags || dst_ds_flags)
6148 if (flags & WINEDDBLT_DEPTHFILL)
6153 TRACE("Depth fill.\n");
6155 surface_get_rect(This, DestRect, &rect);
6157 if (!surface_convert_depth_to_float(This, DDBltFx->u5.dwFillDepth, &depth))
6158 return WINED3DERR_INVALIDCALL;
6160 if (SUCCEEDED(wined3d_surface_depth_fill(This, &rect, depth)))
6165 RECT src_rect, dst_rect;
6167 /* Accessing depth / stencil surfaces is supposed to fail while in
6168 * a scene, except for fills, which seem to work. */
6169 if (device->inScene)
6171 WARN("Rejecting depth / stencil access while in scene.\n");
6172 return WINED3DERR_INVALIDCALL;
6175 if (src_ds_flags != dst_ds_flags)
6177 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
6178 return WINED3DERR_INVALIDCALL;
6181 if (SrcRect && (SrcRect->top || SrcRect->left
6182 || SrcRect->bottom != src->resource.height
6183 || SrcRect->right != src->resource.width))
6185 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
6186 wine_dbgstr_rect(SrcRect));
6187 return WINED3DERR_INVALIDCALL;
6190 if (DestRect && (DestRect->top || DestRect->left
6191 || DestRect->bottom != This->resource.height
6192 || DestRect->right != This->resource.width))
6194 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
6195 wine_dbgstr_rect(SrcRect));
6196 return WINED3DERR_INVALIDCALL;
6199 if (src->resource.height != This->resource.height
6200 || src->resource.width != This->resource.width)
6202 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
6203 return WINED3DERR_INVALIDCALL;
6206 surface_get_rect(src, SrcRect, &src_rect);
6207 surface_get_rect(This, DestRect, &dst_rect);
6209 if (SUCCEEDED(wined3d_surface_depth_blt(src, &src_rect, This, &dst_rect)))
6214 /* Special cases for RenderTargets */
6215 if ((This->resource.usage & WINED3DUSAGE_RENDERTARGET)
6216 || (src && (src->resource.usage & WINED3DUSAGE_RENDERTARGET)))
6218 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This, DestRect, src, SrcRect, flags, DDBltFx, Filter)))
6222 /* For the rest call the X11 surface implementation.
6223 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
6224 * other Blts are rather rare. */
6225 return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, src_surface, SrcRect, flags, DDBltFx, Filter);
6228 static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
6229 IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
6231 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
6232 IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
6233 IWineD3DDeviceImpl *device = This->resource.device;
6235 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
6236 iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
6238 if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
6240 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
6241 return WINEDDERR_SURFACEBUSY;
6244 if (device->inScene && (This == device->depth_stencil || src == device->depth_stencil))
6246 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
6247 return WINED3DERR_INVALIDCALL;
6250 /* Special cases for RenderTargets */
6251 if ((This->resource.usage & WINED3DUSAGE_RENDERTARGET)
6252 || (src->resource.usage & WINED3DUSAGE_RENDERTARGET))
6255 RECT SrcRect, DstRect;
6258 surface_get_rect(src, rsrc, &SrcRect);
6260 DstRect.left = dstx;
6262 DstRect.right = dstx + SrcRect.right - SrcRect.left;
6263 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
6265 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
6266 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
6267 flags |= WINEDDBLT_KEYSRC;
6268 if (trans & WINEDDBLTFAST_DESTCOLORKEY)
6269 flags |= WINEDDBLT_KEYDEST;
6270 if (trans & WINEDDBLTFAST_WAIT)
6271 flags |= WINEDDBLT_WAIT;
6272 if (trans & WINEDDBLTFAST_DONOTWAIT)
6273 flags |= WINEDDBLT_DONOTWAIT;
6275 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This,
6276 &DstRect, src, &SrcRect, flags, NULL, WINED3DTEXF_POINT)))
6280 return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, src_surface, rsrc, trans);
6283 /* GL locking is done by the caller */
6284 static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
6285 GLuint texture, GLsizei w, GLsizei h, GLenum target)
6287 IWineD3DDeviceImpl *device = This->resource.device;
6288 GLint compare_mode = GL_NONE;
6289 struct blt_info info;
6290 GLint old_binding = 0;
6293 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
6295 glDisable(GL_CULL_FACE);
6296 glDisable(GL_BLEND);
6297 glDisable(GL_ALPHA_TEST);
6298 glDisable(GL_SCISSOR_TEST);
6299 glDisable(GL_STENCIL_TEST);
6300 glEnable(GL_DEPTH_TEST);
6301 glDepthFunc(GL_ALWAYS);
6302 glDepthMask(GL_TRUE);
6303 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
6304 glViewport(0, This->pow2Height - h, w, h);
6306 SetRect(&rect, 0, h, w, 0);
6307 surface_get_blt_info(target, &rect, This->pow2Width, This->pow2Height, &info);
6308 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6309 glGetIntegerv(info.binding, &old_binding);
6310 glBindTexture(info.bind_target, texture);
6311 if (gl_info->supported[ARB_SHADOW])
6313 glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
6314 if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
6317 device->shader_backend->shader_select_depth_blt(device->shader_priv,
6318 gl_info, info.tex_type, &This->ds_current_size);
6320 glBegin(GL_TRIANGLE_STRIP);
6321 glTexCoord3fv(info.coords[0]);
6322 glVertex2f(-1.0f, -1.0f);
6323 glTexCoord3fv(info.coords[1]);
6324 glVertex2f(1.0f, -1.0f);
6325 glTexCoord3fv(info.coords[2]);
6326 glVertex2f(-1.0f, 1.0f);
6327 glTexCoord3fv(info.coords[3]);
6328 glVertex2f(1.0f, 1.0f);
6331 if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
6332 glBindTexture(info.bind_target, old_binding);
6336 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
6339 void surface_modify_ds_location(IWineD3DSurfaceImpl *surface,
6340 DWORD location, UINT w, UINT h)
6342 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
6344 if (location & ~SFLAG_DS_LOCATIONS)
6345 FIXME("Invalid location (%#x) specified.\n", location);
6347 surface->ds_current_size.cx = w;
6348 surface->ds_current_size.cy = h;
6349 surface->flags &= ~SFLAG_DS_LOCATIONS;
6350 surface->flags |= location;
6353 /* Context activation is done by the caller. */
6354 void surface_load_ds_location(IWineD3DSurfaceImpl *surface, struct wined3d_context *context, DWORD location)
6356 IWineD3DDeviceImpl *device = surface->resource.device;
6357 const struct wined3d_gl_info *gl_info = context->gl_info;
6360 TRACE("surface %p, new location %#x.\n", surface, location);
6362 /* TODO: Make this work for modes other than FBO */
6363 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
6365 if (!(surface->flags & location))
6367 w = surface->ds_current_size.cx;
6368 h = surface->ds_current_size.cy;
6369 surface->ds_current_size.cx = 0;
6370 surface->ds_current_size.cy = 0;
6374 w = surface->resource.width;
6375 h = surface->resource.height;
6378 if (surface->ds_current_size.cx == surface->resource.width
6379 && surface->ds_current_size.cy == surface->resource.height)
6381 TRACE("Location (%#x) is already up to date.\n", location);
6385 if (surface->current_renderbuffer)
6387 FIXME("Not supported with fixed up depth stencil.\n");
6391 if (!(surface->flags & SFLAG_DS_LOCATIONS))
6393 /* This mostly happens when a depth / stencil is used without being
6394 * cleared first. In principle we could upload from sysmem, or
6395 * explicitly clear before first usage. For the moment there don't
6396 * appear to be a lot of applications depending on this, so a FIXME
6398 FIXME("No up to date depth stencil location.\n");
6399 surface->flags |= location;
6400 surface->ds_current_size.cx = surface->resource.width;
6401 surface->ds_current_size.cy = surface->resource.height;
6405 if (location == SFLAG_DS_OFFSCREEN)
6407 GLint old_binding = 0;
6410 /* The render target is allowed to be smaller than the depth/stencil
6411 * buffer, so the onscreen depth/stencil buffer is potentially smaller
6412 * than the offscreen surface. Don't overwrite the offscreen surface
6413 * with undefined data. */
6414 w = min(w, context->swapchain->presentParms.BackBufferWidth);
6415 h = min(h, context->swapchain->presentParms.BackBufferHeight);
6417 TRACE("Copying onscreen depth buffer to depth texture.\n");
6421 if (!device->depth_blt_texture)
6423 glGenTextures(1, &device->depth_blt_texture);
6426 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
6427 * directly on the FBO texture. That's because we need to flip. */
6428 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
6429 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
6431 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6432 bind_target = GL_TEXTURE_RECTANGLE_ARB;
6436 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6437 bind_target = GL_TEXTURE_2D;
6439 glBindTexture(bind_target, device->depth_blt_texture);
6440 glCopyTexImage2D(bind_target, surface->texture_level, surface->resource.format->glInternal, 0, 0, w, h, 0);
6441 glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6442 glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6443 glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6444 glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6445 glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
6446 glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6447 glBindTexture(bind_target, old_binding);
6449 /* Setup the destination */
6450 if (!device->depth_blt_rb)
6452 gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
6453 checkGLcall("glGenRenderbuffersEXT");
6455 if (device->depth_blt_rb_w != w || device->depth_blt_rb_h != h)
6457 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
6458 checkGLcall("glBindRenderbufferEXT");
6459 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, w, h);
6460 checkGLcall("glRenderbufferStorageEXT");
6461 device->depth_blt_rb_w = w;
6462 device->depth_blt_rb_h = h;
6465 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
6466 gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
6467 GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
6468 checkGLcall("glFramebufferRenderbufferEXT");
6469 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, surface, FALSE);
6471 /* Do the actual blit */
6472 surface_depth_blt(surface, gl_info, device->depth_blt_texture, w, h, bind_target);
6473 checkGLcall("depth_blt");
6475 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
6476 else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
6480 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
6482 else if (location == SFLAG_DS_ONSCREEN)
6484 TRACE("Copying depth texture to onscreen depth buffer.\n");
6488 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
6489 surface_depth_blt(surface, gl_info, surface->texture_name,
6490 w, h, surface->texture_target);
6491 checkGLcall("depth_blt");
6493 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
6497 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
6501 ERR("Invalid location (%#x) specified.\n", location);
6504 surface->flags |= location;
6505 surface->ds_current_size.cx = surface->resource.width;
6506 surface->ds_current_size.cy = surface->resource.height;
6509 void surface_modify_location(IWineD3DSurfaceImpl *surface, DWORD flag, BOOL persistent)
6511 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
6512 IWineD3DSurfaceImpl *overlay;
6514 TRACE("surface %p, location %s, persistent %#x.\n",
6515 surface, debug_surflocation(flag), persistent);
6517 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6519 if (surface_is_offscreen(surface))
6521 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
6522 if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
6526 TRACE("Surface %p is an onscreen surface.\n", surface);
6530 if (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6531 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6533 flag |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6538 if (((surface->flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE))
6539 || ((surface->flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX)))
6541 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6543 TRACE("Passing to container.\n");
6544 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
6547 surface->flags &= ~SFLAG_LOCATIONS;
6548 surface->flags |= flag;
6550 /* Redraw emulated overlays, if any */
6551 if (flag & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
6553 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, IWineD3DSurfaceImpl, overlay_entry)
6555 overlay->surface_ops->surface_draw_overlay(overlay);
6561 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
6563 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6565 TRACE("Passing to container\n");
6566 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
6569 surface->flags &= ~flag;
6572 if (!(surface->flags & SFLAG_LOCATIONS))
6574 ERR("Surface %p does not have any up to date location.\n", surface);
6578 HRESULT surface_load_location(IWineD3DSurfaceImpl *surface, DWORD flag, const RECT *rect)
6580 IWineD3DDeviceImpl *device = surface->resource.device;
6581 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6582 BOOL drawable_read_ok = surface_is_offscreen(surface);
6583 struct wined3d_format format;
6584 CONVERT_TYPES convert;
6585 int width, pitch, outpitch;
6587 BOOL in_fbo = FALSE;
6589 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(flag), wine_dbgstr_rect(rect));
6591 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6593 if (flag == SFLAG_INTEXTURE)
6595 struct wined3d_context *context = context_acquire(device, NULL);
6596 surface_load_ds_location(surface, context, SFLAG_DS_OFFSCREEN);
6597 context_release(context);
6602 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(flag));
6603 return WINED3DERR_INVALIDCALL;
6607 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6609 if (surface_is_offscreen(surface))
6611 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
6612 * Prefer SFLAG_INTEXTURE. */
6613 if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
6614 drawable_read_ok = FALSE;
6619 TRACE("Surface %p is an onscreen surface.\n", surface);
6623 if (flag == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6625 flag = SFLAG_INTEXTURE;
6628 if (surface->flags & flag)
6630 TRACE("Location already up to date\n");
6634 if (!(surface->flags & SFLAG_LOCATIONS))
6636 ERR("Surface %p does not have any up to date location.\n", surface);
6637 surface->flags |= SFLAG_LOST;
6638 return WINED3DERR_DEVICELOST;
6641 if (flag == SFLAG_INSYSMEM)
6643 surface_prepare_system_memory(surface);
6645 /* Download the surface to system memory */
6646 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
6648 struct wined3d_context *context = NULL;
6650 if (!device->isInDraw) context = context_acquire(device, NULL);
6652 surface_bind_and_dirtify(surface, gl_info, !(surface->flags & SFLAG_INTEXTURE));
6653 surface_download_data(surface, gl_info);
6655 if (context) context_release(context);
6659 /* Note: It might be faster to download into a texture first. */
6660 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
6661 IWineD3DSurface_GetPitch((IWineD3DSurface *)surface));
6664 else if (flag == SFLAG_INDRAWABLE)
6666 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
6667 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6669 if (surface->flags & SFLAG_INTEXTURE)
6673 surface_get_rect(surface, rect, &r);
6674 surface_blt_to_drawable(device, WINED3DTEXF_POINT, FALSE, surface, &r, surface, &r);
6679 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
6681 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
6682 * values, otherwise we get incorrect values in the target. For now go the slow way
6683 * via a system memory copy
6685 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6688 d3dfmt_get_conv(surface, FALSE /* We need color keying */,
6689 FALSE /* We won't use textures */, &format, &convert);
6691 /* The width is in 'length' not in bytes */
6692 width = surface->resource.width;
6693 pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
6695 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
6696 * but it isn't set (yet) in all cases it is getting called. */
6697 if ((convert != NO_CONVERSION) && (surface->flags & SFLAG_PBO))
6699 struct wined3d_context *context = NULL;
6701 TRACE("Removing the pbo attached to surface %p.\n", surface);
6703 if (!device->isInDraw) context = context_acquire(device, NULL);
6704 surface_remove_pbo(surface, gl_info);
6705 if (context) context_release(context);
6708 if ((convert != NO_CONVERSION) && surface->resource.allocatedMemory)
6710 int height = surface->resource.height;
6711 byte_count = format.conv_byte_count;
6713 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6714 outpitch = width * byte_count;
6715 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6717 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6719 ERR("Out of memory %d, %d!\n", outpitch, height);
6720 return WINED3DERR_OUTOFVIDEOMEMORY;
6722 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, pitch,
6723 width, height, outpitch, convert, surface);
6725 surface->flags |= SFLAG_CONVERTED;
6729 surface->flags &= ~SFLAG_CONVERTED;
6730 mem = surface->resource.allocatedMemory;
6731 byte_count = format.byte_count;
6734 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6736 /* Don't delete PBO memory */
6737 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6738 HeapFree(GetProcessHeap(), 0, mem);
6741 else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */
6743 const DWORD attach_flags = WINED3DFMT_FLAG_FBO_ATTACHABLE | WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB;
6745 if (drawable_read_ok && (surface->flags & SFLAG_INDRAWABLE))
6747 read_from_framebuffer_texture(surface, flag == SFLAG_INSRGBTEX);
6749 else if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6750 && (surface->resource.format->flags & attach_flags) == attach_flags
6751 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6752 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6753 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6755 DWORD src_location = flag == SFLAG_INSRGBTEX ? SFLAG_INTEXTURE : SFLAG_INSRGBTEX;
6756 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6758 surface_blt_fbo(surface->resource.device, WINED3DTEXF_POINT,
6759 surface, src_location, &rect, surface, flag, &rect);
6763 /* Upload from system memory */
6764 BOOL srgb = flag == SFLAG_INSRGBTEX;
6765 struct wined3d_context *context = NULL;
6767 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6768 TRUE /* We will use textures */, &format, &convert);
6772 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6774 /* Performance warning... */
6775 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6776 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6781 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6783 /* Performance warning... */
6784 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6785 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6788 if (!(surface->flags & SFLAG_INSYSMEM))
6790 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6791 /* Lets hope we get it from somewhere... */
6792 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6795 if (!device->isInDraw) context = context_acquire(device, NULL);
6797 surface_prepare_texture(surface, gl_info, srgb);
6798 surface_bind_and_dirtify(surface, gl_info, srgb);
6800 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6802 surface->flags |= SFLAG_GLCKEY;
6803 surface->glCKey = surface->SrcBltCKey;
6805 else surface->flags &= ~SFLAG_GLCKEY;
6807 /* The width is in 'length' not in bytes */
6808 width = surface->resource.width;
6809 pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
6811 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
6812 * but it isn't set (yet) in all cases it is getting called. */
6813 if ((convert != NO_CONVERSION || format.convert) && (surface->flags & SFLAG_PBO))
6815 TRACE("Removing the pbo attached to surface %p.\n", surface);
6816 surface_remove_pbo(surface, gl_info);
6821 /* This code is entered for texture formats which need a fixup. */
6822 UINT height = surface->resource.height;
6824 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6825 outpitch = width * format.conv_byte_count;
6826 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6828 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6830 ERR("Out of memory %d, %d!\n", outpitch, height);
6831 if (context) context_release(context);
6832 return WINED3DERR_OUTOFVIDEOMEMORY;
6834 format.convert(surface->resource.allocatedMemory, mem, pitch, width, height);
6836 else if (convert != NO_CONVERSION && surface->resource.allocatedMemory)
6838 /* This code is only entered for color keying fixups */
6839 UINT height = surface->resource.height;
6841 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6842 outpitch = width * format.conv_byte_count;
6843 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6845 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6847 ERR("Out of memory %d, %d!\n", outpitch, height);
6848 if (context) context_release(context);
6849 return WINED3DERR_OUTOFVIDEOMEMORY;
6851 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, pitch,
6852 width, height, outpitch, convert, surface);
6856 mem = surface->resource.allocatedMemory;
6859 /* Make sure the correct pitch is used */
6861 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
6864 if (mem || (surface->flags & SFLAG_PBO))
6865 surface_upload_data(surface, gl_info, &format, srgb, mem);
6867 /* Restore the default pitch */
6869 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
6872 if (context) context_release(context);
6874 /* Don't delete PBO memory */
6875 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6876 HeapFree(GetProcessHeap(), 0, mem);
6882 surface->flags |= flag;
6884 if (flag != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6885 surface_evict_sysmem(surface);
6888 if (in_fbo && (surface->flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)))
6890 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
6891 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
6894 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6895 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6897 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6903 BOOL surface_is_offscreen(IWineD3DSurfaceImpl *surface)
6905 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6907 /* Not on a swapchain - must be offscreen */
6908 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6910 /* The front buffer is always onscreen */
6911 if (surface == swapchain->front_buffer) return FALSE;
6913 /* If the swapchain is rendered to an FBO, the backbuffer is
6914 * offscreen, otherwise onscreen */
6915 return swapchain->render_to_fbo;
6918 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
6921 IWineD3DBaseSurfaceImpl_QueryInterface,
6922 IWineD3DBaseSurfaceImpl_AddRef,
6923 IWineD3DSurfaceImpl_Release,
6924 /* IWineD3DResource */
6925 IWineD3DBaseSurfaceImpl_GetParent,
6926 IWineD3DBaseSurfaceImpl_SetPrivateData,
6927 IWineD3DBaseSurfaceImpl_GetPrivateData,
6928 IWineD3DBaseSurfaceImpl_FreePrivateData,
6929 IWineD3DBaseSurfaceImpl_SetPriority,
6930 IWineD3DBaseSurfaceImpl_GetPriority,
6931 IWineD3DSurfaceImpl_PreLoad,
6932 /* IWineD3DSurface */
6933 IWineD3DBaseSurfaceImpl_GetResource,
6934 IWineD3DSurfaceImpl_Map,
6935 IWineD3DSurfaceImpl_Unmap,
6936 IWineD3DSurfaceImpl_GetDC,
6937 IWineD3DSurfaceImpl_ReleaseDC,
6938 IWineD3DSurfaceImpl_Flip,
6939 IWineD3DSurfaceImpl_Blt,
6940 IWineD3DBaseSurfaceImpl_GetBltStatus,
6941 IWineD3DBaseSurfaceImpl_GetFlipStatus,
6942 IWineD3DBaseSurfaceImpl_IsLost,
6943 IWineD3DBaseSurfaceImpl_Restore,
6944 IWineD3DSurfaceImpl_BltFast,
6945 IWineD3DBaseSurfaceImpl_GetPalette,
6946 IWineD3DBaseSurfaceImpl_SetPalette,
6947 IWineD3DBaseSurfaceImpl_SetColorKey,
6948 IWineD3DBaseSurfaceImpl_GetPitch,
6949 IWineD3DSurfaceImpl_SetMem,
6950 IWineD3DBaseSurfaceImpl_SetOverlayPosition,
6951 IWineD3DBaseSurfaceImpl_GetOverlayPosition,
6952 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
6953 IWineD3DBaseSurfaceImpl_UpdateOverlay,
6954 IWineD3DBaseSurfaceImpl_SetClipper,
6955 IWineD3DBaseSurfaceImpl_GetClipper,
6957 IWineD3DSurfaceImpl_SetFormat,
6960 static HRESULT ffp_blit_alloc(IWineD3DDeviceImpl *device) { return WINED3D_OK; }
6961 /* Context activation is done by the caller. */
6962 static void ffp_blit_free(IWineD3DDeviceImpl *device) { }
6964 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6965 /* Context activation is done by the caller. */
6966 static void ffp_blit_p8_upload_palette(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
6969 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
6971 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6973 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6975 GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6979 /* Context activation is done by the caller. */
6980 static HRESULT ffp_blit_set(void *blit_priv, const struct wined3d_gl_info *gl_info, IWineD3DSurfaceImpl *surface)
6982 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6984 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6985 * else the surface is converted in software at upload time in LoadLocation.
6987 if(fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6988 ffp_blit_p8_upload_palette(surface, gl_info);
6991 glEnable(surface->texture_target);
6992 checkGLcall("glEnable(surface->texture_target)");
6997 /* Context activation is done by the caller. */
6998 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
7001 glDisable(GL_TEXTURE_2D);
7002 checkGLcall("glDisable(GL_TEXTURE_2D)");
7003 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
7005 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
7006 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
7008 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
7010 glDisable(GL_TEXTURE_RECTANGLE_ARB);
7011 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
7016 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
7017 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
7018 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
7020 enum complex_fixup src_fixup;
7024 case WINED3D_BLIT_OP_COLOR_BLIT:
7025 src_fixup = get_complex_fixup(src_format->color_fixup);
7026 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
7028 TRACE("Checking support for fixup:\n");
7029 dump_color_fixup_desc(src_format->color_fixup);
7032 if (!is_identity_fixup(dst_format->color_fixup))
7034 TRACE("Destination fixups are not supported\n");
7038 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
7040 TRACE("P8 fixup supported\n");
7044 /* We only support identity conversions. */
7045 if (is_identity_fixup(src_format->color_fixup))
7051 TRACE("[FAILED]\n");
7054 case WINED3D_BLIT_OP_COLOR_FILL:
7055 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
7057 TRACE("Color fill not supported\n");
7063 case WINED3D_BLIT_OP_DEPTH_FILL:
7067 TRACE("Unsupported blit_op=%d\n", blit_op);
7072 /* Do not call while under the GL lock. */
7073 static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface,
7074 const RECT *dst_rect, const WINED3DCOLORVALUE *color)
7076 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
7078 return device_clear_render_targets(device, 1, &dst_surface, NULL,
7079 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
7082 /* Do not call while under the GL lock. */
7083 static HRESULT ffp_blit_depth_fill(IWineD3DDeviceImpl *device,
7084 IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
7086 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
7088 return device_clear_render_targets(device, 0, NULL, surface,
7089 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
7092 const struct blit_shader ffp_blit = {
7098 ffp_blit_color_fill,
7099 ffp_blit_depth_fill,
7102 static HRESULT cpu_blit_alloc(IWineD3DDeviceImpl *device)
7107 /* Context activation is done by the caller. */
7108 static void cpu_blit_free(IWineD3DDeviceImpl *device)
7112 /* Context activation is done by the caller. */
7113 static HRESULT cpu_blit_set(void *blit_priv, const struct wined3d_gl_info *gl_info, IWineD3DSurfaceImpl *surface)
7118 /* Context activation is done by the caller. */
7119 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
7123 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
7124 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
7125 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
7127 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
7135 /* Do not call while under the GL lock. */
7136 static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface,
7137 const RECT *dst_rect, const WINED3DCOLORVALUE *color)
7141 memset(&BltFx, 0, sizeof(BltFx));
7142 BltFx.dwSize = sizeof(BltFx);
7143 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface->resource.format, color);
7144 return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect,
7145 NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
7148 /* Do not call while under the GL lock. */
7149 static HRESULT cpu_blit_depth_fill(IWineD3DDeviceImpl *device,
7150 IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
7152 FIXME("Depth filling not implemented by cpu_blit.\n");
7153 return WINED3DERR_INVALIDCALL;
7156 const struct blit_shader cpu_blit = {
7162 cpu_blit_color_fill,
7163 cpu_blit_depth_fill,
7166 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
7167 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
7168 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
7170 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
7173 /* Source and/or destination need to be on the GL side */
7174 if (src_pool == WINED3DPOOL_SYSTEMMEM || dst_pool == WINED3DPOOL_SYSTEMMEM)
7179 case WINED3D_BLIT_OP_COLOR_BLIT:
7180 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
7182 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
7186 case WINED3D_BLIT_OP_DEPTH_BLIT:
7187 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
7189 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
7197 if (!(src_format->id == dst_format->id
7198 || (is_identity_fixup(src_format->color_fixup)
7199 && is_identity_fixup(dst_format->color_fixup))))
7205 static ULONG WINAPI IWineGDISurfaceImpl_Release(IWineD3DSurface *iface)
7207 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7210 TRACE("Surface %p, container %p of type %#x.\n",
7211 surface, surface->container.u.base, surface->container.type);
7213 switch (surface->container.type)
7215 case WINED3D_CONTAINER_TEXTURE:
7216 return wined3d_texture_decref(surface->container.u.texture);
7218 case WINED3D_CONTAINER_SWAPCHAIN:
7219 return wined3d_swapchain_decref(surface->container.u.swapchain);
7222 ERR("Unhandled container type %#x.\n", surface->container.type);
7223 case WINED3D_CONTAINER_NONE:
7227 refcount = InterlockedDecrement(&surface->resource.ref);
7228 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
7232 surface_gdi_cleanup(surface);
7233 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
7235 TRACE("Destroyed surface %p.\n", surface);
7236 HeapFree(GetProcessHeap(), 0, surface);
7242 static void WINAPI IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
7244 ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
7245 ERR("(%p): Most likely the parent library did something wrong.\n", iface);
7246 ERR("(%p): Please report to wine-devel\n", iface);
7249 static HRESULT WINAPI IWineGDISurfaceImpl_Map(IWineD3DSurface *iface,
7250 WINED3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
7252 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7254 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
7255 iface, locked_rect, wine_dbgstr_rect(rect), flags);
7257 /* Already locked? */
7258 if (surface->flags & SFLAG_LOCKED)
7260 WARN("Surface already mapped.\n");
7261 /* What should I return here? */
7262 return WINED3DERR_INVALIDCALL;
7264 surface->flags |= SFLAG_LOCKED;
7266 if (!surface->resource.allocatedMemory)
7268 /* This happens on gdi surfaces if the application set a user pointer
7269 * and resets it. Recreate the DIB section. */
7270 surface_create_dib_section(surface);
7271 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7274 return IWineD3DBaseSurfaceImpl_Map(iface, locked_rect, rect, flags);
7277 static HRESULT WINAPI IWineGDISurfaceImpl_Unmap(IWineD3DSurface *iface)
7279 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7281 TRACE("iface %p.\n", iface);
7283 if (!(surface->flags & SFLAG_LOCKED))
7285 WARN("Trying to unmap unmapped surface.\n");
7286 return WINEDDERR_NOTLOCKED;
7289 /* Tell the swapchain to update the screen. */
7290 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
7292 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
7293 if (surface == swapchain->front_buffer)
7295 x11_copy_to_screen(swapchain, &surface->lockedRect);
7299 surface->flags &= ~SFLAG_LOCKED;
7300 memset(&surface->lockedRect, 0, sizeof(RECT));
7305 /*****************************************************************************
7306 * IWineD3DSurface::Flip, GDI version
7308 * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
7309 * the parent library. This implementation changes the data pointers of the
7310 * surfaces and copies the new front buffer content to the screen
7313 * override: Flipping target(e.g. back buffer)
7316 * WINED3D_OK on success
7318 *****************************************************************************/
7319 static HRESULT WINAPI IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD flags)
7321 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7322 struct wined3d_swapchain *swapchain;
7325 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
7327 ERR("Flipped surface is not on a swapchain\n");
7328 return WINEDDERR_NOTFLIPPABLE;
7331 swapchain = surface->container.u.swapchain;
7332 hr = wined3d_swapchain_present(swapchain, NULL, NULL, swapchain->win_handle, NULL, 0);
7337 static HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *dc)
7339 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7340 WINED3DLOCKED_RECT lock;
7344 TRACE("iface %p, dc %p.\n", iface, dc);
7346 if (!(surface->flags & SFLAG_DIBSECTION))
7348 WARN("DC not supported on this surface\n");
7349 return WINED3DERR_INVALIDCALL;
7352 if (surface->flags & SFLAG_USERPTR)
7354 ERR("Not supported on surfaces with application-provided memory.\n");
7355 return WINEDDERR_NODC;
7358 /* Give more detailed info for ddraw. */
7359 if (surface->flags & SFLAG_DCINUSE)
7360 return WINEDDERR_DCALREADYCREATED;
7362 /* Can't GetDC if the surface is locked. */
7363 if (surface->flags & SFLAG_LOCKED)
7364 return WINED3DERR_INVALIDCALL;
7366 memset(&lock, 0, sizeof(lock)); /* To be sure */
7368 /* Should have a DIB section already. */
7370 /* Map the surface. */
7371 hr = IWineD3DSurface_Map(iface, &lock, NULL, 0);
7374 ERR("IWineD3DSurface_Map failed, hr %#x.\n", hr);
7375 /* keep the dib section */
7379 if (surface->resource.format->id == WINED3DFMT_P8_UINT
7380 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
7382 const PALETTEENTRY *pal = NULL;
7384 if (surface->palette)
7386 pal = surface->palette->palents;
7390 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
7391 IWineD3DSurfaceImpl *dds_primary = swapchain->front_buffer;
7393 if (dds_primary && dds_primary->palette)
7394 pal = dds_primary->palette->palents;
7401 for (i = 0; i < 256; ++i)
7403 col[i].rgbRed = pal[i].peRed;
7404 col[i].rgbGreen = pal[i].peGreen;
7405 col[i].rgbBlue = pal[i].peBlue;
7406 col[i].rgbReserved = 0;
7408 SetDIBColorTable(surface->hDC, 0, 256, col);
7412 surface->flags |= SFLAG_DCINUSE;
7415 TRACE("Returning dc %p.\n", *dc);
7420 static HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC dc)
7422 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7424 TRACE("iface %p, dc %p.\n", iface, dc);
7426 if (!(surface->flags & SFLAG_DCINUSE))
7427 return WINEDDERR_NODC;
7429 if (surface->hDC != dc)
7431 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
7433 return WINEDDERR_NODC;
7436 /* We locked first, so unlock now. */
7437 IWineD3DSurface_Unmap(iface);
7439 surface->flags &= ~SFLAG_DCINUSE;
7444 static HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *mem)
7446 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7448 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
7449 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
7451 ERR("Not supported on render targets.\n");
7452 return WINED3DERR_INVALIDCALL;
7455 if (surface->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
7457 WARN("Surface is locked or the DC is in use.\n");
7458 return WINED3DERR_INVALIDCALL;
7461 if (mem && mem != surface->resource.allocatedMemory)
7463 void *release = NULL;
7465 /* Do I have to copy the old surface content? */
7466 if (surface->flags & SFLAG_DIBSECTION)
7468 SelectObject(surface->hDC, surface->dib.holdbitmap);
7469 DeleteDC(surface->hDC);
7470 /* Release the DIB section. */
7471 DeleteObject(surface->dib.DIBsection);
7472 surface->dib.bitmap_data = NULL;
7473 surface->resource.allocatedMemory = NULL;
7474 surface->hDC = NULL;
7475 surface->flags &= ~SFLAG_DIBSECTION;
7477 else if (!(surface->flags & SFLAG_USERPTR))
7479 release = surface->resource.allocatedMemory;
7481 surface->resource.allocatedMemory = mem;
7482 surface->flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
7484 /* Now free the old memory, if any. */
7485 HeapFree(GetProcessHeap(), 0, release);
7487 else if (surface->flags & SFLAG_USERPTR)
7489 /* Map() and GetDC() will re-create the dib section and allocated memory. */
7490 surface->resource.allocatedMemory = NULL;
7491 surface->flags &= ~SFLAG_USERPTR;
7497 static const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
7500 IWineD3DBaseSurfaceImpl_QueryInterface,
7501 IWineD3DBaseSurfaceImpl_AddRef,
7502 IWineGDISurfaceImpl_Release,
7503 /* IWineD3DResource */
7504 IWineD3DBaseSurfaceImpl_GetParent,
7505 IWineD3DBaseSurfaceImpl_SetPrivateData,
7506 IWineD3DBaseSurfaceImpl_GetPrivateData,
7507 IWineD3DBaseSurfaceImpl_FreePrivateData,
7508 IWineD3DBaseSurfaceImpl_SetPriority,
7509 IWineD3DBaseSurfaceImpl_GetPriority,
7510 IWineGDISurfaceImpl_PreLoad,
7511 /* IWineD3DSurface */
7512 IWineD3DBaseSurfaceImpl_GetResource,
7513 IWineGDISurfaceImpl_Map,
7514 IWineGDISurfaceImpl_Unmap,
7515 IWineGDISurfaceImpl_GetDC,
7516 IWineGDISurfaceImpl_ReleaseDC,
7517 IWineGDISurfaceImpl_Flip,
7518 IWineD3DBaseSurfaceImpl_Blt,
7519 IWineD3DBaseSurfaceImpl_GetBltStatus,
7520 IWineD3DBaseSurfaceImpl_GetFlipStatus,
7521 IWineD3DBaseSurfaceImpl_IsLost,
7522 IWineD3DBaseSurfaceImpl_Restore,
7523 IWineD3DBaseSurfaceImpl_BltFast,
7524 IWineD3DBaseSurfaceImpl_GetPalette,
7525 IWineD3DBaseSurfaceImpl_SetPalette,
7526 IWineD3DBaseSurfaceImpl_SetColorKey,
7527 IWineD3DBaseSurfaceImpl_GetPitch,
7528 IWineGDISurfaceImpl_SetMem,
7529 IWineD3DBaseSurfaceImpl_SetOverlayPosition,
7530 IWineD3DBaseSurfaceImpl_GetOverlayPosition,
7531 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
7532 IWineD3DBaseSurfaceImpl_UpdateOverlay,
7533 IWineD3DBaseSurfaceImpl_SetClipper,
7534 IWineD3DBaseSurfaceImpl_GetClipper,
7536 IWineD3DBaseSurfaceImpl_SetFormat,
7539 HRESULT surface_init(IWineD3DSurfaceImpl *surface, WINED3DSURFTYPE surface_type, UINT alignment,
7540 UINT width, UINT height, UINT level, BOOL lockable, BOOL discard, WINED3DMULTISAMPLE_TYPE multisample_type,
7541 UINT multisample_quality, IWineD3DDeviceImpl *device, DWORD usage, enum wined3d_format_id format_id,
7542 WINED3DPOOL pool, void *parent, const struct wined3d_parent_ops *parent_ops)
7544 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7545 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7546 void (*cleanup)(IWineD3DSurfaceImpl *This);
7547 unsigned int resource_size;
7550 if (multisample_quality > 0)
7552 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7553 multisample_quality = 0;
7556 /* Quick lockable sanity check.
7557 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7558 * this function is too deep to need to care about things like this.
7559 * Levels need to be checked too, since they all affect what can be done. */
7562 case WINED3DPOOL_SCRATCH:
7565 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7566 "which are mutually exclusive, setting lockable to TRUE.\n");
7571 case WINED3DPOOL_SYSTEMMEM:
7573 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7576 case WINED3DPOOL_MANAGED:
7577 if (usage & WINED3DUSAGE_DYNAMIC)
7578 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7581 case WINED3DPOOL_DEFAULT:
7582 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7583 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7587 FIXME("Unknown pool %#x.\n", pool);
7591 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3DPOOL_DEFAULT)
7592 FIXME("Trying to create a render target that isn't in the default pool.\n");
7594 /* FIXME: Check that the format is supported by the device. */
7596 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7598 return WINED3DERR_INVALIDCALL;
7600 surface->surface_type = surface_type;
7602 /* Look at the implementation and set the correct Vtable. */
7603 switch (surface_type)
7605 case SURFACE_OPENGL:
7606 surface->lpVtbl = &IWineD3DSurface_Vtbl;
7607 surface->surface_ops = &surface_ops;
7608 cleanup = surface_cleanup;
7612 surface->lpVtbl = &IWineGDISurface_Vtbl;
7613 surface->surface_ops = &gdi_surface_ops;
7614 cleanup = surface_gdi_cleanup;
7618 ERR("Requested unknown surface implementation %#x.\n", surface_type);
7619 return WINED3DERR_INVALIDCALL;
7622 hr = resource_init(&surface->resource, device, WINED3DRTYPE_SURFACE, format,
7623 multisample_type, multisample_quality, usage, pool, width, height, 1,
7624 resource_size, parent, parent_ops, &surface_resource_ops);
7627 WARN("Failed to initialize resource, returning %#x.\n", hr);
7631 /* "Standalone" surface. */
7632 surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7634 surface->texture_level = level;
7635 list_init(&surface->overlays);
7638 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7640 surface->flags |= SFLAG_DISCARD;
7641 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7642 surface->flags |= SFLAG_LOCKABLE;
7644 /* Mark the texture as dirty so that it gets loaded first time around. */
7645 surface_add_dirty_rect(surface, NULL);
7646 list_init(&surface->renderbuffers);
7648 TRACE("surface %p, memory %p, size %u\n",
7649 surface, surface->resource.allocatedMemory, surface->resource.size);
7651 /* Call the private setup routine */
7652 hr = surface->surface_ops->surface_private_setup(surface);
7655 ERR("Private setup failed, returning %#x\n", hr);