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 HRESULT surface_cpu_blt(IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect,
39 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD flags,
40 const WINEDDBLTFX *fx, WINED3DTEXTUREFILTERTYPE filter);
41 static HRESULT surface_cpu_bltfast(IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
42 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD trans);
43 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect,
44 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *fx,
45 WINED3DTEXTUREFILTERTYPE filter);
47 static void surface_cleanup(IWineD3DSurfaceImpl *This)
49 TRACE("(%p) : Cleaning up.\n", This);
51 if (This->texture_name || (This->flags & SFLAG_PBO) || !list_empty(&This->renderbuffers))
53 const struct wined3d_gl_info *gl_info;
54 renderbuffer_entry_t *entry, *entry2;
55 struct wined3d_context *context;
57 context = context_acquire(This->resource.device, NULL);
58 gl_info = context->gl_info;
62 if (This->texture_name)
64 TRACE("Deleting texture %u.\n", This->texture_name);
65 glDeleteTextures(1, &This->texture_name);
68 if (This->flags & SFLAG_PBO)
70 TRACE("Deleting PBO %u.\n", This->pbo);
71 GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
74 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry)
76 TRACE("Deleting renderbuffer %u.\n", entry->id);
77 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
78 HeapFree(GetProcessHeap(), 0, entry);
83 context_release(context);
86 if (This->flags & SFLAG_DIBSECTION)
89 SelectObject(This->hDC, This->dib.holdbitmap);
91 /* Release the DIB section. */
92 DeleteObject(This->dib.DIBsection);
93 This->dib.bitmap_data = NULL;
94 This->resource.allocatedMemory = NULL;
97 if (This->flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
98 if (This->overlay_dest) list_remove(&This->overlay_entry);
100 HeapFree(GetProcessHeap(), 0, This->palette9);
102 resource_cleanup(&This->resource);
105 void surface_set_container(IWineD3DSurfaceImpl *surface, enum wined3d_container_type type, void *container)
107 TRACE("surface %p, container %p.\n", surface, container);
109 if (!container && type != WINED3D_CONTAINER_NONE)
110 ERR("Setting NULL container of type %#x.\n", type);
112 if (type == WINED3D_CONTAINER_SWAPCHAIN)
114 surface->get_drawable_size = get_drawable_size_swapchain;
118 switch (wined3d_settings.offscreen_rendering_mode)
121 surface->get_drawable_size = get_drawable_size_fbo;
125 surface->get_drawable_size = get_drawable_size_backbuffer;
129 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
134 surface->container.type = type;
135 surface->container.u.base = container;
142 enum tex_types tex_type;
143 GLfloat coords[4][3];
154 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
156 f->l = ((r->left * 2.0f) / w) - 1.0f;
157 f->t = ((r->top * 2.0f) / h) - 1.0f;
158 f->r = ((r->right * 2.0f) / w) - 1.0f;
159 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
162 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
164 GLfloat (*coords)[3] = info->coords;
170 FIXME("Unsupported texture target %#x\n", target);
171 /* Fall back to GL_TEXTURE_2D */
173 info->binding = GL_TEXTURE_BINDING_2D;
174 info->bind_target = GL_TEXTURE_2D;
175 info->tex_type = tex_2d;
176 coords[0][0] = (float)rect->left / w;
177 coords[0][1] = (float)rect->top / h;
180 coords[1][0] = (float)rect->right / w;
181 coords[1][1] = (float)rect->top / h;
184 coords[2][0] = (float)rect->left / w;
185 coords[2][1] = (float)rect->bottom / h;
188 coords[3][0] = (float)rect->right / w;
189 coords[3][1] = (float)rect->bottom / h;
193 case GL_TEXTURE_RECTANGLE_ARB:
194 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
195 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
196 info->tex_type = tex_rect;
197 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
198 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
199 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
200 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
203 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
204 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
205 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
206 info->tex_type = tex_cube;
207 cube_coords_float(rect, w, h, &f);
209 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
210 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
211 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
212 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
215 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
216 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
217 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
218 info->tex_type = tex_cube;
219 cube_coords_float(rect, w, h, &f);
221 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
222 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
223 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
224 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
227 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
228 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
229 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
230 info->tex_type = tex_cube;
231 cube_coords_float(rect, w, h, &f);
233 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
234 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
235 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
236 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
239 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
240 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
241 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
242 info->tex_type = tex_cube;
243 cube_coords_float(rect, w, h, &f);
245 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
246 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
247 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
248 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
251 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
252 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
253 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
254 info->tex_type = tex_cube;
255 cube_coords_float(rect, w, h, &f);
257 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
258 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
259 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
260 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
263 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
264 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
265 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
266 info->tex_type = tex_cube;
267 cube_coords_float(rect, w, h, &f);
269 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
270 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
271 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
272 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
277 static inline void surface_get_rect(IWineD3DSurfaceImpl *This, const RECT *rect_in, RECT *rect_out)
280 *rect_out = *rect_in;
285 rect_out->right = This->resource.width;
286 rect_out->bottom = This->resource.height;
290 /* GL locking and context activation is done by the caller */
291 void draw_textured_quad(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, const RECT *dst_rect, WINED3DTEXTUREFILTERTYPE Filter)
293 struct blt_info info;
295 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
297 glEnable(info.bind_target);
298 checkGLcall("glEnable(bind_target)");
300 /* Bind the texture */
301 glBindTexture(info.bind_target, src_surface->texture_name);
302 checkGLcall("glBindTexture");
304 /* Filtering for StretchRect */
305 glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
306 wined3d_gl_mag_filter(magLookup, Filter));
307 checkGLcall("glTexParameteri");
308 glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
309 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
310 checkGLcall("glTexParameteri");
311 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
312 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
313 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
314 checkGLcall("glTexEnvi");
317 glBegin(GL_TRIANGLE_STRIP);
318 glTexCoord3fv(info.coords[0]);
319 glVertex2i(dst_rect->left, dst_rect->top);
321 glTexCoord3fv(info.coords[1]);
322 glVertex2i(dst_rect->right, dst_rect->top);
324 glTexCoord3fv(info.coords[2]);
325 glVertex2i(dst_rect->left, dst_rect->bottom);
327 glTexCoord3fv(info.coords[3]);
328 glVertex2i(dst_rect->right, dst_rect->bottom);
331 /* Unbind the texture */
332 glBindTexture(info.bind_target, 0);
333 checkGLcall("glBindTexture(info->bind_target, 0)");
335 /* We changed the filtering settings on the texture. Inform the
336 * container about this to get the filters reset properly next draw. */
337 if (src_surface->container.type == WINED3D_CONTAINER_TEXTURE)
339 struct wined3d_texture *texture = src_surface->container.u.texture;
340 texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
341 texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
342 texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
346 static HRESULT surface_create_dib_section(IWineD3DSurfaceImpl *surface)
348 const struct wined3d_format *format = surface->resource.format;
356 TRACE("surface %p.\n", surface);
358 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
360 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
361 return WINED3DERR_INVALIDCALL;
364 switch (format->byte_count)
368 /* Allocate extra space to store the RGB bit masks. */
369 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
373 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
377 /* Allocate extra space for a palette. */
378 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
379 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
384 return E_OUTOFMEMORY;
386 /* Some applications access the surface in via DWORDs, and do not take
387 * the necessary care at the end of the surface. So we need at least
388 * 4 extra bytes at the end of the surface. Check against the page size,
389 * if the last page used for the surface has at least 4 spare bytes we're
390 * safe, otherwise add an extra line to the DIB section. */
391 GetSystemInfo(&sysInfo);
392 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
395 TRACE("Adding an extra line to the DIB section.\n");
398 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
399 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
400 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface) / format->byte_count;
401 b_info->bmiHeader.biHeight = -surface->resource.height - extraline;
402 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
403 * IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
404 b_info->bmiHeader.biPlanes = 1;
405 b_info->bmiHeader.biBitCount = format->byte_count * 8;
407 b_info->bmiHeader.biXPelsPerMeter = 0;
408 b_info->bmiHeader.biYPelsPerMeter = 0;
409 b_info->bmiHeader.biClrUsed = 0;
410 b_info->bmiHeader.biClrImportant = 0;
412 /* Get the bit masks */
413 masks = (DWORD *)b_info->bmiColors;
414 switch (surface->resource.format->id)
416 case WINED3DFMT_B8G8R8_UNORM:
417 usage = DIB_RGB_COLORS;
418 b_info->bmiHeader.biCompression = BI_RGB;
421 case WINED3DFMT_B5G5R5X1_UNORM:
422 case WINED3DFMT_B5G5R5A1_UNORM:
423 case WINED3DFMT_B4G4R4A4_UNORM:
424 case WINED3DFMT_B4G4R4X4_UNORM:
425 case WINED3DFMT_B2G3R3_UNORM:
426 case WINED3DFMT_B2G3R3A8_UNORM:
427 case WINED3DFMT_R10G10B10A2_UNORM:
428 case WINED3DFMT_R8G8B8A8_UNORM:
429 case WINED3DFMT_R8G8B8X8_UNORM:
430 case WINED3DFMT_B10G10R10A2_UNORM:
431 case WINED3DFMT_B5G6R5_UNORM:
432 case WINED3DFMT_R16G16B16A16_UNORM:
434 b_info->bmiHeader.biCompression = BI_BITFIELDS;
435 masks[0] = format->red_mask;
436 masks[1] = format->green_mask;
437 masks[2] = format->blue_mask;
441 /* Don't know palette */
442 b_info->bmiHeader.biCompression = BI_RGB;
447 if (!(dc = GetDC(0)))
449 HeapFree(GetProcessHeap(), 0, b_info);
450 return HRESULT_FROM_WIN32(GetLastError());
453 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
454 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
455 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
456 surface->dib.DIBsection = CreateDIBSection(dc, b_info, usage, &surface->dib.bitmap_data, 0, 0);
459 if (!surface->dib.DIBsection)
461 ERR("Failed to create DIB section.\n");
462 HeapFree(GetProcessHeap(), 0, b_info);
463 return HRESULT_FROM_WIN32(GetLastError());
466 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
467 /* Copy the existing surface to the dib section. */
468 if (surface->resource.allocatedMemory)
470 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
471 surface->resource.height * IWineD3DSurface_GetPitch((IWineD3DSurface *)surface));
475 /* This is to make maps read the GL texture although memory is allocated. */
476 surface->flags &= ~SFLAG_INSYSMEM;
478 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
480 HeapFree(GetProcessHeap(), 0, b_info);
482 /* Now allocate a DC. */
483 surface->hDC = CreateCompatibleDC(0);
484 surface->dib.holdbitmap = SelectObject(surface->hDC, surface->dib.DIBsection);
485 TRACE("Using wined3d palette %p.\n", surface->palette);
486 SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
488 surface->flags |= SFLAG_DIBSECTION;
490 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
491 surface->resource.heapMemory = NULL;
496 static void surface_prepare_system_memory(IWineD3DSurfaceImpl *surface)
498 IWineD3DDeviceImpl *device = surface->resource.device;
499 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
501 TRACE("surface %p.\n", surface);
503 /* Performance optimization: Count how often a surface is locked, if it is
504 * locked regularly do not throw away the system memory copy. This avoids
505 * the need to download the surface from OpenGL all the time. The surface
506 * is still downloaded if the OpenGL texture is changed. */
507 if (!(surface->flags & SFLAG_DYNLOCK))
509 if (++surface->lockCount > MAXLOCKCOUNT)
511 TRACE("Surface is locked regularly, not freeing the system memory copy any more.\n");
512 surface->flags |= SFLAG_DYNLOCK;
516 /* Create a PBO for dynamically locked surfaces but don't do it for
517 * converted or NPOT surfaces. Also don't create a PBO for systemmem
519 if (gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && (surface->flags & SFLAG_DYNLOCK)
520 && !(surface->flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2))
521 && (surface->resource.pool != WINED3DPOOL_SYSTEMMEM))
523 struct wined3d_context *context;
526 context = context_acquire(device, NULL);
529 GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
530 error = glGetError();
531 if (!surface->pbo || error != GL_NO_ERROR)
532 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
534 TRACE("Binding PBO %u.\n", surface->pbo);
536 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
537 checkGLcall("glBindBufferARB");
539 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
540 surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
541 checkGLcall("glBufferDataARB");
543 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
544 checkGLcall("glBindBufferARB");
546 /* We don't need the system memory anymore and we can't even use it for PBOs. */
547 if (!(surface->flags & SFLAG_CLIENT))
549 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
550 surface->resource.heapMemory = NULL;
552 surface->resource.allocatedMemory = NULL;
553 surface->flags |= SFLAG_PBO;
555 context_release(context);
557 else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO))
559 /* Whatever surface we have, make sure that there is memory allocated
560 * for the downloaded copy, or a PBO to map. */
561 if (!surface->resource.heapMemory)
562 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
564 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
565 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
567 if (surface->flags & SFLAG_INSYSMEM)
568 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
572 static void surface_evict_sysmem(IWineD3DSurfaceImpl *surface)
574 if (surface->flags & SFLAG_DONOTFREE)
577 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
578 surface->resource.allocatedMemory = NULL;
579 surface->resource.heapMemory = NULL;
580 surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
583 /* Context activation is done by the caller. */
584 static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *surface,
585 const struct wined3d_gl_info *gl_info, BOOL srgb)
587 IWineD3DDeviceImpl *device = surface->resource.device;
588 DWORD active_sampler;
589 GLint active_texture;
591 /* We don't need a specific texture unit, but after binding the texture
592 * the current unit is dirty. Read the unit back instead of switching to
593 * 0, this avoids messing around with the state manager's GL states. The
594 * current texture unit should always be a valid one.
596 * To be more specific, this is tricky because we can implicitly be
597 * called from sampler() in state.c. This means we can't touch anything
598 * other than whatever happens to be the currently active texture, or we
599 * would risk marking already applied sampler states dirty again.
601 * TODO: Track the current active texture per GL context instead of using
605 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
607 active_sampler = device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
609 if (active_sampler != WINED3D_UNMAPPED_STAGE)
611 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(active_sampler));
613 surface_bind(surface, gl_info, srgb);
616 static void surface_force_reload(IWineD3DSurfaceImpl *surface)
618 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
621 static void surface_release_client_storage(IWineD3DSurfaceImpl *surface)
623 struct wined3d_context *context = context_acquire(surface->resource.device, NULL);
626 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
627 if (surface->texture_name)
629 surface_bind_and_dirtify(surface, context->gl_info, FALSE);
630 glTexImage2D(surface->texture_target, surface->texture_level,
631 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
633 if (surface->texture_name_srgb)
635 surface_bind_and_dirtify(surface, context->gl_info, TRUE);
636 glTexImage2D(surface->texture_target, surface->texture_level,
637 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
639 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
642 context_release(context);
644 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
645 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
646 surface_force_reload(surface);
649 static HRESULT surface_private_setup(struct IWineD3DSurfaceImpl *surface)
651 /* TODO: Check against the maximum texture sizes supported by the video card. */
652 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
653 unsigned int pow2Width, pow2Height;
655 TRACE("surface %p.\n", surface);
657 surface->texture_name = 0;
658 surface->texture_target = GL_TEXTURE_2D;
660 /* Non-power2 support */
661 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
663 pow2Width = surface->resource.width;
664 pow2Height = surface->resource.height;
668 /* Find the nearest pow2 match */
669 pow2Width = pow2Height = 1;
670 while (pow2Width < surface->resource.width)
672 while (pow2Height < surface->resource.height)
675 surface->pow2Width = pow2Width;
676 surface->pow2Height = pow2Height;
678 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
680 /* TODO: Add support for non power two compressed textures. */
681 if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
683 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
684 surface, surface->resource.width, surface->resource.height);
685 return WINED3DERR_NOTAVAILABLE;
689 if (pow2Width != surface->resource.width
690 || pow2Height != surface->resource.height)
692 surface->flags |= SFLAG_NONPOW2;
695 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
696 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
698 /* One of three options:
699 * 1: Do the same as we do with NPOT and scale the texture, (any
700 * texture ops would require the texture to be scaled which is
702 * 2: Set the texture to the maximum size (bad idea).
703 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
704 * 4: Create the surface, but allow it to be used only for DirectDraw
705 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
706 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
707 * the render target. */
708 if (surface->resource.pool == WINED3DPOOL_DEFAULT || surface->resource.pool == WINED3DPOOL_MANAGED)
710 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
711 return WINED3DERR_NOTAVAILABLE;
714 /* We should never use this surface in combination with OpenGL! */
715 TRACE("Creating an oversized surface: %ux%u.\n",
716 surface->pow2Width, surface->pow2Height);
720 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
721 * and EXT_PALETTED_TEXTURE is used in combination with texture
722 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
723 * EXT_PALETTED_TEXTURE doesn't work in combination with
724 * ARB_TEXTURE_RECTANGLE. */
725 if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
726 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
727 && gl_info->supported[EXT_PALETTED_TEXTURE]
728 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
730 surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
731 surface->pow2Width = surface->resource.width;
732 surface->pow2Height = surface->resource.height;
733 surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
737 switch (wined3d_settings.offscreen_rendering_mode)
740 surface->get_drawable_size = get_drawable_size_fbo;
744 surface->get_drawable_size = get_drawable_size_backbuffer;
748 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
749 return WINED3DERR_INVALIDCALL;
752 surface->flags |= SFLAG_INSYSMEM;
757 static void surface_realize_palette(IWineD3DSurfaceImpl *surface)
759 struct wined3d_palette *palette = surface->palette;
761 TRACE("surface %p.\n", surface);
763 if (!palette) return;
765 if (surface->resource.format->id == WINED3DFMT_P8_UINT
766 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
768 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
770 /* Make sure the texture is up to date. This call doesn't do
771 * anything if the texture is already up to date. */
772 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
774 /* We want to force a palette refresh, so mark the drawable as not being up to date */
775 if (!surface_is_offscreen(surface))
776 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
780 if (!(surface->flags & SFLAG_INSYSMEM))
782 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
783 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
785 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
789 if (surface->flags & SFLAG_DIBSECTION)
794 TRACE("Updating the DC's palette.\n");
796 for (i = 0; i < 256; ++i)
798 col[i].rgbRed = palette->palents[i].peRed;
799 col[i].rgbGreen = palette->palents[i].peGreen;
800 col[i].rgbBlue = palette->palents[i].peBlue;
801 col[i].rgbReserved = 0;
803 SetDIBColorTable(surface->hDC, 0, 256, col);
806 /* Propagate the changes to the drawable when we have a palette. */
807 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
808 surface_load_location(surface, SFLAG_INDRAWABLE, NULL);
811 static HRESULT surface_draw_overlay(IWineD3DSurfaceImpl *surface)
815 /* If there's no destination surface there is nothing to do. */
816 if (!surface->overlay_dest)
819 /* Blt calls ModifyLocation on the dest surface, which in turn calls
820 * DrawOverlay to update the overlay. Prevent an endless recursion. */
821 if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
824 surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
825 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface->overlay_dest,
826 &surface->overlay_destrect, (IWineD3DSurface *)surface, &surface->overlay_srcrect,
827 WINEDDBLT_WAIT, NULL, WINED3DTEXF_LINEAR);
828 surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
833 static void surface_preload(IWineD3DSurfaceImpl *surface)
835 TRACE("surface %p.\n", surface);
837 surface_internal_preload(surface, SRGB_ANY);
840 static void surface_map(IWineD3DSurfaceImpl *surface, const RECT *rect, DWORD flags)
842 IWineD3DDeviceImpl *device = surface->resource.device;
843 const RECT *pass_rect = rect;
845 TRACE("surface %p, rect %s, flags %#x.\n",
846 surface, wine_dbgstr_rect(rect), flags);
848 if (flags & WINED3DLOCK_DISCARD)
850 TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n");
851 surface_prepare_system_memory(surface);
852 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
856 /* surface_load_location() does not check if the rectangle specifies
857 * the full surface. Most callers don't need that, so do it here. */
858 if (rect && !rect->top && !rect->left
859 && rect->right == surface->resource.width
860 && rect->bottom == surface->resource.height)
863 if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
864 && ((surface->container.type == WINED3D_CONTAINER_SWAPCHAIN) || surface == device->render_targets[0])))
865 surface_load_location(surface, SFLAG_INSYSMEM, pass_rect);
868 if (surface->flags & SFLAG_PBO)
870 const struct wined3d_gl_info *gl_info;
871 struct wined3d_context *context;
873 context = context_acquire(device, NULL);
874 gl_info = context->gl_info;
877 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
878 checkGLcall("glBindBufferARB");
880 /* This shouldn't happen but could occur if some other function
881 * didn't handle the PBO properly. */
882 if (surface->resource.allocatedMemory)
883 ERR("The surface already has PBO memory allocated.\n");
885 surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
886 checkGLcall("glMapBufferARB");
888 /* Make sure the PBO isn't set anymore in order not to break non-PBO
890 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
891 checkGLcall("glBindBufferARB");
894 context_release(context);
897 if (!(flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)))
900 surface_add_dirty_rect(surface, NULL);
907 b.Right = rect->right;
908 b.Bottom = rect->bottom;
911 surface_add_dirty_rect(surface, &b);
916 static void surface_unmap(IWineD3DSurfaceImpl *surface)
918 IWineD3DDeviceImpl *device = surface->resource.device;
921 TRACE("surface %p.\n", surface);
923 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
925 if (surface->flags & SFLAG_PBO)
927 const struct wined3d_gl_info *gl_info;
928 struct wined3d_context *context;
930 TRACE("Freeing PBO memory.\n");
932 context = context_acquire(device, NULL);
933 gl_info = context->gl_info;
936 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
937 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
938 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
939 checkGLcall("glUnmapBufferARB");
941 context_release(context);
943 surface->resource.allocatedMemory = NULL;
946 TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
948 if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
950 TRACE("Not dirtified, nothing to do.\n");
954 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
955 || (device->render_targets && surface == device->render_targets[0]))
957 if (wined3d_settings.rendertargetlock_mode == RTL_DISABLE)
959 static BOOL warned = FALSE;
962 ERR("The application tries to write to the render target, but render target locking is disabled.\n");
968 if (!surface->dirtyRect.left && !surface->dirtyRect.top
969 && surface->dirtyRect.right == surface->resource.width
970 && surface->dirtyRect.bottom == surface->resource.height)
976 /* TODO: Proper partial rectangle tracking. */
978 surface->flags |= SFLAG_INSYSMEM;
981 surface_load_location(surface, SFLAG_INDRAWABLE, fullsurface ? NULL : &surface->dirtyRect);
983 /* Partial rectangle tracking is not commonly implemented, it is only
984 * done for render targets. INSYSMEM was set before to tell
985 * surface_load_location() where to read the rectangle from.
986 * Indrawable is set because all modifications from the partial
987 * sysmem copy are written back to the drawable, thus the surface is
988 * merged again in the drawable. The sysmem copy is not fully up to
989 * date because only a subrectangle was read in Map(). */
992 surface_modify_location(surface, SFLAG_INDRAWABLE, TRUE);
993 surface_evict_sysmem(surface);
996 surface->dirtyRect.left = surface->resource.width;
997 surface->dirtyRect.top = surface->resource.height;
998 surface->dirtyRect.right = 0;
999 surface->dirtyRect.bottom = 0;
1001 else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1003 FIXME("Depth / stencil buffer locking is not implemented.\n");
1007 /* Overlays have to be redrawn manually after changes with the GL implementation */
1008 if (surface->overlay_dest)
1009 surface->surface_ops->surface_draw_overlay(surface);
1012 static HRESULT surface_getdc(IWineD3DSurfaceImpl *surface)
1014 WINED3DLOCKED_RECT lock;
1017 TRACE("surface %p.\n", surface);
1019 /* Create a DIB section if there isn't a dc yet. */
1022 if (surface->flags & SFLAG_CLIENT)
1024 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1025 surface_release_client_storage(surface);
1027 hr = surface_create_dib_section(surface);
1029 return WINED3DERR_INVALIDCALL;
1031 /* Use the DIB section from now on if we are not using a PBO. */
1032 if (!(surface->flags & SFLAG_PBO))
1033 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1036 /* Map the surface. */
1037 hr = IWineD3DSurface_Map((IWineD3DSurface *)surface, &lock, NULL, 0);
1039 ERR("Map failed, hr %#x.\n", hr);
1041 /* Sync the DIB with the PBO. This can't be done earlier because Map()
1042 * activates the allocatedMemory. */
1043 if (surface->flags & SFLAG_PBO)
1044 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->dib.bitmap_size);
1049 static HRESULT surface_flip(IWineD3DSurfaceImpl *surface, IWineD3DSurfaceImpl *override)
1051 TRACE("surface %p, override %p.\n", surface, override);
1053 /* Flipping is only supported on render targets and overlays. */
1054 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
1056 WARN("Tried to flip a non-render target, non-overlay surface.\n");
1057 return WINEDDERR_NOTFLIPPABLE;
1060 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
1062 flip_surface(surface, override);
1064 /* Update the overlay if it is visible */
1065 if (surface->overlay_dest)
1066 return surface->surface_ops->surface_draw_overlay(surface);
1074 static BOOL surface_is_full_rect(IWineD3DSurfaceImpl *surface, const RECT *r)
1076 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
1078 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
1083 static void wined3d_surface_depth_blt_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface,
1084 const RECT *src_rect, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect)
1086 const struct wined3d_gl_info *gl_info;
1087 struct wined3d_context *context;
1088 DWORD src_mask, dst_mask;
1091 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
1092 device, src_surface, wine_dbgstr_rect(src_rect),
1093 dst_surface, wine_dbgstr_rect(dst_rect));
1095 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1096 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1098 if (src_mask != dst_mask)
1100 ERR("Incompatible formats %s and %s.\n",
1101 debug_d3dformat(src_surface->resource.format->id),
1102 debug_d3dformat(dst_surface->resource.format->id));
1108 ERR("Not a depth / stencil format: %s.\n",
1109 debug_d3dformat(src_surface->resource.format->id));
1114 if (src_mask & WINED3DFMT_FLAG_DEPTH)
1115 gl_mask |= GL_DEPTH_BUFFER_BIT;
1116 if (src_mask & WINED3DFMT_FLAG_STENCIL)
1117 gl_mask |= GL_STENCIL_BUFFER_BIT;
1119 /* Make sure the locations are up-to-date. Loading the destination
1120 * surface isn't required if the entire surface is overwritten. */
1121 surface_load_location(src_surface, SFLAG_INTEXTURE, NULL);
1122 if (!surface_is_full_rect(dst_surface, dst_rect))
1123 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
1125 context = context_acquire(device, NULL);
1126 if (!context->valid)
1128 context_release(context);
1129 WARN("Invalid context, skipping blit.\n");
1133 gl_info = context->gl_info;
1137 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, SFLAG_INTEXTURE);
1138 glReadBuffer(GL_NONE);
1139 checkGLcall("glReadBuffer()");
1140 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1142 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, SFLAG_INTEXTURE);
1143 context_set_draw_buffer(context, GL_NONE);
1144 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1146 if (gl_mask & GL_DEPTH_BUFFER_BIT)
1148 glDepthMask(GL_TRUE);
1149 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
1151 if (gl_mask & GL_STENCIL_BUFFER_BIT)
1153 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
1155 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1156 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
1159 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
1162 glDisable(GL_SCISSOR_TEST);
1163 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
1165 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
1166 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
1167 checkGLcall("glBlitFramebuffer()");
1171 if (wined3d_settings.strict_draw_ordering)
1172 wglFlush(); /* Flush to ensure ordering across contexts. */
1174 context_release(context);
1177 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
1178 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
1179 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
1181 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1184 /* Source and/or destination need to be on the GL side */
1185 if (src_pool == WINED3DPOOL_SYSTEMMEM || dst_pool == WINED3DPOOL_SYSTEMMEM)
1190 case WINED3D_BLIT_OP_COLOR_BLIT:
1191 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
1193 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
1197 case WINED3D_BLIT_OP_DEPTH_BLIT:
1198 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1200 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1208 if (!(src_format->id == dst_format->id
1209 || (is_identity_fixup(src_format->color_fixup)
1210 && is_identity_fixup(dst_format->color_fixup))))
1216 static BOOL surface_convert_depth_to_float(IWineD3DSurfaceImpl *surface, DWORD depth, float *float_depth)
1218 const struct wined3d_format *format = surface->resource.format;
1222 case WINED3DFMT_S1_UINT_D15_UNORM:
1223 *float_depth = depth / (float)0x00007fff;
1226 case WINED3DFMT_D16_UNORM:
1227 *float_depth = depth / (float)0x0000ffff;
1230 case WINED3DFMT_D24_UNORM_S8_UINT:
1231 case WINED3DFMT_X8D24_UNORM:
1232 *float_depth = depth / (float)0x00ffffff;
1235 case WINED3DFMT_D32_UNORM:
1236 *float_depth = depth / (float)0xffffffff;
1240 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1247 /* Do not call while under the GL lock. */
1248 static HRESULT wined3d_surface_depth_fill(IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
1250 const struct wined3d_resource *resource = &surface->resource;
1251 IWineD3DDeviceImpl *device = resource->device;
1252 const struct blit_shader *blitter;
1254 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
1255 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
1258 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1259 return WINED3DERR_INVALIDCALL;
1262 return blitter->depth_fill(device, surface, rect, depth);
1265 static HRESULT wined3d_surface_depth_blt(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect,
1266 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect)
1268 IWineD3DDeviceImpl *device = src_surface->resource.device;
1270 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
1271 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1272 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1273 return WINED3DERR_INVALIDCALL;
1275 wined3d_surface_depth_blt_fbo(device, src_surface, src_rect, dst_surface, dst_rect);
1277 surface_modify_ds_location(dst_surface, SFLAG_DS_OFFSCREEN,
1278 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
1279 surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
1284 /* Do not call while under the GL lock. */
1285 static HRESULT surface_blt(IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in,
1286 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in, DWORD flags,
1287 const WINEDDBLTFX *fx, WINED3DTEXTUREFILTERTYPE filter)
1289 IWineD3DDeviceImpl *device = dst_surface->resource.device;
1290 DWORD src_ds_flags, dst_ds_flags;
1292 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1293 dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
1294 flags, fx, debug_d3dtexturefiltertype(filter));
1295 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
1297 if ((dst_surface->flags & SFLAG_LOCKED) || (src_surface && (src_surface->flags & SFLAG_LOCKED)))
1299 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1300 return WINEDDERR_SURFACEBUSY;
1303 dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1305 src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1309 if (src_ds_flags || dst_ds_flags)
1311 if (flags & WINEDDBLT_DEPTHFILL)
1316 TRACE("Depth fill.\n");
1318 surface_get_rect(dst_surface, dst_rect_in, &rect);
1320 if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
1321 return WINED3DERR_INVALIDCALL;
1323 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &rect, depth)))
1328 RECT src_rect, dst_rect;
1330 /* Accessing depth / stencil surfaces is supposed to fail while in
1331 * a scene, except for fills, which seem to work. */
1332 if (device->inScene)
1334 WARN("Rejecting depth / stencil access while in scene.\n");
1335 return WINED3DERR_INVALIDCALL;
1338 if (src_ds_flags != dst_ds_flags)
1340 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1341 return WINED3DERR_INVALIDCALL;
1344 if (src_rect_in && (src_rect_in->top || src_rect_in->left
1345 || src_rect_in->bottom != src_surface->resource.height
1346 || src_rect_in->right != src_surface->resource.width))
1348 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
1349 wine_dbgstr_rect(src_rect_in));
1350 return WINED3DERR_INVALIDCALL;
1353 if (dst_rect_in && (dst_rect_in->top || dst_rect_in->left
1354 || dst_rect_in->bottom != dst_surface->resource.height
1355 || dst_rect_in->right != dst_surface->resource.width))
1357 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
1358 wine_dbgstr_rect(src_rect_in));
1359 return WINED3DERR_INVALIDCALL;
1362 if (src_surface->resource.height != dst_surface->resource.height
1363 || src_surface->resource.width != dst_surface->resource.width)
1365 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
1366 return WINED3DERR_INVALIDCALL;
1369 surface_get_rect(src_surface, src_rect_in, &src_rect);
1370 surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
1372 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, &src_rect, dst_surface, &dst_rect)))
1377 /* Special cases for render targets. */
1378 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1379 || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)))
1381 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface, dst_rect_in,
1382 src_surface, src_rect_in, flags, fx, filter)))
1386 /* For the rest call the X11 surface implementation. For render targets
1387 * this should be implemented OpenGL accelerated in BltOverride, other
1388 * blits are rather rare. */
1389 return surface_cpu_blt(dst_surface, dst_rect_in, src_surface, src_rect_in, flags, fx, filter);
1392 /* Do not call while under the GL lock. */
1393 static HRESULT surface_bltfast(IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
1394 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in, DWORD trans)
1396 IWineD3DDeviceImpl *device = dst_surface->resource.device;
1398 TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1399 dst_surface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect_in), trans);
1401 if ((dst_surface->flags & SFLAG_LOCKED) || (src_surface->flags & SFLAG_LOCKED))
1403 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1404 return WINEDDERR_SURFACEBUSY;
1407 if (device->inScene && (dst_surface == device->depth_stencil || src_surface == device->depth_stencil))
1409 WARN("Attempt to access the depth / stencil surface while in a scene.\n");
1410 return WINED3DERR_INVALIDCALL;
1413 /* Special cases for RenderTargets */
1414 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1415 || (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
1418 RECT src_rect, dst_rect;
1421 surface_get_rect(src_surface, src_rect_in, &src_rect);
1423 dst_rect.left = dst_x;
1424 dst_rect.top = dst_y;
1425 dst_rect.right = dst_x + src_rect.right - src_rect.left;
1426 dst_rect.bottom = dst_y + src_rect.bottom - src_rect.top;
1428 /* Convert BltFast flags into Blt ones because BltOverride is called
1429 * from Blt as well. */
1430 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
1431 flags |= WINEDDBLT_KEYSRC;
1432 if (trans & WINEDDBLTFAST_DESTCOLORKEY)
1433 flags |= WINEDDBLT_KEYDEST;
1434 if (trans & WINEDDBLTFAST_WAIT)
1435 flags |= WINEDDBLT_WAIT;
1436 if (trans & WINEDDBLTFAST_DONOTWAIT)
1437 flags |= WINEDDBLT_DONOTWAIT;
1439 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface,
1440 &dst_rect, src_surface, &src_rect, flags, NULL, WINED3DTEXF_POINT)))
1444 return surface_cpu_bltfast(dst_surface, dst_x, dst_y, src_surface, src_rect_in, trans);
1447 static HRESULT surface_set_mem(IWineD3DSurfaceImpl *surface, void *mem)
1449 TRACE("surface %p, mem %p.\n", surface, mem);
1451 if (mem && mem != surface->resource.allocatedMemory)
1453 void *release = NULL;
1455 /* Do I have to copy the old surface content? */
1456 if (surface->flags & SFLAG_DIBSECTION)
1458 SelectObject(surface->hDC, surface->dib.holdbitmap);
1459 DeleteDC(surface->hDC);
1460 /* Release the DIB section. */
1461 DeleteObject(surface->dib.DIBsection);
1462 surface->dib.bitmap_data = NULL;
1463 surface->resource.allocatedMemory = NULL;
1464 surface->hDC = NULL;
1465 surface->flags &= ~SFLAG_DIBSECTION;
1467 else if (!(surface->flags & SFLAG_USERPTR))
1469 release = surface->resource.heapMemory;
1470 surface->resource.heapMemory = NULL;
1472 surface->resource.allocatedMemory = mem;
1473 surface->flags |= SFLAG_USERPTR;
1475 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
1476 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1478 /* For client textures OpenGL has to be notified. */
1479 if (surface->flags & SFLAG_CLIENT)
1480 surface_release_client_storage(surface);
1482 /* Now free the old memory if any. */
1483 HeapFree(GetProcessHeap(), 0, release);
1485 else if (surface->flags & SFLAG_USERPTR)
1487 /* Map and GetDC will re-create the dib section and allocated memory. */
1488 surface->resource.allocatedMemory = NULL;
1489 /* HeapMemory should be NULL already. */
1490 if (surface->resource.heapMemory)
1491 ERR("User pointer surface has heap memory allocated.\n");
1492 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
1494 if (surface->flags & SFLAG_CLIENT)
1495 surface_release_client_storage(surface);
1497 surface_prepare_system_memory(surface);
1498 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1504 /* Context activation is done by the caller. */
1505 static void surface_remove_pbo(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
1507 if (!surface->resource.heapMemory)
1509 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
1510 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
1511 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1515 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
1516 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1517 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
1518 surface->resource.size, surface->resource.allocatedMemory));
1519 checkGLcall("glGetBufferSubDataARB");
1520 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
1521 checkGLcall("glDeleteBuffersARB");
1525 surface->flags &= ~SFLAG_PBO;
1528 /* Do not call while under the GL lock. */
1529 static void surface_unload(struct wined3d_resource *resource)
1531 IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
1532 IWineD3DDeviceImpl *device = resource->device;
1533 const struct wined3d_gl_info *gl_info;
1534 renderbuffer_entry_t *entry, *entry2;
1535 struct wined3d_context *context;
1537 TRACE("surface %p.\n", surface);
1539 if (resource->pool == WINED3DPOOL_DEFAULT)
1541 /* Default pool resources are supposed to be destroyed before Reset is called.
1542 * Implicit resources stay however. So this means we have an implicit render target
1543 * or depth stencil. The content may be destroyed, but we still have to tear down
1544 * opengl resources, so we cannot leave early.
1546 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1547 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1548 * or the depth stencil into an FBO the texture or render buffer will be removed
1549 * and all flags get lost
1551 surface_init_sysmem(surface);
1555 /* Load the surface into system memory */
1556 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1557 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
1559 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
1560 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
1561 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1563 context = context_acquire(device, NULL);
1564 gl_info = context->gl_info;
1566 /* Destroy PBOs, but load them into real sysmem before */
1567 if (surface->flags & SFLAG_PBO)
1568 surface_remove_pbo(surface, gl_info);
1570 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1571 * all application-created targets the application has to release the surface
1572 * before calling _Reset
1574 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, renderbuffer_entry_t, entry)
1577 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1579 list_remove(&entry->entry);
1580 HeapFree(GetProcessHeap(), 0, entry);
1582 list_init(&surface->renderbuffers);
1583 surface->current_renderbuffer = NULL;
1585 /* If we're in a texture, the texture name belongs to the texture.
1586 * Otherwise, destroy it. */
1587 if (surface->container.type != WINED3D_CONTAINER_TEXTURE)
1590 glDeleteTextures(1, &surface->texture_name);
1591 surface->texture_name = 0;
1592 glDeleteTextures(1, &surface->texture_name_srgb);
1593 surface->texture_name_srgb = 0;
1597 context_release(context);
1599 resource_unload(resource);
1602 static const struct wined3d_resource_ops surface_resource_ops =
1607 static const struct wined3d_surface_ops surface_ops =
1609 surface_private_setup,
1611 surface_realize_palette,
1612 surface_draw_overlay,
1623 /*****************************************************************************
1624 * Initializes the GDI surface, aka creates the DIB section we render to
1625 * The DIB section creation is done by calling GetDC, which will create the
1626 * section and releasing the dc to allow the app to use it. The dib section
1627 * will stay until the surface is released
1629 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1630 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1631 * avoid confusion in the shared surface code.
1634 * WINED3D_OK on success
1635 * The return values of called methods on failure
1637 *****************************************************************************/
1638 static HRESULT gdi_surface_private_setup(IWineD3DSurfaceImpl *surface)
1642 TRACE("surface %p.\n", surface);
1644 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
1646 ERR("Overlays not yet supported by GDI surfaces.\n");
1647 return WINED3DERR_INVALIDCALL;
1650 /* Sysmem textures have memory already allocated - release it,
1651 * this avoids an unnecessary memcpy. */
1652 hr = surface_create_dib_section(surface);
1655 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
1656 surface->resource.heapMemory = NULL;
1657 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1660 /* We don't mind the nonpow2 stuff in GDI. */
1661 surface->pow2Width = surface->resource.width;
1662 surface->pow2Height = surface->resource.height;
1667 static void surface_gdi_cleanup(IWineD3DSurfaceImpl *surface)
1669 TRACE("surface %p.\n", surface);
1671 if (surface->flags & SFLAG_DIBSECTION)
1673 /* Release the DC. */
1674 SelectObject(surface->hDC, surface->dib.holdbitmap);
1675 DeleteDC(surface->hDC);
1676 /* Release the DIB section. */
1677 DeleteObject(surface->dib.DIBsection);
1678 surface->dib.bitmap_data = NULL;
1679 surface->resource.allocatedMemory = NULL;
1682 if (surface->flags & SFLAG_USERPTR)
1683 IWineD3DSurface_SetMem((IWineD3DSurface *)surface, NULL);
1684 if (surface->overlay_dest)
1685 list_remove(&surface->overlay_entry);
1687 HeapFree(GetProcessHeap(), 0, surface->palette9);
1689 resource_cleanup(&surface->resource);
1692 static void gdi_surface_realize_palette(IWineD3DSurfaceImpl *surface)
1694 struct wined3d_palette *palette = surface->palette;
1696 TRACE("surface %p.\n", surface);
1698 if (!palette) return;
1700 if (surface->flags & SFLAG_DIBSECTION)
1705 TRACE("Updating the DC's palette.\n");
1707 for (i = 0; i < 256; ++i)
1709 col[i].rgbRed = palette->palents[i].peRed;
1710 col[i].rgbGreen = palette->palents[i].peGreen;
1711 col[i].rgbBlue = palette->palents[i].peBlue;
1712 col[i].rgbReserved = 0;
1714 SetDIBColorTable(surface->hDC, 0, 256, col);
1717 /* Update the image because of the palette change. Some games like e.g.
1718 * Red Alert call SetEntries a lot to implement fading. */
1719 /* Tell the swapchain to update the screen. */
1720 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1722 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
1723 if (surface == swapchain->front_buffer)
1725 x11_copy_to_screen(swapchain, NULL);
1730 static HRESULT gdi_surface_draw_overlay(IWineD3DSurfaceImpl *surface)
1732 FIXME("GDI surfaces can't draw overlays yet.\n");
1736 static void gdi_surface_preload(IWineD3DSurfaceImpl *surface)
1738 TRACE("surface %p.\n", surface);
1740 ERR("Preloading GDI surfaces is not supported.\n");
1743 static void gdi_surface_map(IWineD3DSurfaceImpl *surface, const RECT *rect, DWORD flags)
1745 TRACE("surface %p, rect %s, flags %#x.\n",
1746 surface, wine_dbgstr_rect(rect), flags);
1748 if (!surface->resource.allocatedMemory)
1750 /* This happens on gdi surfaces if the application set a user pointer
1751 * and resets it. Recreate the DIB section. */
1752 surface_create_dib_section(surface);
1753 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1757 static void gdi_surface_unmap(IWineD3DSurfaceImpl *surface)
1759 TRACE("surface %p.\n", surface);
1761 /* Tell the swapchain to update the screen. */
1762 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1764 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
1765 if (surface == swapchain->front_buffer)
1767 x11_copy_to_screen(swapchain, &surface->lockedRect);
1771 memset(&surface->lockedRect, 0, sizeof(RECT));
1774 static HRESULT gdi_surface_getdc(IWineD3DSurfaceImpl *surface)
1776 WINED3DLOCKED_RECT lock;
1779 TRACE("surface %p.\n", surface);
1781 /* Should have a DIB section already. */
1782 if (!(surface->flags & SFLAG_DIBSECTION))
1784 WARN("DC not supported on this surface\n");
1785 return WINED3DERR_INVALIDCALL;
1788 /* Map the surface. */
1789 hr = IWineD3DSurface_Map((IWineD3DSurface *)surface, &lock, NULL, 0);
1791 ERR("Map failed, hr %#x.\n", hr);
1796 static HRESULT gdi_surface_flip(IWineD3DSurfaceImpl *surface, IWineD3DSurfaceImpl *override)
1798 TRACE("surface %p, override %p.\n", surface, override);
1803 static HRESULT gdi_surface_blt(IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect,
1804 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD flags,
1805 const WINEDDBLTFX *fx, WINED3DTEXTUREFILTERTYPE filter)
1807 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1808 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
1809 flags, fx, debug_d3dtexturefiltertype(filter));
1811 return surface_cpu_blt(dst_surface, dst_rect, src_surface, src_rect, flags, fx, filter);
1814 static HRESULT gdi_surface_bltfast(IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
1815 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD trans)
1817 TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
1818 dst_surface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect), trans);
1820 return surface_cpu_bltfast(dst_surface, dst_x, dst_y, src_surface, src_rect, trans);
1823 static HRESULT gdi_surface_set_mem(IWineD3DSurfaceImpl *surface, void *mem)
1825 TRACE("surface %p, mem %p.\n", surface, mem);
1827 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
1828 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1830 ERR("Not supported on render targets.\n");
1831 return WINED3DERR_INVALIDCALL;
1834 if (mem && mem != surface->resource.allocatedMemory)
1836 void *release = NULL;
1838 /* Do I have to copy the old surface content? */
1839 if (surface->flags & SFLAG_DIBSECTION)
1841 SelectObject(surface->hDC, surface->dib.holdbitmap);
1842 DeleteDC(surface->hDC);
1843 /* Release the DIB section. */
1844 DeleteObject(surface->dib.DIBsection);
1845 surface->dib.bitmap_data = NULL;
1846 surface->resource.allocatedMemory = NULL;
1847 surface->hDC = NULL;
1848 surface->flags &= ~SFLAG_DIBSECTION;
1850 else if (!(surface->flags & SFLAG_USERPTR))
1852 release = surface->resource.allocatedMemory;
1854 surface->resource.allocatedMemory = mem;
1855 surface->flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
1857 /* Now free the old memory, if any. */
1858 HeapFree(GetProcessHeap(), 0, release);
1860 else if (surface->flags & SFLAG_USERPTR)
1862 /* Map() and GetDC() will re-create the dib section and allocated memory. */
1863 surface->resource.allocatedMemory = NULL;
1864 surface->flags &= ~SFLAG_USERPTR;
1870 static const struct wined3d_surface_ops gdi_surface_ops =
1872 gdi_surface_private_setup,
1873 surface_gdi_cleanup,
1874 gdi_surface_realize_palette,
1875 gdi_surface_draw_overlay,
1876 gdi_surface_preload,
1882 gdi_surface_bltfast,
1883 gdi_surface_set_mem,
1886 void surface_set_texture_name(IWineD3DSurfaceImpl *surface, GLuint new_name, BOOL srgb)
1891 TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
1895 name = &surface->texture_name_srgb;
1896 flag = SFLAG_INSRGBTEX;
1900 name = &surface->texture_name;
1901 flag = SFLAG_INTEXTURE;
1904 if (!*name && new_name)
1906 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
1907 * surface has no texture name yet. See if we can get rid of this. */
1908 if (surface->flags & flag)
1909 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
1910 surface_modify_location(surface, flag, FALSE);
1914 surface_force_reload(surface);
1917 void surface_set_texture_target(IWineD3DSurfaceImpl *surface, GLenum target)
1919 TRACE("surface %p, target %#x.\n", surface, target);
1921 if (surface->texture_target != target)
1923 if (target == GL_TEXTURE_RECTANGLE_ARB)
1925 surface->flags &= ~SFLAG_NORMCOORD;
1927 else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
1929 surface->flags |= SFLAG_NORMCOORD;
1932 surface->texture_target = target;
1933 surface_force_reload(surface);
1936 /* Context activation is done by the caller. */
1937 void surface_bind(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
1939 TRACE("surface %p, gl_info %p, srgb %#x.\n", surface, gl_info, srgb);
1941 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
1943 struct wined3d_texture *texture = surface->container.u.texture;
1945 TRACE("Passing to container (%p).\n", texture);
1946 texture->texture_ops->texture_bind(texture, gl_info, srgb);
1950 if (surface->texture_level)
1952 ERR("Standalone surface %p is non-zero texture level %u.\n",
1953 surface, surface->texture_level);
1957 ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
1961 if (!surface->texture_name)
1963 glGenTextures(1, &surface->texture_name);
1964 checkGLcall("glGenTextures");
1966 TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
1968 glBindTexture(surface->texture_target, surface->texture_name);
1969 checkGLcall("glBindTexture");
1970 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1971 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1972 glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
1973 glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1974 glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1975 checkGLcall("glTexParameteri");
1979 glBindTexture(surface->texture_target, surface->texture_name);
1980 checkGLcall("glBindTexture");
1987 /* This function checks if the primary render target uses the 8bit paletted format. */
1988 static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device)
1990 if (device->render_targets && device->render_targets[0])
1992 IWineD3DSurfaceImpl *render_target = device->render_targets[0];
1993 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
1994 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
2000 /* This call just downloads data, the caller is responsible for binding the
2001 * correct texture. */
2002 /* Context activation is done by the caller. */
2003 static void surface_download_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
2005 const struct wined3d_format *format = This->resource.format;
2007 /* Only support read back of converted P8 surfaces */
2008 if (This->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
2010 FIXME("Readback conversion not supported for format %s.\n", debug_d3dformat(format->id));
2016 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2018 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2019 This, This->texture_level, format->glFormat, format->glType,
2020 This->resource.allocatedMemory);
2022 if (This->flags & SFLAG_PBO)
2024 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
2025 checkGLcall("glBindBufferARB");
2026 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target, This->texture_level, NULL));
2027 checkGLcall("glGetCompressedTexImageARB");
2028 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2029 checkGLcall("glBindBufferARB");
2033 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target,
2034 This->texture_level, This->resource.allocatedMemory));
2035 checkGLcall("glGetCompressedTexImageARB");
2041 GLenum gl_format = format->glFormat;
2042 GLenum gl_type = format->glType;
2046 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
2047 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(This->resource.device))
2049 gl_format = GL_ALPHA;
2050 gl_type = GL_UNSIGNED_BYTE;
2053 if (This->flags & SFLAG_NONPOW2)
2055 unsigned char alignment = This->resource.device->surface_alignment;
2056 src_pitch = format->byte_count * This->pow2Width;
2057 dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
2058 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
2059 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
2061 mem = This->resource.allocatedMemory;
2064 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2065 This, This->texture_level, gl_format, gl_type, mem);
2067 if (This->flags & SFLAG_PBO)
2069 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
2070 checkGLcall("glBindBufferARB");
2072 glGetTexImage(This->texture_target, This->texture_level, gl_format, gl_type, NULL);
2073 checkGLcall("glGetTexImage");
2075 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2076 checkGLcall("glBindBufferARB");
2078 glGetTexImage(This->texture_target, This->texture_level, gl_format, gl_type, mem);
2079 checkGLcall("glGetTexImage");
2083 if (This->flags & SFLAG_NONPOW2)
2085 const BYTE *src_data;
2089 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2090 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2091 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2093 * We're doing this...
2095 * instead of boxing the texture :
2096 * |<-texture width ->| -->pow2width| /\
2097 * |111111111111111111| | |
2098 * |222 Texture 222222| boxed empty | texture height
2099 * |3333 Data 33333333| | |
2100 * |444444444444444444| | \/
2101 * ----------------------------------- |
2102 * | boxed empty | boxed empty | pow2height
2104 * -----------------------------------
2107 * we're repacking the data to the expected texture width
2109 * |<-texture width ->| -->pow2width| /\
2110 * |111111111111111111222222222222222| |
2111 * |222333333333333333333444444444444| texture height
2115 * | empty | pow2height
2117 * -----------------------------------
2121 * |<-texture width ->| /\
2122 * |111111111111111111|
2123 * |222222222222222222|texture height
2124 * |333333333333333333|
2125 * |444444444444444444| \/
2126 * --------------------
2128 * this also means that any references to allocatedMemory should work with the data as if were a
2129 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2131 * internally the texture is still stored in a boxed format so any references to textureName will
2132 * get a boxed texture with width pow2width and not a texture of width resource.width.
2134 * Performance should not be an issue, because applications normally do not lock the surfaces when
2135 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2136 * and doesn't have to be re-read.
2139 dst_data = This->resource.allocatedMemory;
2140 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
2141 for (y = 1; y < This->resource.height; ++y)
2143 /* skip the first row */
2144 src_data += src_pitch;
2145 dst_data += dst_pitch;
2146 memcpy(dst_data, src_data, dst_pitch);
2149 HeapFree(GetProcessHeap(), 0, mem);
2153 /* Surface has now been downloaded */
2154 This->flags |= SFLAG_INSYSMEM;
2157 /* This call just uploads data, the caller is responsible for binding the
2158 * correct texture. */
2159 /* Context activation is done by the caller. */
2160 static void surface_upload_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
2161 const struct wined3d_format *format, BOOL srgb, const GLvoid *data)
2163 GLsizei width = This->resource.width;
2164 GLsizei height = This->resource.height;
2169 internal = format->glGammaInternal;
2171 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(This))
2173 internal = format->rtInternal;
2177 internal = format->glInternal;
2180 TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
2181 This, internal, width, height, format->glFormat, format->glType, data);
2182 TRACE("target %#x, level %u, resource size %u.\n",
2183 This->texture_target, This->texture_level, This->resource.size);
2185 if (format->heightscale != 1.0f && format->heightscale != 0.0f) height *= format->heightscale;
2189 if (This->flags & SFLAG_PBO)
2191 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
2192 checkGLcall("glBindBufferARB");
2194 TRACE("(%p) pbo: %#x, data: %p.\n", This, This->pbo, data);
2198 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2200 TRACE("Calling glCompressedTexSubImage2DARB.\n");
2202 GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
2203 0, 0, width, height, internal, This->resource.size, data));
2204 checkGLcall("glCompressedTexSubImage2DARB");
2208 TRACE("Calling glTexSubImage2D.\n");
2210 glTexSubImage2D(This->texture_target, This->texture_level,
2211 0, 0, width, height, format->glFormat, format->glType, data);
2212 checkGLcall("glTexSubImage2D");
2215 if (This->flags & SFLAG_PBO)
2217 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2218 checkGLcall("glBindBufferARB");
2223 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2225 IWineD3DDeviceImpl *device = This->resource.device;
2228 for (i = 0; i < device->context_count; ++i)
2230 context_surface_update(device->contexts[i], This);
2235 /* This call just allocates the texture, the caller is responsible for binding
2236 * the correct texture. */
2237 /* Context activation is done by the caller. */
2238 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
2239 const struct wined3d_format *format, BOOL srgb)
2241 BOOL enable_client_storage = FALSE;
2242 GLsizei width = This->pow2Width;
2243 GLsizei height = This->pow2Height;
2244 const BYTE *mem = NULL;
2249 internal = format->glGammaInternal;
2251 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(This))
2253 internal = format->rtInternal;
2257 internal = format->glInternal;
2260 if (format->heightscale != 1.0f && format->heightscale != 0.0f) height *= format->heightscale;
2262 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",
2263 This, This->texture_target, This->texture_level, debug_d3dformat(format->id),
2264 internal, width, height, format->glFormat, format->glType);
2268 if (gl_info->supported[APPLE_CLIENT_STORAGE])
2270 if (This->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2271 || !This->resource.allocatedMemory)
2273 /* In some cases we want to disable client storage.
2274 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2275 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2276 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2277 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2279 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2280 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2281 This->flags &= ~SFLAG_CLIENT;
2282 enable_client_storage = TRUE;
2286 This->flags |= SFLAG_CLIENT;
2288 /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
2289 * it might point into a pbo. Instead use heapMemory, but get the alignment right.
2291 mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2295 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
2297 GL_EXTCALL(glCompressedTexImage2DARB(This->texture_target, This->texture_level,
2298 internal, width, height, 0, This->resource.size, mem));
2299 checkGLcall("glCompressedTexImage2DARB");
2303 glTexImage2D(This->texture_target, This->texture_level,
2304 internal, width, height, 0, format->glFormat, format->glType, mem);
2305 checkGLcall("glTexImage2D");
2308 if(enable_client_storage) {
2309 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2310 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2315 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2316 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2317 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2318 /* GL locking is done by the caller */
2319 void surface_set_compatible_renderbuffer(IWineD3DSurfaceImpl *surface, IWineD3DSurfaceImpl *rt)
2321 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
2322 renderbuffer_entry_t *entry;
2323 GLuint renderbuffer = 0;
2324 unsigned int src_width, src_height;
2325 unsigned int width, height;
2327 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
2329 width = rt->pow2Width;
2330 height = rt->pow2Height;
2334 width = surface->pow2Width;
2335 height = surface->pow2Height;
2338 src_width = surface->pow2Width;
2339 src_height = surface->pow2Height;
2341 /* A depth stencil smaller than the render target is not valid */
2342 if (width > src_width || height > src_height) return;
2344 /* Remove any renderbuffer set if the sizes match */
2345 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
2346 || (width == src_width && height == src_height))
2348 surface->current_renderbuffer = NULL;
2352 /* Look if we've already got a renderbuffer of the correct dimensions */
2353 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, renderbuffer_entry_t, entry)
2355 if (entry->width == width && entry->height == height)
2357 renderbuffer = entry->id;
2358 surface->current_renderbuffer = entry;
2365 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
2366 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
2367 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
2368 surface->resource.format->glInternal, width, height);
2370 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
2371 entry->width = width;
2372 entry->height = height;
2373 entry->id = renderbuffer;
2374 list_add_head(&surface->renderbuffers, &entry->entry);
2376 surface->current_renderbuffer = entry;
2379 checkGLcall("set_compatible_renderbuffer");
2382 GLenum surface_get_gl_buffer(IWineD3DSurfaceImpl *surface)
2384 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2386 TRACE("surface %p.\n", surface);
2388 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
2390 ERR("Surface %p is not on a swapchain.\n", surface);
2394 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
2396 if (swapchain->render_to_fbo)
2398 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2399 return GL_COLOR_ATTACHMENT0;
2401 TRACE("Returning GL_BACK\n");
2404 else if (surface == swapchain->front_buffer)
2406 TRACE("Returning GL_FRONT\n");
2410 FIXME("Higher back buffer, returning GL_BACK\n");
2414 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2415 void surface_add_dirty_rect(IWineD3DSurfaceImpl *surface, const WINED3DBOX *dirty_rect)
2417 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
2419 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
2420 /* No partial locking for textures yet. */
2421 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2423 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2426 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->Left);
2427 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->Top);
2428 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->Right);
2429 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->Bottom);
2433 surface->dirtyRect.left = 0;
2434 surface->dirtyRect.top = 0;
2435 surface->dirtyRect.right = surface->resource.width;
2436 surface->dirtyRect.bottom = surface->resource.height;
2439 /* if the container is a texture then mark it dirty. */
2440 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
2442 TRACE("Passing to container.\n");
2443 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
2447 static BOOL surface_convert_color_to_float(IWineD3DSurfaceImpl *surface, DWORD color, WINED3DCOLORVALUE *float_color)
2449 const struct wined3d_format *format = surface->resource.format;
2450 IWineD3DDeviceImpl *device = surface->resource.device;
2454 case WINED3DFMT_P8_UINT:
2455 if (surface->palette)
2457 float_color->r = surface->palette->palents[color].peRed / 255.0f;
2458 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
2459 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
2463 float_color->r = 0.0f;
2464 float_color->g = 0.0f;
2465 float_color->b = 0.0f;
2467 float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
2470 case WINED3DFMT_B5G6R5_UNORM:
2471 float_color->r = ((color >> 11) & 0x1f) / 31.0f;
2472 float_color->g = ((color >> 5) & 0x3f) / 63.0f;
2473 float_color->b = (color & 0x1f) / 31.0f;
2474 float_color->a = 1.0f;
2477 case WINED3DFMT_B8G8R8_UNORM:
2478 case WINED3DFMT_B8G8R8X8_UNORM:
2479 float_color->r = D3DCOLOR_R(color);
2480 float_color->g = D3DCOLOR_G(color);
2481 float_color->b = D3DCOLOR_B(color);
2482 float_color->a = 1.0f;
2485 case WINED3DFMT_B8G8R8A8_UNORM:
2486 float_color->r = D3DCOLOR_R(color);
2487 float_color->g = D3DCOLOR_G(color);
2488 float_color->b = D3DCOLOR_B(color);
2489 float_color->a = D3DCOLOR_A(color);
2493 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
2500 HRESULT surface_load(IWineD3DSurfaceImpl *surface, BOOL srgb)
2502 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2504 TRACE("surface %p, srgb %#x.\n", surface, srgb);
2506 if (surface->resource.pool == WINED3DPOOL_SCRATCH)
2508 ERR("Not supported on scratch surfaces.\n");
2509 return WINED3DERR_INVALIDCALL;
2512 if (!(surface->flags & flag))
2514 TRACE("Reloading because surface is dirty\n");
2516 /* Reload if either the texture and sysmem have different ideas about the
2517 * color key, or the actual key values changed. */
2518 else if (!(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT)
2519 || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
2520 && (surface->glCKey.dwColorSpaceLowValue != surface->SrcBltCKey.dwColorSpaceLowValue
2521 || surface->glCKey.dwColorSpaceHighValue != surface->SrcBltCKey.dwColorSpaceHighValue)))
2523 TRACE("Reloading because of color keying\n");
2524 /* To perform the color key conversion we need a sysmem copy of
2525 * the surface. Make sure we have it. */
2527 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2528 /* Make sure the texture is reloaded because of the color key change,
2529 * this kills performance though :( */
2530 /* TODO: This is not necessarily needed with hw palettized texture support. */
2531 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2535 TRACE("surface is already in texture\n");
2539 /* No partial locking for textures yet. */
2540 surface_load_location(surface, flag, NULL);
2541 surface_evict_sysmem(surface);
2546 /* See also float_16_to_32() in wined3d_private.h */
2547 static inline unsigned short float_32_to_16(const float *in)
2550 float tmp = fabs(*in);
2551 unsigned int mantissa;
2554 /* Deal with special numbers */
2560 return (*in < 0.0f ? 0xfc00 : 0x7c00);
2562 if (tmp < powf(2, 10))
2568 } while (tmp < powf(2, 10));
2570 else if (tmp >= powf(2, 11))
2576 } while (tmp >= powf(2, 11));
2579 mantissa = (unsigned int)tmp;
2580 if (tmp - mantissa >= 0.5f)
2581 ++mantissa; /* Round to nearest, away from zero. */
2583 exp += 10; /* Normalize the mantissa. */
2584 exp += 15; /* Exponent is encoded with excess 15. */
2586 if (exp > 30) /* too big */
2588 ret = 0x7c00; /* INF */
2592 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2595 mantissa = mantissa >> 1;
2598 ret = mantissa & 0x3ff;
2602 ret = (exp << 10) | (mantissa & 0x3ff);
2605 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
2609 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface,
2610 REFIID riid, void **object)
2612 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
2614 if (IsEqualGUID(riid, &IID_IWineD3DSurface)
2615 || IsEqualGUID(riid, &IID_IUnknown))
2617 IUnknown_AddRef(iface);
2622 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
2625 return E_NOINTERFACE;
2628 static ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface)
2630 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2633 TRACE("Surface %p, container %p of type %#x.\n",
2634 surface, surface->container.u.base, surface->container.type);
2636 switch (surface->container.type)
2638 case WINED3D_CONTAINER_TEXTURE:
2639 return wined3d_texture_incref(surface->container.u.texture);
2641 case WINED3D_CONTAINER_SWAPCHAIN:
2642 return wined3d_swapchain_incref(surface->container.u.swapchain);
2645 ERR("Unhandled container type %#x.\n", surface->container.type);
2646 case WINED3D_CONTAINER_NONE:
2650 refcount = InterlockedIncrement(&surface->resource.ref);
2651 TRACE("%p increasing refcount to %u.\n", surface, refcount);
2656 /* Do not call while under the GL lock. */
2657 static ULONG WINAPI IWineD3DBaseSurfaceImpl_Release(IWineD3DSurface *iface)
2659 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2662 TRACE("Surface %p, container %p of type %#x.\n",
2663 surface, surface->container.u.base, surface->container.type);
2665 switch (surface->container.type)
2667 case WINED3D_CONTAINER_TEXTURE:
2668 return wined3d_texture_decref(surface->container.u.texture);
2670 case WINED3D_CONTAINER_SWAPCHAIN:
2671 return wined3d_swapchain_decref(surface->container.u.swapchain);
2674 ERR("Unhandled container type %#x.\n", surface->container.type);
2675 case WINED3D_CONTAINER_NONE:
2679 refcount = InterlockedDecrement(&surface->resource.ref);
2680 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
2684 surface_cleanup(surface);
2685 surface->surface_ops->surface_cleanup(surface);
2686 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
2688 TRACE("Destroyed surface %p.\n", surface);
2689 HeapFree(GetProcessHeap(), 0, surface);
2695 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface,
2696 REFGUID riid, const void *data, DWORD data_size, DWORD flags)
2698 return resource_set_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, riid, data, data_size, flags);
2701 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface,
2702 REFGUID guid, void *data, DWORD *data_size)
2704 return resource_get_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, guid, data, data_size);
2707 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
2709 return resource_free_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, refguid);
2712 static DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
2714 return resource_set_priority(&((IWineD3DSurfaceImpl *)iface)->resource, priority);
2717 static DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
2719 return resource_get_priority(&((IWineD3DSurfaceImpl *)iface)->resource);
2722 static void WINAPI IWineD3DBaseSurfaceImpl_PreLoad(IWineD3DSurface *iface)
2724 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2726 TRACE("iface %p.\n", iface);
2728 surface->surface_ops->surface_preload(surface);
2731 static void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
2733 TRACE("iface %p.\n", iface);
2735 return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
2738 static struct wined3d_resource * WINAPI IWineD3DBaseSurfaceImpl_GetResource(IWineD3DSurface *iface)
2740 TRACE("iface %p.\n", iface);
2742 return &((IWineD3DSurfaceImpl *)iface)->resource;
2745 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
2747 TRACE("iface %p, flags %#x.\n", iface, flags);
2751 case WINEDDGBS_CANBLT:
2752 case WINEDDGBS_ISBLTDONE:
2756 return WINED3DERR_INVALIDCALL;
2760 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
2762 /* XXX: DDERR_INVALIDSURFACETYPE */
2764 TRACE("iface %p, flags %#x.\n", iface, flags);
2768 case WINEDDGFS_CANFLIP:
2769 case WINEDDGFS_ISFLIPDONE:
2773 return WINED3DERR_INVALIDCALL;
2777 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface)
2779 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2781 TRACE("iface %p.\n", iface);
2783 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2784 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
2787 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface)
2789 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2791 TRACE("iface %p.\n", iface);
2793 /* So far we don't lose anything :) */
2794 surface->flags &= ~SFLAG_LOST;
2798 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
2800 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2802 TRACE("iface %p, palette %p.\n", iface, palette);
2804 if (surface->palette == palette)
2806 TRACE("Nop palette change.\n");
2810 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
2811 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
2813 surface->palette = palette;
2817 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
2818 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
2820 surface->surface_ops->surface_realize_palette(surface);
2826 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface,
2827 DWORD flags, const WINEDDCOLORKEY *color_key)
2829 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2831 TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, color_key);
2833 if (flags & WINEDDCKEY_COLORSPACE)
2835 FIXME(" colorkey value not supported (%08x) !\n", flags);
2836 return WINED3DERR_INVALIDCALL;
2839 /* Dirtify the surface, but only if a key was changed. */
2842 switch (flags & ~WINEDDCKEY_COLORSPACE)
2844 case WINEDDCKEY_DESTBLT:
2845 surface->DestBltCKey = *color_key;
2846 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
2849 case WINEDDCKEY_DESTOVERLAY:
2850 surface->DestOverlayCKey = *color_key;
2851 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
2854 case WINEDDCKEY_SRCOVERLAY:
2855 surface->SrcOverlayCKey = *color_key;
2856 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
2859 case WINEDDCKEY_SRCBLT:
2860 surface->SrcBltCKey = *color_key;
2861 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
2867 switch (flags & ~WINEDDCKEY_COLORSPACE)
2869 case WINEDDCKEY_DESTBLT:
2870 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
2873 case WINEDDCKEY_DESTOVERLAY:
2874 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
2877 case WINEDDCKEY_SRCOVERLAY:
2878 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
2881 case WINEDDCKEY_SRCBLT:
2882 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
2890 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
2892 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) iface;
2894 TRACE("iface %p, palette %p.\n", iface, palette);
2896 *palette = surface->palette;
2901 static DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
2903 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2904 const struct wined3d_format *format = surface->resource.format;
2907 TRACE("iface %p.\n", iface);
2909 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
2911 /* Since compressed formats are block based, pitch means the amount of
2912 * bytes to the next row of block rather than the next row of pixels. */
2913 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
2914 pitch = row_block_count * format->block_byte_count;
2918 unsigned char alignment = surface->resource.device->surface_alignment;
2919 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
2920 pitch = (pitch + alignment - 1) & ~(alignment - 1);
2923 TRACE("Returning %u.\n", pitch);
2928 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetMem(IWineD3DSurface *iface, void *mem)
2930 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2932 TRACE("iface %p, mem %p.\n", iface, mem);
2934 if (surface->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
2936 WARN("Surface is locked or the DC is in use.\n");
2937 return WINED3DERR_INVALIDCALL;
2940 return surface->surface_ops->surface_set_mem(surface, mem);
2943 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG x, LONG y)
2945 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2948 TRACE("iface %p, x %d, y %d.\n", iface, x, y);
2950 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2952 WARN("Not an overlay surface.\n");
2953 return WINEDDERR_NOTAOVERLAYSURFACE;
2956 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
2957 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
2958 surface->overlay_destrect.left = x;
2959 surface->overlay_destrect.top = y;
2960 surface->overlay_destrect.right = x + w;
2961 surface->overlay_destrect.bottom = y + h;
2963 surface->surface_ops->surface_draw_overlay(surface);
2968 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *x, LONG *y)
2970 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2972 TRACE("iface %p, x %p, y %p.\n", iface, x, y);
2974 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2976 TRACE("Not an overlay surface.\n");
2977 return WINEDDERR_NOTAOVERLAYSURFACE;
2980 if (!surface->overlay_dest)
2982 TRACE("Overlay not visible.\n");
2985 return WINEDDERR_OVERLAYNOTVISIBLE;
2988 *x = surface->overlay_destrect.left;
2989 *y = surface->overlay_destrect.top;
2991 TRACE("Returning position %d, %d.\n", *x, *y);
2996 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface,
2997 DWORD flags, IWineD3DSurface *ref)
2999 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3001 FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, ref);
3003 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3005 TRACE("Not an overlay surface.\n");
3006 return WINEDDERR_NOTAOVERLAYSURFACE;
3012 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *src_rect,
3013 IWineD3DSurface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3015 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3016 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *)dst_surface;
3018 TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3019 iface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3021 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3023 WARN("Not an overlay surface.\n");
3024 return WINEDDERR_NOTAOVERLAYSURFACE;
3026 else if (!dst_surface)
3028 WARN("Dest surface is NULL.\n");
3029 return WINED3DERR_INVALIDCALL;
3034 surface->overlay_srcrect = *src_rect;
3038 surface->overlay_srcrect.left = 0;
3039 surface->overlay_srcrect.top = 0;
3040 surface->overlay_srcrect.right = surface->resource.width;
3041 surface->overlay_srcrect.bottom = surface->resource.height;
3046 surface->overlay_destrect = *dst_rect;
3050 surface->overlay_destrect.left = 0;
3051 surface->overlay_destrect.top = 0;
3052 surface->overlay_destrect.right = Dst ? Dst->resource.width : 0;
3053 surface->overlay_destrect.bottom = Dst ? Dst->resource.height : 0;
3056 if (surface->overlay_dest && (surface->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
3058 list_remove(&surface->overlay_entry);
3061 if (flags & WINEDDOVER_SHOW)
3063 if (surface->overlay_dest != Dst)
3065 surface->overlay_dest = Dst;
3066 list_add_tail(&Dst->overlays, &surface->overlay_entry);
3069 else if (flags & WINEDDOVER_HIDE)
3071 /* tests show that the rectangles are erased on hide */
3072 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3073 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3074 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3075 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3076 surface->overlay_dest = NULL;
3079 surface->surface_ops->surface_draw_overlay(surface);
3084 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
3086 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3088 TRACE("iface %p, clipper %p.\n", iface, clipper);
3090 surface->clipper = clipper;
3095 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
3097 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3099 TRACE("iface %p, clipper %p.\n", iface, clipper);
3101 *clipper = surface->clipper;
3103 wined3d_clipper_incref(*clipper);
3108 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
3110 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3111 const struct wined3d_format *format = wined3d_get_format(&surface->resource.device->adapter->gl_info, format_id);
3113 TRACE("iface %p, format %s.\n", iface, debug_d3dformat(format_id));
3115 if (surface->resource.format->id != WINED3DFMT_UNKNOWN)
3117 FIXME("The format of the surface must be WINED3DFORMAT_UNKNOWN.\n");
3118 return WINED3DERR_INVALIDCALL;
3121 surface->resource.size = wined3d_format_calculate_size(format, surface->resource.device->surface_alignment,
3122 surface->pow2Width, surface->pow2Height);
3123 surface->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
3124 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
3125 surface->resource.format = format;
3127 TRACE("size %u, byte_count %u\n", surface->resource.size, format->byte_count);
3128 TRACE("glFormat %#x, glInternal %#x, glType %#x.\n",
3129 format->glFormat, format->glInternal, format->glType);
3134 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3135 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3137 unsigned short *dst_s;
3141 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3143 for (y = 0; y < h; ++y)
3145 src_f = (const float *)(src + y * pitch_in);
3146 dst_s = (unsigned short *) (dst + y * pitch_out);
3147 for (x = 0; x < w; ++x)
3149 dst_s[x] = float_32_to_16(src_f + x);
3154 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3155 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3157 static const unsigned char convert_5to8[] =
3159 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3160 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3161 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3162 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3164 static const unsigned char convert_6to8[] =
3166 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3167 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3168 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3169 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3170 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3171 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3172 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3173 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3177 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3179 for (y = 0; y < h; ++y)
3181 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3182 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3183 for (x = 0; x < w; ++x)
3185 WORD pixel = src_line[x];
3186 dst_line[x] = 0xff000000
3187 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3188 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3189 | convert_5to8[(pixel & 0x001f)];
3194 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3195 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3199 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3201 for (y = 0; y < h; ++y)
3203 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3204 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3206 for (x = 0; x < w; ++x)
3208 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3213 static inline BYTE cliptobyte(int x)
3215 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3218 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3219 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3221 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3224 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3226 for (y = 0; y < h; ++y)
3228 const BYTE *src_line = src + y * pitch_in;
3229 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3230 for (x = 0; x < w; ++x)
3232 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3233 * C = Y - 16; D = U - 128; E = V - 128;
3234 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3235 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3236 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3237 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3238 * U and V are shared between the pixels. */
3239 if (!(x & 1)) /* For every even pixel, read new U and V. */
3241 d = (int) src_line[1] - 128;
3242 e = (int) src_line[3] - 128;
3244 g2 = - 100 * d - 208 * e + 128;
3247 c2 = 298 * ((int) src_line[0] - 16);
3248 dst_line[x] = 0xff000000
3249 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3250 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3251 | cliptobyte((c2 + b2) >> 8); /* blue */
3252 /* Scale RGB values to 0..255 range,
3253 * then clip them if still not in range (may be negative),
3254 * then shift them within DWORD if necessary. */
3260 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3261 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3264 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3266 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3268 for (y = 0; y < h; ++y)
3270 const BYTE *src_line = src + y * pitch_in;
3271 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3272 for (x = 0; x < w; ++x)
3274 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3275 * C = Y - 16; D = U - 128; E = V - 128;
3276 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3277 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3278 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3279 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3280 * U and V are shared between the pixels. */
3281 if (!(x & 1)) /* For every even pixel, read new U and V. */
3283 d = (int) src_line[1] - 128;
3284 e = (int) src_line[3] - 128;
3286 g2 = - 100 * d - 208 * e + 128;
3289 c2 = 298 * ((int) src_line[0] - 16);
3290 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3291 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3292 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3293 /* Scale RGB values to 0..255 range,
3294 * then clip them if still not in range (may be negative),
3295 * then shift them within DWORD if necessary. */
3301 struct d3dfmt_convertor_desc
3303 enum wined3d_format_id from, to;
3304 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3307 static const struct d3dfmt_convertor_desc convertors[] =
3309 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3310 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3311 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3312 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3313 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3316 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from,
3317 enum wined3d_format_id to)
3321 for (i = 0; i < (sizeof(convertors) / sizeof(*convertors)); ++i)
3323 if (convertors[i].from == from && convertors[i].to == to)
3324 return &convertors[i];
3330 /*****************************************************************************
3331 * surface_convert_format
3333 * Creates a duplicate of a surface in a different format. Is used by Blt to
3334 * blit between surfaces with different formats.
3337 * source: Source surface
3338 * fmt: Requested destination format
3340 *****************************************************************************/
3341 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
3343 const struct d3dfmt_convertor_desc *conv;
3344 WINED3DLOCKED_RECT lock_src, lock_dst;
3345 IWineD3DSurface *ret = NULL;
3348 conv = find_convertor(source->resource.format->id, to_fmt);
3351 FIXME("Cannot find a conversion function from format %s to %s.\n",
3352 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
3356 IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->resource.width,
3357 source->resource.height, to_fmt, TRUE /* lockable */, TRUE /* discard */, 0 /* level */,
3358 0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
3359 0 /* MultiSampleQuality */, source->surface_type, NULL /* parent */, &wined3d_null_parent_ops, &ret);
3362 ERR("Failed to create a destination surface for conversion.\n");
3366 memset(&lock_src, 0, sizeof(lock_src));
3367 memset(&lock_dst, 0, sizeof(lock_dst));
3369 hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
3372 ERR("Failed to lock the source surface.\n");
3373 IWineD3DSurface_Release(ret);
3376 hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
3379 ERR("Failed to lock the destination surface.\n");
3380 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
3381 IWineD3DSurface_Release(ret);
3385 conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
3386 source->resource.width, source->resource.height);
3388 IWineD3DSurface_Unmap(ret);
3389 IWineD3DSurface_Unmap((IWineD3DSurface *)source);
3391 return (IWineD3DSurfaceImpl *)ret;
3394 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
3395 unsigned int bpp, UINT pitch, DWORD color)
3402 #define COLORFILL_ROW(type) \
3404 type *d = (type *)buf; \
3405 for (x = 0; x < width; ++x) \
3406 d[x] = (type)color; \
3412 COLORFILL_ROW(BYTE);
3416 COLORFILL_ROW(WORD);
3422 for (x = 0; x < width; ++x, d += 3)
3424 d[0] = (color ) & 0xFF;
3425 d[1] = (color >> 8) & 0xFF;
3426 d[2] = (color >> 16) & 0xFF;
3431 COLORFILL_ROW(DWORD);
3435 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
3436 return WINED3DERR_NOTAVAILABLE;
3439 #undef COLORFILL_ROW
3441 /* Now copy first row. */
3443 for (y = 1; y < height; ++y)
3446 memcpy(buf, first, width * bpp);
3452 /* Do not call while under the GL lock. */
3453 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *dst_rect,
3454 IWineD3DSurface *src_surface, const RECT *src_rect, DWORD flags,
3455 const WINEDDBLTFX *fx, WINED3DTEXTUREFILTERTYPE filter)
3457 IWineD3DSurfaceImpl *dst_surface = (IWineD3DSurfaceImpl *)iface;
3459 TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
3460 iface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
3461 flags, fx, debug_d3dtexturefiltertype(filter));
3463 return dst_surface->surface_ops->surface_blt(dst_surface, dst_rect,
3464 (IWineD3DSurfaceImpl *)src_surface, src_rect, flags, fx, filter);
3467 /* Do not call while under the GL lock. */
3468 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface,
3469 DWORD dst_x, DWORD dst_y, IWineD3DSurface *src_surface, const RECT *src_rect, DWORD trans)
3471 IWineD3DSurfaceImpl *dst_surface = (IWineD3DSurfaceImpl *)iface;
3473 TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, trans %#x.\n",
3474 iface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect), trans);
3476 return dst_surface->surface_ops->surface_bltfast(dst_surface, dst_x, dst_y,
3477 (IWineD3DSurfaceImpl *)src_surface, src_rect, trans);
3480 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Unmap(IWineD3DSurface *iface)
3482 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3484 TRACE("iface %p.\n", iface);
3486 if (!(surface->flags & SFLAG_LOCKED))
3488 WARN("Trying to unmap unmapped surface.\n");
3489 return WINEDDERR_NOTLOCKED;
3491 surface->flags &= ~SFLAG_LOCKED;
3493 surface->surface_ops->surface_unmap(surface);
3498 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
3499 WINED3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
3501 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3503 TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
3504 iface, locked_rect, wine_dbgstr_rect(rect), flags);
3506 if (surface->flags & SFLAG_LOCKED)
3508 WARN("Surface is already mapped.\n");
3509 return WINED3DERR_INVALIDCALL;
3511 surface->flags |= SFLAG_LOCKED;
3513 if (!(surface->flags & SFLAG_LOCKABLE))
3514 WARN("Trying to lock unlockable surface.\n");
3516 surface->surface_ops->surface_map(surface, rect, flags);
3518 locked_rect->Pitch = IWineD3DSurface_GetPitch(iface);
3522 locked_rect->pBits = surface->resource.allocatedMemory;
3523 surface->lockedRect.left = 0;
3524 surface->lockedRect.top = 0;
3525 surface->lockedRect.right = surface->resource.width;
3526 surface->lockedRect.bottom = surface->resource.height;
3530 const struct wined3d_format *format = surface->resource.format;
3532 if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
3534 /* Compressed textures are block based, so calculate the offset of
3535 * the block that contains the top-left pixel of the locked rectangle. */
3536 locked_rect->pBits = surface->resource.allocatedMemory
3537 + ((rect->top / format->block_height) * locked_rect->Pitch)
3538 + ((rect->left / format->block_width) * format->block_byte_count);
3542 locked_rect->pBits = surface->resource.allocatedMemory
3543 + (locked_rect->Pitch * rect->top)
3544 + (rect->left * format->byte_count);
3546 surface->lockedRect.left = rect->left;
3547 surface->lockedRect.top = rect->top;
3548 surface->lockedRect.right = rect->right;
3549 surface->lockedRect.bottom = rect->bottom;
3552 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3553 TRACE("Returning memory %p, pitch %u.\n", locked_rect->pBits, locked_rect->Pitch);
3558 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *dc)
3560 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3563 TRACE("iface %p, dc %p.\n", iface, dc);
3565 if (surface->flags & SFLAG_USERPTR)
3567 ERR("Not supported on surfaces with application-provided memory.\n");
3568 return WINEDDERR_NODC;
3571 /* Give more detailed info for ddraw. */
3572 if (surface->flags & SFLAG_DCINUSE)
3573 return WINEDDERR_DCALREADYCREATED;
3575 /* Can't GetDC if the surface is locked. */
3576 if (surface->flags & SFLAG_LOCKED)
3577 return WINED3DERR_INVALIDCALL;
3579 hr = surface->surface_ops->surface_getdc(surface);
3583 if (surface->resource.format->id == WINED3DFMT_P8_UINT
3584 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
3586 /* GetDC on palettized formats is unsupported in D3D9, and the method
3587 * is missing in D3D8, so this should only be used for DX <=7
3588 * surfaces (with non-device palettes). */
3589 const PALETTEENTRY *pal = NULL;
3591 if (surface->palette)
3593 pal = surface->palette->palents;
3597 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
3598 IWineD3DSurfaceImpl *dds_primary = swapchain->front_buffer;
3600 if (dds_primary && dds_primary->palette)
3601 pal = dds_primary->palette->palents;
3609 for (i = 0; i < 256; ++i)
3611 col[i].rgbRed = pal[i].peRed;
3612 col[i].rgbGreen = pal[i].peGreen;
3613 col[i].rgbBlue = pal[i].peBlue;
3614 col[i].rgbReserved = 0;
3616 SetDIBColorTable(surface->hDC, 0, 256, col);
3620 surface->flags |= SFLAG_DCINUSE;
3623 TRACE("Returning dc %p.\n", *dc);
3628 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC dc)
3630 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3632 TRACE("iface %p, dc %p.\n", iface, dc);
3634 if (!(surface->flags & SFLAG_DCINUSE))
3635 return WINEDDERR_NODC;
3637 if (surface->hDC != dc)
3639 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3641 return WINEDDERR_NODC;
3644 if ((surface->flags & SFLAG_PBO) && surface->resource.allocatedMemory)
3646 /* Copy the contents of the DIB over to the PBO. */
3647 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->dib.bitmap_size);
3650 /* We locked first, so unlock now. */
3651 IWineD3DSurface_Unmap(iface);
3653 surface->flags &= ~SFLAG_DCINUSE;
3658 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD flags)
3660 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3661 struct wined3d_swapchain *swapchain;
3664 TRACE("iface %p, override %p, flags %#x.\n", iface, override, flags);
3666 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
3668 ERR("Flipped surface is not on a swapchain.\n");
3669 return WINEDDERR_NOTFLIPPABLE;
3671 swapchain = surface->container.u.swapchain;
3673 hr = surface->surface_ops->surface_flip(surface, (IWineD3DSurfaceImpl *)override);
3677 /* Just overwrite the swapchain presentation interval. This is ok because
3678 * only ddraw apps can call Flip, and only d3d8 and d3d9 applications
3679 * specify the presentation interval. */
3680 if (!(flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)))
3681 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
3682 else if (flags & WINEDDFLIP_NOVSYNC)
3683 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3684 else if (flags & WINEDDFLIP_INTERVAL2)
3685 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
3686 else if (flags & WINEDDFLIP_INTERVAL3)
3687 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
3689 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
3691 return wined3d_swapchain_present(swapchain, NULL, NULL, swapchain->win_handle, NULL, 0);
3694 /* ****************************************************
3695 IWineD3DSurface IWineD3DResource parts follow
3696 **************************************************** */
3698 /* Do not call while under the GL lock. */
3699 void surface_internal_preload(IWineD3DSurfaceImpl *surface, enum WINED3DSRGB srgb)
3701 IWineD3DDeviceImpl *device = surface->resource.device;
3703 TRACE("iface %p, srgb %#x.\n", surface, srgb);
3705 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
3707 struct wined3d_texture *texture = surface->container.u.texture;
3709 TRACE("Passing to container (%p).\n", texture);
3710 texture->texture_ops->texture_preload(texture, srgb);
3714 struct wined3d_context *context = NULL;
3716 TRACE("(%p) : About to load surface\n", surface);
3718 if (!device->isInDraw) context = context_acquire(device, NULL);
3720 if (surface->resource.format->id == WINED3DFMT_P8_UINT
3721 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
3723 if (palette9_changed(surface))
3725 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
3726 /* TODO: This is not necessarily needed with hw palettized texture support */
3727 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3728 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
3729 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
3733 surface_load(surface, srgb == SRGB_SRGB ? TRUE : FALSE);
3735 if (surface->resource.pool == WINED3DPOOL_DEFAULT)
3737 /* Tell opengl to try and keep this texture in video ram (well mostly) */
3741 glPrioritizeTextures(1, &surface->texture_name, &tmp);
3745 if (context) context_release(context);
3749 BOOL surface_init_sysmem(IWineD3DSurfaceImpl *surface)
3751 if (!surface->resource.allocatedMemory)
3753 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3754 surface->resource.size + RESOURCE_ALIGNMENT);
3755 if (!surface->resource.heapMemory)
3757 ERR("Out of memory\n");
3760 surface->resource.allocatedMemory =
3761 (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
3765 memset(surface->resource.allocatedMemory, 0, surface->resource.size);
3768 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3773 /* ******************************************************
3774 IWineD3DSurface IWineD3DSurface parts follow
3775 ****************************************************** */
3777 /* Read the framebuffer back into the surface */
3778 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, const RECT *rect, void *dest, UINT pitch)
3780 IWineD3DDeviceImpl *device = This->resource.device;
3781 const struct wined3d_gl_info *gl_info;
3782 struct wined3d_context *context;
3786 BYTE *row, *top, *bottom;
3790 BOOL srcIsUpsideDown;
3795 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
3796 static BOOL warned = FALSE;
3798 ERR("The application tries to lock the render target, but render target locking is disabled\n");
3804 context = context_acquire(device, This);
3805 context_apply_blit_state(context, device);
3806 gl_info = context->gl_info;
3810 /* Select the correct read buffer, and give some debug output.
3811 * There is no need to keep track of the current read buffer or reset it, every part of the code
3812 * that reads sets the read buffer as desired.
3814 if (surface_is_offscreen(This))
3816 /* Mapping the primary render target which is not on a swapchain.
3817 * Read from the back buffer. */
3818 TRACE("Mapping offscreen render target.\n");
3819 glReadBuffer(device->offscreenBuffer);
3820 srcIsUpsideDown = TRUE;
3824 /* Onscreen surfaces are always part of a swapchain */
3825 GLenum buffer = surface_get_gl_buffer(This);
3826 TRACE("Mapping %#x buffer.\n", buffer);
3827 glReadBuffer(buffer);
3828 checkGLcall("glReadBuffer");
3829 srcIsUpsideDown = FALSE;
3832 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
3834 local_rect.left = 0;
3836 local_rect.right = This->resource.width;
3837 local_rect.bottom = This->resource.height;
3843 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
3845 switch (This->resource.format->id)
3847 case WINED3DFMT_P8_UINT:
3849 if (primary_render_target_is_p8(device))
3851 /* In case of P8 render targets the index is stored in the alpha component */
3853 type = GL_UNSIGNED_BYTE;
3855 bpp = This->resource.format->byte_count;
3857 /* GL can't return palettized data, so read ARGB pixels into a
3858 * separate block of memory and convert them into palettized format
3859 * in software. Slow, but if the app means to use palettized render
3860 * targets and locks it...
3862 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
3863 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
3864 * for the color channels when palettizing the colors.
3867 type = GL_UNSIGNED_BYTE;
3869 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
3871 ERR("Out of memory\n");
3875 bpp = This->resource.format->byte_count * 3;
3882 fmt = This->resource.format->glFormat;
3883 type = This->resource.format->glType;
3884 bpp = This->resource.format->byte_count;
3887 if (This->flags & SFLAG_PBO)
3889 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
3890 checkGLcall("glBindBufferARB");
3893 ERR("mem not null for pbo -- unexpected\n");
3898 /* Save old pixel store pack state */
3899 glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
3900 checkGLcall("glGetIntegerv");
3901 glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
3902 checkGLcall("glGetIntegerv");
3903 glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
3904 checkGLcall("glGetIntegerv");
3906 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3907 glPixelStorei(GL_PACK_ROW_LENGTH, This->resource.width);
3908 checkGLcall("glPixelStorei");
3909 glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
3910 checkGLcall("glPixelStorei");
3911 glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
3912 checkGLcall("glPixelStorei");
3914 glReadPixels(local_rect.left, !srcIsUpsideDown ? (This->resource.height - local_rect.bottom) : local_rect.top,
3915 local_rect.right - local_rect.left,
3916 local_rect.bottom - local_rect.top,
3918 checkGLcall("glReadPixels");
3920 /* Reset previous pixel store pack state */
3921 glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
3922 checkGLcall("glPixelStorei");
3923 glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
3924 checkGLcall("glPixelStorei");
3925 glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
3926 checkGLcall("glPixelStorei");
3928 if (This->flags & SFLAG_PBO)
3930 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
3931 checkGLcall("glBindBufferARB");
3933 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
3934 * to get a pointer to it and perform the flipping in software. This is a lot
3935 * faster than calling glReadPixels for each line. In case we want more speed
3936 * we should rerender it flipped in a FBO and read the data back from the FBO. */
3937 if(!srcIsUpsideDown) {
3938 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
3939 checkGLcall("glBindBufferARB");
3941 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
3942 checkGLcall("glMapBufferARB");
3946 /* TODO: Merge this with the palettization loop below for P8 targets */
3947 if(!srcIsUpsideDown) {
3949 /* glReadPixels returns the image upside down, and there is no way to prevent this.
3950 Flip the lines in software */
3951 len = (local_rect.right - local_rect.left) * bpp;
3952 off = local_rect.left * bpp;
3954 row = HeapAlloc(GetProcessHeap(), 0, len);
3956 ERR("Out of memory\n");
3957 if (This->resource.format->id == WINED3DFMT_P8_UINT) HeapFree(GetProcessHeap(), 0, mem);
3962 top = mem + pitch * local_rect.top;
3963 bottom = mem + pitch * (local_rect.bottom - 1);
3964 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
3965 memcpy(row, top + off, len);
3966 memcpy(top + off, bottom + off, len);
3967 memcpy(bottom + off, row, len);
3971 HeapFree(GetProcessHeap(), 0, row);
3973 /* Unmap the temp PBO buffer */
3974 if (This->flags & SFLAG_PBO)
3976 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
3977 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
3982 context_release(context);
3984 /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
3985 * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
3986 * the same color but we have no choice.
3987 * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
3989 if (This->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
3991 const PALETTEENTRY *pal = NULL;
3992 DWORD width = pitch / 3;
3996 pal = This->palette->palents;
3998 ERR("Palette is missing, cannot perform inverse palette lookup\n");
3999 HeapFree(GetProcessHeap(), 0, mem);
4003 for(y = local_rect.top; y < local_rect.bottom; y++) {
4004 for(x = local_rect.left; x < local_rect.right; x++) {
4005 /* start lines pixels */
4006 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4007 const BYTE *green = blue + 1;
4008 const BYTE *red = green + 1;
4010 for(c = 0; c < 256; c++) {
4011 if(*red == pal[c].peRed &&
4012 *green == pal[c].peGreen &&
4013 *blue == pal[c].peBlue)
4015 *((BYTE *) dest + y * width + x) = c;
4021 HeapFree(GetProcessHeap(), 0, mem);
4025 /* Read the framebuffer contents into a texture */
4026 static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb)
4028 IWineD3DDeviceImpl *device = This->resource.device;
4029 const struct wined3d_gl_info *gl_info;
4030 struct wined3d_context *context;
4032 if (!surface_is_offscreen(This))
4034 /* We would need to flip onscreen surfaces, but there's no efficient
4035 * way to do that here. It makes more sense for the caller to
4036 * explicitly go through sysmem. */
4037 ERR("Not supported for onscreen targets.\n");
4041 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
4042 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
4043 * states in the stateblock, and no driver was found yet that had bugs in that regard.
4045 context = context_acquire(device, This);
4046 gl_info = context->gl_info;
4048 surface_prepare_texture(This, gl_info, srgb);
4049 surface_bind_and_dirtify(This, gl_info, srgb);
4051 TRACE("Reading back offscreen render target %p.\n", This);
4055 glReadBuffer(device->offscreenBuffer);
4056 checkGLcall("glReadBuffer");
4058 glCopyTexSubImage2D(This->texture_target, This->texture_level,
4059 0, 0, 0, 0, This->resource.width, This->resource.height);
4060 checkGLcall("glCopyTexSubImage2D");
4064 context_release(context);
4067 /* Context activation is done by the caller. */
4068 static void surface_prepare_texture_internal(IWineD3DSurfaceImpl *surface,
4069 const struct wined3d_gl_info *gl_info, BOOL srgb)
4071 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4072 CONVERT_TYPES convert;
4073 struct wined3d_format format;
4075 if (surface->flags & alloc_flag) return;
4077 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4078 if (convert != NO_CONVERSION || format.convert) surface->flags |= SFLAG_CONVERTED;
4079 else surface->flags &= ~SFLAG_CONVERTED;
4081 surface_bind_and_dirtify(surface, gl_info, srgb);
4082 surface_allocate_surface(surface, gl_info, &format, srgb);
4083 surface->flags |= alloc_flag;
4086 /* Context activation is done by the caller. */
4087 void surface_prepare_texture(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
4089 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4091 struct wined3d_texture *texture = surface->container.u.texture;
4092 UINT sub_count = texture->level_count * texture->layer_count;
4095 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4097 for (i = 0; i < sub_count; ++i)
4099 IWineD3DSurfaceImpl *s = surface_from_resource(texture->sub_resources[i]);
4100 surface_prepare_texture_internal(s, gl_info, srgb);
4106 surface_prepare_texture_internal(surface, gl_info, srgb);
4109 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *surface,
4110 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4112 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface); /* target is argb, 4 byte */
4113 IWineD3DDeviceImpl *device = surface->resource.device;
4114 const struct wined3d_gl_info *gl_info;
4115 struct wined3d_context *context;
4119 surface_get_rect(surface, rect, &local_rect);
4121 mem += local_rect.top * pitch + local_rect.left * bpp;
4122 w = local_rect.right - local_rect.left;
4123 h = local_rect.bottom - local_rect.top;
4125 /* Activate the correct context for the render target */
4126 context = context_acquire(device, surface);
4127 context_apply_blit_state(context, device);
4128 gl_info = context->gl_info;
4132 if (!surface_is_offscreen(surface))
4134 GLenum buffer = surface_get_gl_buffer(surface);
4135 TRACE("Unlocking %#x buffer.\n", buffer);
4136 context_set_draw_buffer(context, buffer);
4138 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4139 glPixelZoom(1.0f, -1.0f);
4143 /* Primary offscreen render target */
4144 TRACE("Offscreen render target.\n");
4145 context_set_draw_buffer(context, device->offscreenBuffer);
4147 glPixelZoom(1.0f, 1.0f);
4150 glRasterPos3i(local_rect.left, local_rect.top, 1);
4151 checkGLcall("glRasterPos3i");
4153 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4154 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4156 if (surface->flags & SFLAG_PBO)
4158 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4159 checkGLcall("glBindBufferARB");
4162 glDrawPixels(w, h, fmt, type, mem);
4163 checkGLcall("glDrawPixels");
4165 if (surface->flags & SFLAG_PBO)
4167 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4168 checkGLcall("glBindBufferARB");
4171 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4172 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4176 if (wined3d_settings.strict_draw_ordering
4177 || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4178 && surface->container.u.swapchain->front_buffer == surface))
4181 context_release(context);
4184 /* ******************************************************
4185 IWineD3DSurface Internal (No mapping to directx api) parts follow
4186 ****************************************************** */
4188 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck,
4189 BOOL use_texturing, struct wined3d_format *format, CONVERT_TYPES *convert)
4191 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
4192 IWineD3DDeviceImpl *device = This->resource.device;
4193 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4194 BOOL blit_supported = FALSE;
4196 /* Copy the default values from the surface. Below we might perform fixups */
4197 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
4198 *format = *This->resource.format;
4199 *convert = NO_CONVERSION;
4201 /* Ok, now look if we have to do any conversion */
4202 switch (This->resource.format->id)
4204 case WINED3DFMT_P8_UINT:
4205 /* Below the call to blit_supported is disabled for Wine 1.2
4206 * because the function isn't operating correctly yet. At the
4207 * moment 8-bit blits are handled in software and if certain GL
4208 * extensions are around, surface conversion is performed at
4209 * upload time. The blit_supported call recognizes it as a
4210 * destination fixup. This type of upload 'fixup' and 8-bit to
4211 * 8-bit blits need to be handled by the blit_shader.
4212 * TODO: get rid of this #if 0. */
4214 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4215 &rect, This->resource.usage, This->resource.pool, This->resource.format,
4216 &rect, This->resource.usage, This->resource.pool, This->resource.format);
4218 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
4220 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
4221 * texturing. Further also use conversion in case of color keying.
4222 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
4223 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
4224 * conflicts with this.
4226 if (!((blit_supported && device->render_targets && This == device->render_targets[0]))
4227 || colorkey_active || !use_texturing)
4229 format->glFormat = GL_RGBA;
4230 format->glInternal = GL_RGBA;
4231 format->glType = GL_UNSIGNED_BYTE;
4232 format->conv_byte_count = 4;
4233 if (colorkey_active)
4234 *convert = CONVERT_PALETTED_CK;
4236 *convert = CONVERT_PALETTED;
4240 case WINED3DFMT_B2G3R3_UNORM:
4241 /* **********************
4242 GL_UNSIGNED_BYTE_3_3_2
4243 ********************** */
4244 if (colorkey_active) {
4245 /* This texture format will never be used.. So do not care about color keying
4246 up until the point in time it will be needed :-) */
4247 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
4251 case WINED3DFMT_B5G6R5_UNORM:
4252 if (colorkey_active)
4254 *convert = CONVERT_CK_565;
4255 format->glFormat = GL_RGBA;
4256 format->glInternal = GL_RGB5_A1;
4257 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
4258 format->conv_byte_count = 2;
4262 case WINED3DFMT_B5G5R5X1_UNORM:
4263 if (colorkey_active)
4265 *convert = CONVERT_CK_5551;
4266 format->glFormat = GL_BGRA;
4267 format->glInternal = GL_RGB5_A1;
4268 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
4269 format->conv_byte_count = 2;
4273 case WINED3DFMT_B8G8R8_UNORM:
4274 if (colorkey_active)
4276 *convert = CONVERT_CK_RGB24;
4277 format->glFormat = GL_RGBA;
4278 format->glInternal = GL_RGBA8;
4279 format->glType = GL_UNSIGNED_INT_8_8_8_8;
4280 format->conv_byte_count = 4;
4284 case WINED3DFMT_B8G8R8X8_UNORM:
4285 if (colorkey_active)
4287 *convert = CONVERT_RGB32_888;
4288 format->glFormat = GL_RGBA;
4289 format->glInternal = GL_RGBA8;
4290 format->glType = GL_UNSIGNED_INT_8_8_8_8;
4291 format->conv_byte_count = 4;
4302 void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
4304 IWineD3DDeviceImpl *device = This->resource.device;
4305 struct wined3d_palette *pal = This->palette;
4306 BOOL index_in_alpha = FALSE;
4309 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4310 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4311 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4312 * duplicate entries. Store the color key in the unused alpha component to speed the
4313 * download up and to make conversion unneeded. */
4314 index_in_alpha = primary_render_target_is_p8(device);
4318 UINT dxVersion = device->wined3d->dxVersion;
4320 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
4323 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4326 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4327 * there's no palette at this time. */
4328 for (i = 0; i < 256; i++) table[i][3] = i;
4333 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
4334 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
4335 * capability flag is present (wine does advertise this capability) */
4336 for (i = 0; i < 256; ++i)
4338 table[i][0] = device->palettes[device->currentPalette][i].peRed;
4339 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
4340 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
4341 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
4347 TRACE("Using surface palette %p\n", pal);
4348 /* Get the surface's palette */
4349 for (i = 0; i < 256; ++i)
4351 table[i][0] = pal->palents[i].peRed;
4352 table[i][1] = pal->palents[i].peGreen;
4353 table[i][2] = pal->palents[i].peBlue;
4355 /* When index_in_alpha is set the palette index is stored in the
4356 * alpha component. In case of a readback we can then read
4357 * GL_ALPHA. Color keying is handled in BltOverride using a
4358 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4359 * color key itself is passed to glAlphaFunc in other cases the
4360 * alpha component of pixels that should be masked away is set to 0. */
4365 else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
4366 && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
4370 else if (pal->flags & WINEDDPCAPS_ALPHA)
4372 table[i][3] = pal->palents[i].peFlags;
4382 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
4383 UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
4387 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
4392 memcpy(dst, src, pitch * height);
4395 case CONVERT_PALETTED:
4396 case CONVERT_PALETTED_CK:
4401 d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
4403 for (y = 0; y < height; y++)
4405 source = src + pitch * y;
4406 dest = dst + outpitch * y;
4407 /* This is an 1 bpp format, using the width here is fine */
4408 for (x = 0; x < width; x++) {
4409 BYTE color = *source++;
4410 *dest++ = table[color][0];
4411 *dest++ = table[color][1];
4412 *dest++ = table[color][2];
4413 *dest++ = table[color][3];
4419 case CONVERT_CK_565:
4421 /* Converting the 565 format in 5551 packed to emulate color-keying.
4423 Note : in all these conversion, it would be best to average the averaging
4424 pixels to get the color of the pixel that will be color-keyed to
4425 prevent 'color bleeding'. This will be done later on if ever it is
4428 Note2: Nvidia documents say that their driver does not support alpha + color keying
4429 on the same surface and disables color keying in such a case
4435 TRACE("Color keyed 565\n");
4437 for (y = 0; y < height; y++) {
4438 Source = (const WORD *)(src + y * pitch);
4439 Dest = (WORD *) (dst + y * outpitch);
4440 for (x = 0; x < width; x++ ) {
4441 WORD color = *Source++;
4442 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
4443 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4444 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4453 case CONVERT_CK_5551:
4455 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4459 TRACE("Color keyed 5551\n");
4460 for (y = 0; y < height; y++) {
4461 Source = (const WORD *)(src + y * pitch);
4462 Dest = (WORD *) (dst + y * outpitch);
4463 for (x = 0; x < width; x++ ) {
4464 WORD color = *Source++;
4466 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4467 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4471 *Dest &= ~(1 << 15);
4479 case CONVERT_CK_RGB24:
4481 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4483 for (y = 0; y < height; y++)
4485 source = src + pitch * y;
4486 dest = dst + outpitch * y;
4487 for (x = 0; x < width; x++) {
4488 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4489 DWORD dstcolor = color << 8;
4490 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4491 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4494 *(DWORD*)dest = dstcolor;
4502 case CONVERT_RGB32_888:
4504 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4506 for (y = 0; y < height; y++)
4508 source = src + pitch * y;
4509 dest = dst + outpitch * y;
4510 for (x = 0; x < width; x++) {
4511 DWORD color = 0xffffff & *(const DWORD*)source;
4512 DWORD dstcolor = color << 8;
4513 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4514 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4517 *(DWORD*)dest = dstcolor;
4526 ERR("Unsupported conversion type %#x.\n", convert);
4531 BOOL palette9_changed(IWineD3DSurfaceImpl *This)
4533 IWineD3DDeviceImpl *device = This->resource.device;
4535 if (This->palette || (This->resource.format->id != WINED3DFMT_P8_UINT
4536 && This->resource.format->id != WINED3DFMT_P8_UINT_A8_UNORM))
4538 /* If a ddraw-style palette is attached assume no d3d9 palette change.
4539 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
4546 if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
4551 This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4553 memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
4557 void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
4559 /* Flip the surface contents */
4564 front->hDC = back->hDC;
4568 /* Flip the DIBsection */
4571 BOOL hasDib = front->flags & SFLAG_DIBSECTION;
4572 tmp = front->dib.DIBsection;
4573 front->dib.DIBsection = back->dib.DIBsection;
4574 back->dib.DIBsection = tmp;
4576 if (back->flags & SFLAG_DIBSECTION) front->flags |= SFLAG_DIBSECTION;
4577 else front->flags &= ~SFLAG_DIBSECTION;
4578 if (hasDib) back->flags |= SFLAG_DIBSECTION;
4579 else back->flags &= ~SFLAG_DIBSECTION;
4582 /* Flip the surface data */
4586 tmp = front->dib.bitmap_data;
4587 front->dib.bitmap_data = back->dib.bitmap_data;
4588 back->dib.bitmap_data = tmp;
4590 tmp = front->resource.allocatedMemory;
4591 front->resource.allocatedMemory = back->resource.allocatedMemory;
4592 back->resource.allocatedMemory = tmp;
4594 tmp = front->resource.heapMemory;
4595 front->resource.heapMemory = back->resource.heapMemory;
4596 back->resource.heapMemory = tmp;
4601 GLuint tmp_pbo = front->pbo;
4602 front->pbo = back->pbo;
4603 back->pbo = tmp_pbo;
4606 /* client_memory should not be different, but just in case */
4609 tmp = front->dib.client_memory;
4610 front->dib.client_memory = back->dib.client_memory;
4611 back->dib.client_memory = tmp;
4614 /* Flip the opengl texture */
4618 tmp = back->texture_name;
4619 back->texture_name = front->texture_name;
4620 front->texture_name = tmp;
4622 tmp = back->texture_name_srgb;
4623 back->texture_name_srgb = front->texture_name_srgb;
4624 front->texture_name_srgb = tmp;
4626 resource_unload(&back->resource);
4627 resource_unload(&front->resource);
4631 DWORD tmp_flags = back->flags;
4632 back->flags = front->flags;
4633 front->flags = tmp_flags;
4637 /* Does a direct frame buffer -> texture copy. Stretching is done
4638 * with single pixel copy calls
4640 static void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
4641 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
4643 IWineD3DDeviceImpl *device = dst_surface->resource.device;
4646 struct wined3d_context *context;
4647 BOOL upsidedown = FALSE;
4648 RECT dst_rect = *dst_rect_in;
4650 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4651 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4653 if(dst_rect.top > dst_rect.bottom) {
4654 UINT tmp = dst_rect.bottom;
4655 dst_rect.bottom = dst_rect.top;
4660 context = context_acquire(device, src_surface);
4661 context_apply_blit_state(context, device);
4662 surface_internal_preload(dst_surface, SRGB_RGB);
4665 /* Bind the target texture */
4666 glBindTexture(dst_surface->texture_target, dst_surface->texture_name);
4667 checkGLcall("glBindTexture");
4668 if (surface_is_offscreen(src_surface))
4670 TRACE("Reading from an offscreen target\n");
4671 upsidedown = !upsidedown;
4672 glReadBuffer(device->offscreenBuffer);
4676 glReadBuffer(surface_get_gl_buffer(src_surface));
4678 checkGLcall("glReadBuffer");
4680 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
4681 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
4683 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4685 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4687 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
4688 ERR("Texture filtering not supported in direct blit\n");
4691 else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
4692 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4694 ERR("Texture filtering not supported in direct blit\n");
4698 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4699 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4701 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
4703 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4704 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
4705 src_rect->left, src_surface->resource.height - src_rect->bottom,
4706 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4710 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
4711 /* I have to process this row by row to swap the image,
4712 * otherwise it would be upside down, so stretching in y direction
4713 * doesn't cost extra time
4715 * However, stretching in x direction can be avoided if not necessary
4717 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
4718 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4720 /* Well, that stuff works, but it's very slow.
4721 * find a better way instead
4725 for (col = dst_rect.left; col < dst_rect.right; ++col)
4727 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4728 dst_rect.left + col /* x offset */, row /* y offset */,
4729 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
4734 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4735 dst_rect.left /* x offset */, row /* y offset */,
4736 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
4740 checkGLcall("glCopyTexSubImage2D");
4743 context_release(context);
4745 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
4746 * path is never entered
4748 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
4751 /* Uses the hardware to stretch and flip the image */
4752 static void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
4753 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
4755 IWineD3DDeviceImpl *device = dst_surface->resource.device;
4756 struct wined3d_swapchain *src_swapchain = NULL;
4757 GLuint src, backup = 0;
4758 float left, right, top, bottom; /* Texture coordinates */
4759 UINT fbwidth = src_surface->resource.width;
4760 UINT fbheight = src_surface->resource.height;
4761 struct wined3d_context *context;
4762 GLenum drawBuffer = GL_BACK;
4763 GLenum texture_target;
4764 BOOL noBackBufferBackup;
4766 BOOL upsidedown = FALSE;
4767 RECT dst_rect = *dst_rect_in;
4769 TRACE("Using hwstretch blit\n");
4770 /* Activate the Proper context for reading from the source surface, set it up for blitting */
4771 context = context_acquire(device, src_surface);
4772 context_apply_blit_state(context, device);
4773 surface_internal_preload(dst_surface, SRGB_RGB);
4775 src_offscreen = surface_is_offscreen(src_surface);
4776 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
4777 if (!noBackBufferBackup && !src_surface->texture_name)
4779 /* Get it a description */
4780 surface_internal_preload(src_surface, SRGB_RGB);
4784 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
4785 * This way we don't have to wait for the 2nd readback to finish to leave this function.
4787 if (context->aux_buffers >= 2)
4789 /* Got more than one aux buffer? Use the 2nd aux buffer */
4790 drawBuffer = GL_AUX1;
4792 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
4794 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
4795 drawBuffer = GL_AUX0;
4798 if(noBackBufferBackup) {
4799 glGenTextures(1, &backup);
4800 checkGLcall("glGenTextures");
4801 glBindTexture(GL_TEXTURE_2D, backup);
4802 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
4803 texture_target = GL_TEXTURE_2D;
4805 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
4806 * we are reading from the back buffer, the backup can be used as source texture
4808 texture_target = src_surface->texture_target;
4809 glBindTexture(texture_target, src_surface->texture_name);
4810 checkGLcall("glBindTexture(texture_target, src_surface->texture_name)");
4811 glEnable(texture_target);
4812 checkGLcall("glEnable(texture_target)");
4814 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
4815 src_surface->flags &= ~SFLAG_INTEXTURE;
4818 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4819 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4821 if(dst_rect.top > dst_rect.bottom) {
4822 UINT tmp = dst_rect.bottom;
4823 dst_rect.bottom = dst_rect.top;
4830 TRACE("Reading from an offscreen target\n");
4831 upsidedown = !upsidedown;
4832 glReadBuffer(device->offscreenBuffer);
4836 glReadBuffer(surface_get_gl_buffer(src_surface));
4839 /* TODO: Only back up the part that will be overwritten */
4840 glCopyTexSubImage2D(texture_target, 0,
4841 0, 0 /* read offsets */,
4846 checkGLcall("glCopyTexSubImage2D");
4848 /* No issue with overriding these - the sampler is dirty due to blit usage */
4849 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
4850 wined3d_gl_mag_filter(magLookup, Filter));
4851 checkGLcall("glTexParameteri");
4852 glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
4853 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
4854 checkGLcall("glTexParameteri");
4856 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
4857 src_swapchain = src_surface->container.u.swapchain;
4858 if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
4860 src = backup ? backup : src_surface->texture_name;
4864 glReadBuffer(GL_FRONT);
4865 checkGLcall("glReadBuffer(GL_FRONT)");
4867 glGenTextures(1, &src);
4868 checkGLcall("glGenTextures(1, &src)");
4869 glBindTexture(GL_TEXTURE_2D, src);
4870 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
4872 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
4873 * out for power of 2 sizes
4875 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
4876 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
4877 checkGLcall("glTexImage2D");
4878 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
4879 0, 0 /* read offsets */,
4884 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4885 checkGLcall("glTexParameteri");
4886 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4887 checkGLcall("glTexParameteri");
4889 glReadBuffer(GL_BACK);
4890 checkGLcall("glReadBuffer(GL_BACK)");
4892 if(texture_target != GL_TEXTURE_2D) {
4893 glDisable(texture_target);
4894 glEnable(GL_TEXTURE_2D);
4895 texture_target = GL_TEXTURE_2D;
4898 checkGLcall("glEnd and previous");
4900 left = src_rect->left;
4901 right = src_rect->right;
4905 top = src_surface->resource.height - src_rect->top;
4906 bottom = src_surface->resource.height - src_rect->bottom;
4910 top = src_surface->resource.height - src_rect->bottom;
4911 bottom = src_surface->resource.height - src_rect->top;
4914 if (src_surface->flags & SFLAG_NORMCOORD)
4916 left /= src_surface->pow2Width;
4917 right /= src_surface->pow2Width;
4918 top /= src_surface->pow2Height;
4919 bottom /= src_surface->pow2Height;
4922 /* draw the source texture stretched and upside down. The correct surface is bound already */
4923 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
4924 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
4926 context_set_draw_buffer(context, drawBuffer);
4927 glReadBuffer(drawBuffer);
4931 glTexCoord2f(left, bottom);
4935 glTexCoord2f(left, top);
4936 glVertex2i(0, dst_rect.bottom - dst_rect.top);
4939 glTexCoord2f(right, top);
4940 glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4943 glTexCoord2f(right, bottom);
4944 glVertex2i(dst_rect.right - dst_rect.left, 0);
4946 checkGLcall("glEnd and previous");
4948 if (texture_target != dst_surface->texture_target)
4950 glDisable(texture_target);
4951 glEnable(dst_surface->texture_target);
4952 texture_target = dst_surface->texture_target;
4955 /* Now read the stretched and upside down image into the destination texture */
4956 glBindTexture(texture_target, dst_surface->texture_name);
4957 checkGLcall("glBindTexture");
4958 glCopyTexSubImage2D(texture_target,
4960 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
4961 0, 0, /* We blitted the image to the origin */
4962 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4963 checkGLcall("glCopyTexSubImage2D");
4965 if(drawBuffer == GL_BACK) {
4966 /* Write the back buffer backup back */
4968 if(texture_target != GL_TEXTURE_2D) {
4969 glDisable(texture_target);
4970 glEnable(GL_TEXTURE_2D);
4971 texture_target = GL_TEXTURE_2D;
4973 glBindTexture(GL_TEXTURE_2D, backup);
4974 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
4978 if (texture_target != src_surface->texture_target)
4980 glDisable(texture_target);
4981 glEnable(src_surface->texture_target);
4982 texture_target = src_surface->texture_target;
4984 glBindTexture(src_surface->texture_target, src_surface->texture_name);
4985 checkGLcall("glBindTexture(src_surface->texture_target, src_surface->texture_name)");
4990 glTexCoord2f(0.0f, 0.0f);
4991 glVertex2i(0, fbheight);
4994 glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
4998 glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
4999 (float)fbheight / (float)src_surface->pow2Height);
5000 glVertex2i(fbwidth, 0);
5003 glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5004 glVertex2i(fbwidth, fbheight);
5007 glDisable(texture_target);
5008 checkGLcall("glDisable(texture_target)");
5011 if (src != src_surface->texture_name && src != backup)
5013 glDeleteTextures(1, &src);
5014 checkGLcall("glDeleteTextures(1, &src)");
5017 glDeleteTextures(1, &backup);
5018 checkGLcall("glDeleteTextures(1, &backup)");
5023 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5025 context_release(context);
5027 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5028 * path is never entered
5030 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5033 /* Front buffer coordinates are always full screen coordinates, but our GL
5034 * drawable is limited to the window's client area. The sysmem and texture
5035 * copies do have the full screen size. Note that GL has a bottom-left
5036 * origin, while D3D has a top-left origin. */
5037 void surface_translate_drawable_coords(IWineD3DSurfaceImpl *surface, HWND window, RECT *rect)
5039 UINT drawable_height;
5041 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5042 && surface == surface->container.u.swapchain->front_buffer)
5044 POINT offset = {0, 0};
5047 ScreenToClient(window, &offset);
5048 OffsetRect(rect, offset.x, offset.y);
5050 GetClientRect(window, &windowsize);
5051 drawable_height = windowsize.bottom - windowsize.top;
5055 drawable_height = surface->resource.height;
5058 rect->top = drawable_height - rect->top;
5059 rect->bottom = drawable_height - rect->bottom;
5062 /* blit between surface locations. onscreen on different swapchains is not supported.
5063 * depth / stencil is not supported. */
5064 static void surface_blt_fbo(IWineD3DDeviceImpl *device, const WINED3DTEXTUREFILTERTYPE filter,
5065 IWineD3DSurfaceImpl *src_surface, DWORD src_location, const RECT *src_rect_in,
5066 IWineD3DSurfaceImpl *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
5068 const struct wined3d_gl_info *gl_info;
5069 struct wined3d_context *context;
5070 RECT src_rect, dst_rect;
5073 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
5074 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
5075 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
5076 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
5077 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
5079 src_rect = *src_rect_in;
5080 dst_rect = *dst_rect_in;
5084 case WINED3DTEXF_LINEAR:
5085 gl_filter = GL_LINEAR;
5089 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
5090 case WINED3DTEXF_NONE:
5091 case WINED3DTEXF_POINT:
5092 gl_filter = GL_NEAREST;
5096 if (src_location == SFLAG_INDRAWABLE && surface_is_offscreen(src_surface))
5097 src_location = SFLAG_INTEXTURE;
5098 if (dst_location == SFLAG_INDRAWABLE && surface_is_offscreen(dst_surface))
5099 dst_location = SFLAG_INTEXTURE;
5101 /* Make sure the locations are up-to-date. Loading the destination
5102 * surface isn't required if the entire surface is overwritten. (And is
5103 * in fact harmful if we're being called by surface_load_location() with
5104 * the purpose of loading the destination surface.) */
5105 surface_load_location(src_surface, src_location, NULL);
5106 if (!surface_is_full_rect(dst_surface, &dst_rect))
5107 surface_load_location(dst_surface, dst_location, NULL);
5109 if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
5110 else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
5111 else context = context_acquire(device, NULL);
5113 if (!context->valid)
5115 context_release(context);
5116 WARN("Invalid context, skipping blit.\n");
5120 gl_info = context->gl_info;
5122 if (src_location == SFLAG_INDRAWABLE)
5124 GLenum buffer = surface_get_gl_buffer(src_surface);
5126 TRACE("Source surface %p is onscreen.\n", src_surface);
5128 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
5131 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5132 glReadBuffer(buffer);
5133 checkGLcall("glReadBuffer()");
5137 TRACE("Source surface %p is offscreen.\n", src_surface);
5139 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
5140 glReadBuffer(GL_COLOR_ATTACHMENT0);
5141 checkGLcall("glReadBuffer()");
5143 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
5146 if (dst_location == SFLAG_INDRAWABLE)
5148 GLenum buffer = surface_get_gl_buffer(dst_surface);
5150 TRACE("Destination surface %p is onscreen.\n", dst_surface);
5152 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5155 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5156 context_set_draw_buffer(context, buffer);
5160 TRACE("Destination surface %p is offscreen.\n", dst_surface);
5163 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
5164 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5166 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
5168 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5169 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5170 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5171 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5172 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5174 glDisable(GL_SCISSOR_TEST);
5175 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5177 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5178 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
5179 checkGLcall("glBlitFramebuffer()");
5183 if (wined3d_settings.strict_draw_ordering
5184 || (dst_location == SFLAG_INDRAWABLE
5185 && dst_surface->container.u.swapchain->front_buffer == dst_surface))
5188 context_release(context);
5191 static void surface_blt_to_drawable(IWineD3DDeviceImpl *device,
5192 WINED3DTEXTUREFILTERTYPE filter, BOOL color_key,
5193 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5194 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in)
5196 struct wined3d_context *context;
5197 RECT src_rect, dst_rect;
5199 src_rect = *src_rect_in;
5200 dst_rect = *dst_rect_in;
5202 /* Make sure the surface is up-to-date. This should probably use
5203 * surface_load_location() and worry about the destination surface too,
5204 * unless we're overwriting it completely. */
5205 surface_internal_preload(src_surface, SRGB_RGB);
5207 /* Activate the destination context, set it up for blitting */
5208 context = context_acquire(device, dst_surface);
5209 context_apply_blit_state(context, device);
5211 if (!surface_is_offscreen(dst_surface))
5212 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5214 device->blitter->set_shader(device->blit_priv, context->gl_info, src_surface);
5220 glEnable(GL_ALPHA_TEST);
5221 checkGLcall("glEnable(GL_ALPHA_TEST)");
5223 /* When the primary render target uses P8, the alpha component
5224 * contains the palette index. Which means that the colorkey is one of
5225 * the palette entries. In other cases pixels that should be masked
5226 * away have alpha set to 0. */
5227 if (primary_render_target_is_p8(device))
5228 glAlphaFunc(GL_NOTEQUAL, (float)src_surface->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
5230 glAlphaFunc(GL_NOTEQUAL, 0.0f);
5231 checkGLcall("glAlphaFunc");
5235 glDisable(GL_ALPHA_TEST);
5236 checkGLcall("glDisable(GL_ALPHA_TEST)");
5239 draw_textured_quad(src_surface, &src_rect, &dst_rect, filter);
5243 glDisable(GL_ALPHA_TEST);
5244 checkGLcall("glDisable(GL_ALPHA_TEST)");
5249 /* Leave the opengl state valid for blitting */
5250 device->blitter->unset_shader(context->gl_info);
5252 if (wined3d_settings.strict_draw_ordering
5253 || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5254 && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5255 wglFlush(); /* Flush to ensure ordering across contexts. */
5257 context_release(context);
5260 /* Do not call while under the GL lock. */
5261 HRESULT surface_color_fill(IWineD3DSurfaceImpl *s, const RECT *rect, const WINED3DCOLORVALUE *color)
5263 IWineD3DDeviceImpl *device = s->resource.device;
5264 const struct blit_shader *blitter;
5266 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5267 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5270 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5271 return WINED3DERR_INVALIDCALL;
5274 return blitter->color_fill(device, s, rect, color);
5277 /* Do not call while under the GL lock. */
5278 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *DestRect,
5279 IWineD3DSurfaceImpl *src_surface, const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5280 WINED3DTEXTUREFILTERTYPE Filter)
5282 IWineD3DDeviceImpl *device = dst_surface->resource.device;
5283 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5284 struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5285 RECT dst_rect, src_rect;
5287 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5288 dst_surface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
5289 flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
5291 /* Get the swapchain. One of the surfaces has to be a primary surface */
5292 if (dst_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
5294 WARN("Destination is in sysmem, rejecting gl blt\n");
5295 return WINED3DERR_INVALIDCALL;
5298 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5299 dstSwapchain = dst_surface->container.u.swapchain;
5303 if (src_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
5305 WARN("Src is in sysmem, rejecting gl blt\n");
5306 return WINED3DERR_INVALIDCALL;
5309 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5310 srcSwapchain = src_surface->container.u.swapchain;
5313 /* Early sort out of cases where no render target is used */
5314 if (!dstSwapchain && !srcSwapchain
5315 && src_surface != device->render_targets[0]
5316 && dst_surface != device->render_targets[0])
5318 TRACE("No surface is render target, not using hardware blit.\n");
5319 return WINED3DERR_INVALIDCALL;
5322 /* No destination color keying supported */
5323 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5325 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5326 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5327 return WINED3DERR_INVALIDCALL;
5330 surface_get_rect(dst_surface, DestRect, &dst_rect);
5331 if (src_surface) surface_get_rect(src_surface, SrcRect, &src_rect);
5333 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
5334 if (dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->back_buffers
5335 && dst_surface == dstSwapchain->front_buffer
5336 && src_surface == dstSwapchain->back_buffers[0])
5338 /* Half-Life does a Blt from the back buffer to the front buffer,
5339 * Full surface size, no flags... Use present instead
5341 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
5344 /* Check rects - IWineD3DDevice_Present doesn't handle them */
5347 TRACE("Looking if a Present can be done...\n");
5348 /* Source Rectangle must be full surface */
5349 if (src_rect.left || src_rect.top
5350 || src_rect.right != src_surface->resource.width
5351 || src_rect.bottom != src_surface->resource.height)
5353 TRACE("No, Source rectangle doesn't match\n");
5357 /* No stretching may occur */
5358 if(src_rect.right != dst_rect.right - dst_rect.left ||
5359 src_rect.bottom != dst_rect.bottom - dst_rect.top) {
5360 TRACE("No, stretching is done\n");
5364 /* Destination must be full surface or match the clipping rectangle */
5365 if (dst_surface->clipper && dst_surface->clipper->hWnd)
5369 GetClientRect(dst_surface->clipper->hWnd, &cliprect);
5370 pos[0].x = dst_rect.left;
5371 pos[0].y = dst_rect.top;
5372 pos[1].x = dst_rect.right;
5373 pos[1].y = dst_rect.bottom;
5374 MapWindowPoints(GetDesktopWindow(), dst_surface->clipper->hWnd, pos, 2);
5376 if(pos[0].x != cliprect.left || pos[0].y != cliprect.top ||
5377 pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
5379 TRACE("No, dest rectangle doesn't match(clipper)\n");
5380 TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect));
5381 TRACE("Blt dest: %s\n", wine_dbgstr_rect(&dst_rect));
5385 else if (dst_rect.left || dst_rect.top
5386 || dst_rect.right != dst_surface->resource.width
5387 || dst_rect.bottom != dst_surface->resource.height)
5389 TRACE("No, dest rectangle doesn't match(surface size)\n");
5395 /* These flags are unimportant for the flag check, remove them */
5396 if (!(flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)))
5398 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
5400 /* The idea behind this is that a glReadPixels and a glDrawPixels call
5401 * take very long, while a flip is fast.
5402 * This applies to Half-Life, which does such Blts every time it finished
5403 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
5404 * menu. This is also used by all apps when they do windowed rendering
5406 * The problem is that flipping is not really the same as copying. After a
5407 * Blt the front buffer is a copy of the back buffer, and the back buffer is
5408 * untouched. Therefore it's necessary to override the swap effect
5409 * and to set it back after the flip.
5411 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
5415 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
5416 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
5418 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead.\n");
5419 wined3d_swapchain_present(dstSwapchain, NULL, NULL, dstSwapchain->win_handle, NULL, 0);
5421 dstSwapchain->presentParms.SwapEffect = orig_swap;
5428 TRACE("Unsupported blit between buffers on the same swapchain\n");
5429 return WINED3DERR_INVALIDCALL;
5430 } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
5431 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5432 return WINED3DERR_INVALIDCALL;
5433 } else if(dstSwapchain && srcSwapchain) {
5434 FIXME("Implement hardware blit between two different swapchains\n");
5435 return WINED3DERR_INVALIDCALL;
5437 else if (dstSwapchain)
5439 /* Handled with regular texture -> swapchain blit */
5440 if (src_surface == device->render_targets[0])
5441 TRACE("Blit from active render target to a swapchain\n");
5443 else if (srcSwapchain && dst_surface == device->render_targets[0])
5445 FIXME("Implement blit from a swapchain to the active render target\n");
5446 return WINED3DERR_INVALIDCALL;
5449 if ((srcSwapchain || src_surface == device->render_targets[0]) && !dstSwapchain)
5451 /* Blit from render target to texture */
5454 /* P8 read back is not implemented */
5455 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5456 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5458 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5459 return WINED3DERR_INVALIDCALL;
5462 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5464 TRACE("Color keying not supported by frame buffer to texture blit\n");
5465 return WINED3DERR_INVALIDCALL;
5466 /* Destination color key is checked above */
5469 if(dst_rect.right - dst_rect.left != src_rect.right - src_rect.left) {
5475 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5476 * flip the image nor scale it.
5478 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5479 * -> If the app wants a image width an unscaled width, copy it line per line
5480 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5481 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5482 * back buffer. This is slower than reading line per line, thus not used for flipping
5483 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5486 * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
5487 * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
5489 if (fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5490 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5491 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5493 surface_blt_fbo(device, Filter,
5494 src_surface, SFLAG_INDRAWABLE, &src_rect,
5495 dst_surface, SFLAG_INDRAWABLE, &dst_rect);
5496 surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
5498 else if (!stretchx || dst_rect.right - dst_rect.left > src_surface->resource.width
5499 || dst_rect.bottom - dst_rect.top > src_surface->resource.height)
5501 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
5502 fb_copy_to_texture_direct(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
5504 TRACE("Using hardware stretching to flip / stretch the texture\n");
5505 fb_copy_to_texture_hwstretch(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
5508 if (!(dst_surface->flags & SFLAG_DONOTFREE))
5510 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5511 dst_surface->resource.allocatedMemory = NULL;
5512 dst_surface->resource.heapMemory = NULL;
5516 dst_surface->flags &= ~SFLAG_INSYSMEM;
5521 else if (src_surface)
5523 /* Blit from offscreen surface to render target */
5524 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5525 WINEDDCOLORKEY oldBltCKey = src_surface->SrcBltCKey;
5527 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5529 if (!(flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5530 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5531 &src_rect, src_surface->resource.usage, src_surface->resource.pool,
5532 src_surface->resource.format,
5533 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
5534 dst_surface->resource.format))
5536 TRACE("Using surface_blt_fbo.\n");
5537 /* The source is always a texture, but never the currently active render target, and the texture
5538 * contents are never upside down. */
5539 surface_blt_fbo(device, Filter,
5540 src_surface, SFLAG_INDRAWABLE, &src_rect,
5541 dst_surface, SFLAG_INDRAWABLE, &dst_rect);
5542 surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
5546 if (!(flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5547 && arbfp_blit.blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5548 &src_rect, src_surface->resource.usage, src_surface->resource.pool,
5549 src_surface->resource.format,
5550 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
5551 dst_surface->resource.format))
5553 return arbfp_blit_surface(device, src_surface, &src_rect, dst_surface, &dst_rect,
5554 WINED3D_BLIT_OP_COLOR_BLIT, Filter);
5557 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5558 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5559 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5561 FIXME("Unsupported blit operation falling back to software\n");
5562 return WINED3DERR_INVALIDCALL;
5565 /* Color keying: Check if we have to do a color keyed blt,
5566 * and if not check if a color key is activated.
5568 * Just modify the color keying parameters in the surface and restore them afterwards
5569 * The surface keeps track of the color key last used to load the opengl surface.
5570 * PreLoad will catch the change to the flags and color key and reload if necessary.
5572 if (flags & WINEDDBLT_KEYSRC)
5574 /* Use color key from surface */
5576 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5578 /* Use color key from DDBltFx */
5579 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5580 src_surface->SrcBltCKey = DDBltFx->ddckSrcColorkey;
5584 /* Do not use color key */
5585 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5588 surface_blt_to_drawable(device, Filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5589 src_surface, &src_rect, dst_surface, &dst_rect);
5591 /* Restore the color key parameters */
5592 src_surface->CKeyFlags = oldCKeyFlags;
5593 src_surface->SrcBltCKey = oldBltCKey;
5595 surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
5601 /* Source-Less Blit to render target */
5602 if (flags & WINEDDBLT_COLORFILL)
5604 WINED3DCOLORVALUE color;
5606 TRACE("Colorfill\n");
5608 /* The color as given in the Blt function is in the surface format. */
5609 if (!surface_convert_color_to_float(dst_surface, DDBltFx->u5.dwFillColor, &color))
5610 return WINED3DERR_INVALIDCALL;
5612 return surface_color_fill(dst_surface, &dst_rect, &color);
5616 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5617 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5618 return WINED3DERR_INVALIDCALL;
5621 /* GL locking is done by the caller */
5622 static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
5623 GLuint texture, GLsizei w, GLsizei h, GLenum target)
5625 IWineD3DDeviceImpl *device = This->resource.device;
5626 GLint compare_mode = GL_NONE;
5627 struct blt_info info;
5628 GLint old_binding = 0;
5631 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5633 glDisable(GL_CULL_FACE);
5634 glDisable(GL_BLEND);
5635 glDisable(GL_ALPHA_TEST);
5636 glDisable(GL_SCISSOR_TEST);
5637 glDisable(GL_STENCIL_TEST);
5638 glEnable(GL_DEPTH_TEST);
5639 glDepthFunc(GL_ALWAYS);
5640 glDepthMask(GL_TRUE);
5641 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5642 glViewport(0, This->pow2Height - h, w, h);
5644 SetRect(&rect, 0, h, w, 0);
5645 surface_get_blt_info(target, &rect, This->pow2Width, This->pow2Height, &info);
5646 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5647 glGetIntegerv(info.binding, &old_binding);
5648 glBindTexture(info.bind_target, texture);
5649 if (gl_info->supported[ARB_SHADOW])
5651 glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5652 if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5655 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5656 gl_info, info.tex_type, &This->ds_current_size);
5658 glBegin(GL_TRIANGLE_STRIP);
5659 glTexCoord3fv(info.coords[0]);
5660 glVertex2f(-1.0f, -1.0f);
5661 glTexCoord3fv(info.coords[1]);
5662 glVertex2f(1.0f, -1.0f);
5663 glTexCoord3fv(info.coords[2]);
5664 glVertex2f(-1.0f, 1.0f);
5665 glTexCoord3fv(info.coords[3]);
5666 glVertex2f(1.0f, 1.0f);
5669 if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5670 glBindTexture(info.bind_target, old_binding);
5674 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5677 void surface_modify_ds_location(IWineD3DSurfaceImpl *surface,
5678 DWORD location, UINT w, UINT h)
5680 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5682 if (location & ~SFLAG_DS_LOCATIONS)
5683 FIXME("Invalid location (%#x) specified.\n", location);
5685 surface->ds_current_size.cx = w;
5686 surface->ds_current_size.cy = h;
5687 surface->flags &= ~SFLAG_DS_LOCATIONS;
5688 surface->flags |= location;
5691 /* Context activation is done by the caller. */
5692 void surface_load_ds_location(IWineD3DSurfaceImpl *surface, struct wined3d_context *context, DWORD location)
5694 IWineD3DDeviceImpl *device = surface->resource.device;
5695 const struct wined3d_gl_info *gl_info = context->gl_info;
5698 TRACE("surface %p, new location %#x.\n", surface, location);
5700 /* TODO: Make this work for modes other than FBO */
5701 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5703 if (!(surface->flags & location))
5705 w = surface->ds_current_size.cx;
5706 h = surface->ds_current_size.cy;
5707 surface->ds_current_size.cx = 0;
5708 surface->ds_current_size.cy = 0;
5712 w = surface->resource.width;
5713 h = surface->resource.height;
5716 if (surface->ds_current_size.cx == surface->resource.width
5717 && surface->ds_current_size.cy == surface->resource.height)
5719 TRACE("Location (%#x) is already up to date.\n", location);
5723 if (surface->current_renderbuffer)
5725 FIXME("Not supported with fixed up depth stencil.\n");
5729 if (!(surface->flags & SFLAG_DS_LOCATIONS))
5731 /* This mostly happens when a depth / stencil is used without being
5732 * cleared first. In principle we could upload from sysmem, or
5733 * explicitly clear before first usage. For the moment there don't
5734 * appear to be a lot of applications depending on this, so a FIXME
5736 FIXME("No up to date depth stencil location.\n");
5737 surface->flags |= location;
5738 surface->ds_current_size.cx = surface->resource.width;
5739 surface->ds_current_size.cy = surface->resource.height;
5743 if (location == SFLAG_DS_OFFSCREEN)
5745 GLint old_binding = 0;
5748 /* The render target is allowed to be smaller than the depth/stencil
5749 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5750 * than the offscreen surface. Don't overwrite the offscreen surface
5751 * with undefined data. */
5752 w = min(w, context->swapchain->presentParms.BackBufferWidth);
5753 h = min(h, context->swapchain->presentParms.BackBufferHeight);
5755 TRACE("Copying onscreen depth buffer to depth texture.\n");
5759 if (!device->depth_blt_texture)
5761 glGenTextures(1, &device->depth_blt_texture);
5764 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5765 * directly on the FBO texture. That's because we need to flip. */
5766 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5767 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
5769 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5770 bind_target = GL_TEXTURE_RECTANGLE_ARB;
5774 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5775 bind_target = GL_TEXTURE_2D;
5777 glBindTexture(bind_target, device->depth_blt_texture);
5778 glCopyTexImage2D(bind_target, surface->texture_level, surface->resource.format->glInternal, 0, 0, w, h, 0);
5779 glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5780 glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5781 glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5782 glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5783 glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
5784 glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5785 glBindTexture(bind_target, old_binding);
5787 /* Setup the destination */
5788 if (!device->depth_blt_rb)
5790 gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
5791 checkGLcall("glGenRenderbuffersEXT");
5793 if (device->depth_blt_rb_w != w || device->depth_blt_rb_h != h)
5795 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
5796 checkGLcall("glBindRenderbufferEXT");
5797 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, w, h);
5798 checkGLcall("glRenderbufferStorageEXT");
5799 device->depth_blt_rb_w = w;
5800 device->depth_blt_rb_h = h;
5803 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5804 gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
5805 GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
5806 checkGLcall("glFramebufferRenderbufferEXT");
5807 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, surface, FALSE);
5809 /* Do the actual blit */
5810 surface_depth_blt(surface, gl_info, device->depth_blt_texture, w, h, bind_target);
5811 checkGLcall("depth_blt");
5813 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
5814 else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5818 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5820 else if (location == SFLAG_DS_ONSCREEN)
5822 TRACE("Copying depth texture to onscreen depth buffer.\n");
5826 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5827 surface_depth_blt(surface, gl_info, surface->texture_name,
5828 w, h, surface->texture_target);
5829 checkGLcall("depth_blt");
5831 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
5835 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5839 ERR("Invalid location (%#x) specified.\n", location);
5842 surface->flags |= location;
5843 surface->ds_current_size.cx = surface->resource.width;
5844 surface->ds_current_size.cy = surface->resource.height;
5847 void surface_modify_location(IWineD3DSurfaceImpl *surface, DWORD flag, BOOL persistent)
5849 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
5850 IWineD3DSurfaceImpl *overlay;
5852 TRACE("surface %p, location %s, persistent %#x.\n",
5853 surface, debug_surflocation(flag), persistent);
5855 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5857 if (surface_is_offscreen(surface))
5859 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
5860 if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
5864 TRACE("Surface %p is an onscreen surface.\n", surface);
5868 if (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
5869 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
5871 flag |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
5876 if (((surface->flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE))
5877 || ((surface->flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX)))
5879 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5881 TRACE("Passing to container.\n");
5882 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5885 surface->flags &= ~SFLAG_LOCATIONS;
5886 surface->flags |= flag;
5888 /* Redraw emulated overlays, if any */
5889 if (flag & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
5891 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, IWineD3DSurfaceImpl, overlay_entry)
5893 overlay->surface_ops->surface_draw_overlay(overlay);
5899 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
5901 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5903 TRACE("Passing to container\n");
5904 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5907 surface->flags &= ~flag;
5910 if (!(surface->flags & SFLAG_LOCATIONS))
5912 ERR("Surface %p does not have any up to date location.\n", surface);
5916 HRESULT surface_load_location(IWineD3DSurfaceImpl *surface, DWORD flag, const RECT *rect)
5918 IWineD3DDeviceImpl *device = surface->resource.device;
5919 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5920 BOOL drawable_read_ok = surface_is_offscreen(surface);
5921 struct wined3d_format format;
5922 CONVERT_TYPES convert;
5923 int width, pitch, outpitch;
5925 BOOL in_fbo = FALSE;
5927 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(flag), wine_dbgstr_rect(rect));
5929 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
5931 if (flag == SFLAG_INTEXTURE)
5933 struct wined3d_context *context = context_acquire(device, NULL);
5934 surface_load_ds_location(surface, context, SFLAG_DS_OFFSCREEN);
5935 context_release(context);
5940 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(flag));
5941 return WINED3DERR_INVALIDCALL;
5945 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5947 if (surface_is_offscreen(surface))
5949 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
5950 * Prefer SFLAG_INTEXTURE. */
5951 if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
5952 drawable_read_ok = FALSE;
5957 TRACE("Surface %p is an onscreen surface.\n", surface);
5961 if (flag == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
5963 flag = SFLAG_INTEXTURE;
5966 if (surface->flags & flag)
5968 TRACE("Location already up to date\n");
5972 if (!(surface->flags & SFLAG_LOCATIONS))
5974 ERR("Surface %p does not have any up to date location.\n", surface);
5975 surface->flags |= SFLAG_LOST;
5976 return WINED3DERR_DEVICELOST;
5979 if (flag == SFLAG_INSYSMEM)
5981 surface_prepare_system_memory(surface);
5983 /* Download the surface to system memory */
5984 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
5986 struct wined3d_context *context = NULL;
5988 if (!device->isInDraw) context = context_acquire(device, NULL);
5990 surface_bind_and_dirtify(surface, gl_info, !(surface->flags & SFLAG_INTEXTURE));
5991 surface_download_data(surface, gl_info);
5993 if (context) context_release(context);
5997 /* Note: It might be faster to download into a texture first. */
5998 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
5999 IWineD3DSurface_GetPitch((IWineD3DSurface *)surface));
6002 else if (flag == SFLAG_INDRAWABLE)
6004 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
6005 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6007 if (surface->flags & SFLAG_INTEXTURE)
6011 surface_get_rect(surface, rect, &r);
6012 surface_blt_to_drawable(device, WINED3DTEXF_POINT, FALSE, surface, &r, surface, &r);
6017 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
6019 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
6020 * values, otherwise we get incorrect values in the target. For now go the slow way
6021 * via a system memory copy
6023 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6026 d3dfmt_get_conv(surface, FALSE /* We need color keying */,
6027 FALSE /* We won't use textures */, &format, &convert);
6029 /* The width is in 'length' not in bytes */
6030 width = surface->resource.width;
6031 pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
6033 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
6034 * but it isn't set (yet) in all cases it is getting called. */
6035 if ((convert != NO_CONVERSION) && (surface->flags & SFLAG_PBO))
6037 struct wined3d_context *context = NULL;
6039 TRACE("Removing the pbo attached to surface %p.\n", surface);
6041 if (!device->isInDraw) context = context_acquire(device, NULL);
6042 surface_remove_pbo(surface, gl_info);
6043 if (context) context_release(context);
6046 if ((convert != NO_CONVERSION) && surface->resource.allocatedMemory)
6048 int height = surface->resource.height;
6049 byte_count = format.conv_byte_count;
6051 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6052 outpitch = width * byte_count;
6053 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6055 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6057 ERR("Out of memory %d, %d!\n", outpitch, height);
6058 return WINED3DERR_OUTOFVIDEOMEMORY;
6060 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, pitch,
6061 width, height, outpitch, convert, surface);
6063 surface->flags |= SFLAG_CONVERTED;
6067 surface->flags &= ~SFLAG_CONVERTED;
6068 mem = surface->resource.allocatedMemory;
6069 byte_count = format.byte_count;
6072 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6074 /* Don't delete PBO memory */
6075 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6076 HeapFree(GetProcessHeap(), 0, mem);
6079 else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */
6081 const DWORD attach_flags = WINED3DFMT_FLAG_FBO_ATTACHABLE | WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB;
6083 if (drawable_read_ok && (surface->flags & SFLAG_INDRAWABLE))
6085 read_from_framebuffer_texture(surface, flag == SFLAG_INSRGBTEX);
6087 else if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6088 && (surface->resource.format->flags & attach_flags) == attach_flags
6089 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6090 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6091 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6093 DWORD src_location = flag == SFLAG_INSRGBTEX ? SFLAG_INTEXTURE : SFLAG_INSRGBTEX;
6094 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6096 surface_blt_fbo(surface->resource.device, WINED3DTEXF_POINT,
6097 surface, src_location, &rect, surface, flag, &rect);
6101 /* Upload from system memory */
6102 BOOL srgb = flag == SFLAG_INSRGBTEX;
6103 struct wined3d_context *context = NULL;
6105 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6106 TRUE /* We will use textures */, &format, &convert);
6110 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6112 /* Performance warning... */
6113 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6114 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6119 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6121 /* Performance warning... */
6122 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6123 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6126 if (!(surface->flags & SFLAG_INSYSMEM))
6128 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6129 /* Lets hope we get it from somewhere... */
6130 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6133 if (!device->isInDraw) context = context_acquire(device, NULL);
6135 surface_prepare_texture(surface, gl_info, srgb);
6136 surface_bind_and_dirtify(surface, gl_info, srgb);
6138 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6140 surface->flags |= SFLAG_GLCKEY;
6141 surface->glCKey = surface->SrcBltCKey;
6143 else surface->flags &= ~SFLAG_GLCKEY;
6145 /* The width is in 'length' not in bytes */
6146 width = surface->resource.width;
6147 pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
6149 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
6150 * but it isn't set (yet) in all cases it is getting called. */
6151 if ((convert != NO_CONVERSION || format.convert) && (surface->flags & SFLAG_PBO))
6153 TRACE("Removing the pbo attached to surface %p.\n", surface);
6154 surface_remove_pbo(surface, gl_info);
6159 /* This code is entered for texture formats which need a fixup. */
6160 UINT height = surface->resource.height;
6162 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6163 outpitch = width * format.conv_byte_count;
6164 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6166 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6168 ERR("Out of memory %d, %d!\n", outpitch, height);
6169 if (context) context_release(context);
6170 return WINED3DERR_OUTOFVIDEOMEMORY;
6172 format.convert(surface->resource.allocatedMemory, mem, pitch, width, height);
6174 else if (convert != NO_CONVERSION && surface->resource.allocatedMemory)
6176 /* This code is only entered for color keying fixups */
6177 UINT height = surface->resource.height;
6179 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6180 outpitch = width * format.conv_byte_count;
6181 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6183 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6185 ERR("Out of memory %d, %d!\n", outpitch, height);
6186 if (context) context_release(context);
6187 return WINED3DERR_OUTOFVIDEOMEMORY;
6189 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, pitch,
6190 width, height, outpitch, convert, surface);
6194 mem = surface->resource.allocatedMemory;
6197 /* Make sure the correct pitch is used */
6199 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
6202 if (mem || (surface->flags & SFLAG_PBO))
6203 surface_upload_data(surface, gl_info, &format, srgb, mem);
6205 /* Restore the default pitch */
6207 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
6210 if (context) context_release(context);
6212 /* Don't delete PBO memory */
6213 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6214 HeapFree(GetProcessHeap(), 0, mem);
6220 surface->flags |= flag;
6222 if (flag != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6223 surface_evict_sysmem(surface);
6226 if (in_fbo && (surface->flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)))
6228 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
6229 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
6232 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6233 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6235 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6241 BOOL surface_is_offscreen(IWineD3DSurfaceImpl *surface)
6243 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6245 /* Not on a swapchain - must be offscreen */
6246 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6248 /* The front buffer is always onscreen */
6249 if (surface == swapchain->front_buffer) return FALSE;
6251 /* If the swapchain is rendered to an FBO, the backbuffer is
6252 * offscreen, otherwise onscreen */
6253 return swapchain->render_to_fbo;
6256 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
6259 IWineD3DBaseSurfaceImpl_QueryInterface,
6260 IWineD3DBaseSurfaceImpl_AddRef,
6261 IWineD3DBaseSurfaceImpl_Release,
6262 /* IWineD3DResource */
6263 IWineD3DBaseSurfaceImpl_GetParent,
6264 IWineD3DBaseSurfaceImpl_SetPrivateData,
6265 IWineD3DBaseSurfaceImpl_GetPrivateData,
6266 IWineD3DBaseSurfaceImpl_FreePrivateData,
6267 IWineD3DBaseSurfaceImpl_SetPriority,
6268 IWineD3DBaseSurfaceImpl_GetPriority,
6269 IWineD3DBaseSurfaceImpl_PreLoad,
6270 /* IWineD3DSurface */
6271 IWineD3DBaseSurfaceImpl_GetResource,
6272 IWineD3DBaseSurfaceImpl_Map,
6273 IWineD3DBaseSurfaceImpl_Unmap,
6274 IWineD3DBaseSurfaceImpl_GetDC,
6275 IWineD3DBaseSurfaceImpl_ReleaseDC,
6276 IWineD3DBaseSurfaceImpl_Flip,
6277 IWineD3DBaseSurfaceImpl_Blt,
6278 IWineD3DBaseSurfaceImpl_GetBltStatus,
6279 IWineD3DBaseSurfaceImpl_GetFlipStatus,
6280 IWineD3DBaseSurfaceImpl_IsLost,
6281 IWineD3DBaseSurfaceImpl_Restore,
6282 IWineD3DBaseSurfaceImpl_BltFast,
6283 IWineD3DBaseSurfaceImpl_GetPalette,
6284 IWineD3DBaseSurfaceImpl_SetPalette,
6285 IWineD3DBaseSurfaceImpl_SetColorKey,
6286 IWineD3DBaseSurfaceImpl_GetPitch,
6287 IWineD3DBaseSurfaceImpl_SetMem,
6288 IWineD3DBaseSurfaceImpl_SetOverlayPosition,
6289 IWineD3DBaseSurfaceImpl_GetOverlayPosition,
6290 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
6291 IWineD3DBaseSurfaceImpl_UpdateOverlay,
6292 IWineD3DBaseSurfaceImpl_SetClipper,
6293 IWineD3DBaseSurfaceImpl_GetClipper,
6295 IWineD3DBaseSurfaceImpl_SetFormat,
6298 static HRESULT ffp_blit_alloc(IWineD3DDeviceImpl *device) { return WINED3D_OK; }
6299 /* Context activation is done by the caller. */
6300 static void ffp_blit_free(IWineD3DDeviceImpl *device) { }
6302 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6303 /* Context activation is done by the caller. */
6304 static void ffp_blit_p8_upload_palette(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
6307 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
6309 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6311 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6313 GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6317 /* Context activation is done by the caller. */
6318 static HRESULT ffp_blit_set(void *blit_priv, const struct wined3d_gl_info *gl_info, IWineD3DSurfaceImpl *surface)
6320 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6322 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6323 * else the surface is converted in software at upload time in LoadLocation.
6325 if(fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6326 ffp_blit_p8_upload_palette(surface, gl_info);
6329 glEnable(surface->texture_target);
6330 checkGLcall("glEnable(surface->texture_target)");
6335 /* Context activation is done by the caller. */
6336 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6339 glDisable(GL_TEXTURE_2D);
6340 checkGLcall("glDisable(GL_TEXTURE_2D)");
6341 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6343 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6344 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6346 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6348 glDisable(GL_TEXTURE_RECTANGLE_ARB);
6349 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6354 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6355 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
6356 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
6358 enum complex_fixup src_fixup;
6362 case WINED3D_BLIT_OP_COLOR_BLIT:
6363 src_fixup = get_complex_fixup(src_format->color_fixup);
6364 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6366 TRACE("Checking support for fixup:\n");
6367 dump_color_fixup_desc(src_format->color_fixup);
6370 if (!is_identity_fixup(dst_format->color_fixup))
6372 TRACE("Destination fixups are not supported\n");
6376 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6378 TRACE("P8 fixup supported\n");
6382 /* We only support identity conversions. */
6383 if (is_identity_fixup(src_format->color_fixup))
6389 TRACE("[FAILED]\n");
6392 case WINED3D_BLIT_OP_COLOR_FILL:
6393 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6395 TRACE("Color fill not supported\n");
6401 case WINED3D_BLIT_OP_DEPTH_FILL:
6405 TRACE("Unsupported blit_op=%d\n", blit_op);
6410 /* Do not call while under the GL lock. */
6411 static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface,
6412 const RECT *dst_rect, const WINED3DCOLORVALUE *color)
6414 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6416 return device_clear_render_targets(device, 1, &dst_surface, NULL,
6417 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6420 /* Do not call while under the GL lock. */
6421 static HRESULT ffp_blit_depth_fill(IWineD3DDeviceImpl *device,
6422 IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
6424 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6426 return device_clear_render_targets(device, 0, NULL, surface,
6427 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6430 const struct blit_shader ffp_blit = {
6436 ffp_blit_color_fill,
6437 ffp_blit_depth_fill,
6440 static HRESULT cpu_blit_alloc(IWineD3DDeviceImpl *device)
6445 /* Context activation is done by the caller. */
6446 static void cpu_blit_free(IWineD3DDeviceImpl *device)
6450 /* Context activation is done by the caller. */
6451 static HRESULT cpu_blit_set(void *blit_priv, const struct wined3d_gl_info *gl_info, IWineD3DSurfaceImpl *surface)
6456 /* Context activation is done by the caller. */
6457 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6461 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6462 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
6463 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
6465 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6473 static HRESULT surface_cpu_blt(IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect,
6474 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD flags,
6475 const WINEDDBLTFX *fx, WINED3DTEXTUREFILTERTYPE filter)
6477 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
6478 const struct wined3d_format *src_format, *dst_format;
6479 IWineD3DSurfaceImpl *orig_src = src_surface;
6480 WINED3DLOCKED_RECT dlock, slock;
6481 HRESULT hr = WINED3D_OK;
6487 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6488 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
6489 flags, fx, debug_d3dtexturefiltertype(filter));
6491 if ((dst_surface->flags & SFLAG_LOCKED) || (src_surface && (src_surface->flags & SFLAG_LOCKED)))
6493 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY\n");
6494 return WINEDDERR_SURFACEBUSY;
6497 /* First check for the validity of source / destination rectangles.
6498 * This was verified using a test application and by MSDN. */
6503 if (src_rect->right < src_rect->left || src_rect->bottom < src_rect->top
6504 || src_rect->left > src_surface->resource.width || src_rect->left < 0
6505 || src_rect->top > src_surface->resource.height || src_rect->top < 0
6506 || src_rect->right > src_surface->resource.width || src_rect->right < 0
6507 || src_rect->bottom > src_surface->resource.height || src_rect->bottom < 0)
6509 WARN("Application gave us bad source rectangle for Blt.\n");
6510 return WINEDDERR_INVALIDRECT;
6513 if (!src_rect->right || !src_rect->bottom
6514 || src_rect->left == (int)src_surface->resource.width
6515 || src_rect->top == (int)src_surface->resource.height)
6517 TRACE("Nothing to be done.\n");
6524 else if (src_surface)
6528 xsrc.right = src_surface->resource.width;
6529 xsrc.bottom = src_surface->resource.height;
6533 memset(&xsrc, 0, sizeof(xsrc));
6538 /* For the Destination rect, it can be out of bounds on the condition
6539 * that a clipper is set for the given surface. */
6540 if (!dst_surface->clipper && (dst_rect->right < dst_rect->left || dst_rect->bottom < dst_rect->top
6541 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
6542 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
6543 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
6544 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0))
6546 WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
6547 return WINEDDERR_INVALIDRECT;
6550 if (dst_rect->right <= 0 || dst_rect->bottom <= 0
6551 || dst_rect->left >= (int)dst_surface->resource.width
6552 || dst_rect->top >= (int)dst_surface->resource.height)
6554 TRACE("Nothing to be done.\n");
6564 full_rect.right = dst_surface->resource.width;
6565 full_rect.bottom = dst_surface->resource.height;
6566 IntersectRect(&xdst, &full_rect, dst_rect);
6570 BOOL clip_horiz, clip_vert;
6573 clip_horiz = xdst.left < 0 || xdst.right > (int)dst_surface->resource.width;
6574 clip_vert = xdst.top < 0 || xdst.bottom > (int)dst_surface->resource.height;
6576 if (clip_vert || clip_horiz)
6578 /* Now check if this is a special case or not... */
6579 if ((flags & WINEDDBLT_DDFX)
6580 || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
6581 || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
6583 WARN("Out of screen rectangle in special case. Not handled right now.\n");
6591 xsrc.left -= xdst.left;
6594 if (xdst.right > dst_surface->resource.width)
6596 xsrc.right -= (xdst.right - (int)dst_surface->resource.width);
6597 xdst.right = (int)dst_surface->resource.width;
6605 xsrc.top -= xdst.top;
6608 if (xdst.bottom > dst_surface->resource.height)
6610 xsrc.bottom -= (xdst.bottom - (int)dst_surface->resource.height);
6611 xdst.bottom = (int)dst_surface->resource.height;
6615 /* And check if after clipping something is still to be done... */
6616 if ((xdst.right <= 0) || (xdst.bottom <= 0)
6617 || (xdst.left >= (int)dst_surface->resource.width)
6618 || (xdst.top >= (int)dst_surface->resource.height)
6619 || (xsrc.right <= 0) || (xsrc.bottom <= 0)
6620 || (xsrc.left >= (int)src_surface->resource.width)
6621 || (xsrc.top >= (int)src_surface->resource.height))
6623 TRACE("Nothing to be done after clipping.\n");
6633 xdst.right = dst_surface->resource.width;
6634 xdst.bottom = dst_surface->resource.height;
6637 if (src_surface == dst_surface)
6639 IWineD3DSurface_Map((IWineD3DSurface *)dst_surface, &dlock, NULL, 0);
6641 src_format = dst_surface->resource.format;
6642 dst_format = src_format;
6646 dst_format = dst_surface->resource.format;
6649 if (dst_surface->resource.format->id != src_surface->resource.format->id)
6651 src_surface = surface_convert_format(src_surface, dst_format->id);
6654 /* The conv function writes a FIXME */
6655 WARN("Cannot convert source surface format to dest format.\n");
6659 IWineD3DSurface_Map((IWineD3DSurface *)src_surface, &slock, NULL, WINED3DLOCK_READONLY);
6660 src_format = src_surface->resource.format;
6664 src_format = dst_format;
6667 IWineD3DSurface_Map((IWineD3DSurface *)dst_surface, &dlock, &xdst, 0);
6669 IWineD3DSurface_Map((IWineD3DSurface *)dst_surface, &dlock, NULL, 0);
6672 if (!fx || !(fx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
6674 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_FOURCC)
6676 if (!dst_rect || src_surface == dst_surface)
6678 memcpy(dlock.pBits, slock.pBits, dst_surface->resource.size);
6683 bpp = dst_surface->resource.format->byte_count;
6684 srcheight = xsrc.bottom - xsrc.top;
6685 srcwidth = xsrc.right - xsrc.left;
6686 dstheight = xdst.bottom - xdst.top;
6687 dstwidth = xdst.right - xdst.left;
6688 width = (xdst.right - xdst.left) * bpp;
6690 if (dst_rect && src_surface != dst_surface)
6693 dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
6695 if (flags & WINEDDBLT_WAIT)
6697 flags &= ~WINEDDBLT_WAIT;
6699 if (flags & WINEDDBLT_ASYNC)
6701 static BOOL displayed = FALSE;
6703 FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
6705 flags &= ~WINEDDBLT_ASYNC;
6707 if (flags & WINEDDBLT_DONOTWAIT)
6709 /* WINEDDBLT_DONOTWAIT appeared in DX7 */
6710 static BOOL displayed = FALSE;
6712 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
6714 flags &= ~WINEDDBLT_DONOTWAIT;
6717 /* First, all the 'source-less' blits */
6718 if (flags & WINEDDBLT_COLORFILL)
6720 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dlock.Pitch, fx->u5.dwFillColor);
6721 flags &= ~WINEDDBLT_COLORFILL;
6724 if (flags & WINEDDBLT_DEPTHFILL)
6726 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6728 if (flags & WINEDDBLT_ROP)
6730 /* Catch some degenerate cases here. */
6734 hr = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
6736 case 0xAA0029: /* No-op */
6739 hr = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
6741 case SRCCOPY: /* Well, we do that below? */
6744 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
6747 flags &= ~WINEDDBLT_ROP;
6749 if (flags & WINEDDBLT_DDROPS)
6751 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
6753 /* Now the 'with source' blits. */
6757 int sx, xinc, sy, yinc;
6759 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
6762 if (filter != WINED3DTEXF_NONE && filter != WINED3DTEXF_POINT
6763 && (srcwidth != dstwidth || srcheight != dstheight))
6765 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6766 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
6769 sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
6770 xinc = (srcwidth << 16) / dstwidth;
6771 yinc = (srcheight << 16) / dstheight;
6775 /* No effects, we can cheat here. */
6776 if (dstwidth == srcwidth)
6778 if (dstheight == srcheight)
6780 /* No stretching in either direction. This needs to be as
6781 * fast as possible. */
6784 /* Check for overlapping surfaces. */
6785 if (src_surface != dst_surface || xdst.top < xsrc.top
6786 || xdst.right <= xsrc.left || xsrc.right <= xdst.left)
6788 /* No overlap, or dst above src, so copy from top downwards. */
6789 for (y = 0; y < dstheight; ++y)
6791 memcpy(dbuf, sbuf, width);
6792 sbuf += slock.Pitch;
6793 dbuf += dlock.Pitch;
6796 else if (xdst.top > xsrc.top)
6798 /* Copy from bottom upwards. */
6799 sbuf += (slock.Pitch*dstheight);
6800 dbuf += (dlock.Pitch*dstheight);
6801 for (y = 0; y < dstheight; ++y)
6803 sbuf -= slock.Pitch;
6804 dbuf -= dlock.Pitch;
6805 memcpy(dbuf, sbuf, width);
6810 /* Src and dst overlapping on the same line, use memmove. */
6811 for (y = 0; y < dstheight; ++y)
6813 memmove(dbuf, sbuf, width);
6814 sbuf += slock.Pitch;
6815 dbuf += dlock.Pitch;
6821 /* Stretching in y direction only. */
6822 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6824 sbuf = sbase + (sy >> 16) * slock.Pitch;
6825 memcpy(dbuf, sbuf, width);
6826 dbuf += dlock.Pitch;
6832 /* Stretching in X direction. */
6834 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6836 sbuf = sbase + (sy >> 16) * slock.Pitch;
6838 if ((sy >> 16) == (last_sy >> 16))
6840 /* This source row is the same as last source row -
6841 * Copy the already stretched row. */
6842 memcpy(dbuf, dbuf - dlock.Pitch, width);
6846 #define STRETCH_ROW(type) \
6848 const type *s = (const type *)sbuf; \
6849 type *d = (type *)dbuf; \
6850 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6851 d[x] = s[sx >> 16]; \
6869 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
6873 s = sbuf + 3 * (sx >> 16);
6874 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
6875 d[0] = (pixel ) & 0xff;
6876 d[1] = (pixel >> 8) & 0xff;
6877 d[2] = (pixel >> 16) & 0xff;
6883 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
6884 hr = WINED3DERR_NOTAVAILABLE;
6889 dbuf += dlock.Pitch;
6896 LONG dstyinc = dlock.Pitch, dstxinc = bpp;
6897 DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
6898 DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
6899 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
6901 /* The color keying flags are checked for correctness in ddraw */
6902 if (flags & WINEDDBLT_KEYSRC)
6904 keylow = src_surface->SrcBltCKey.dwColorSpaceLowValue;
6905 keyhigh = src_surface->SrcBltCKey.dwColorSpaceHighValue;
6907 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6909 keylow = fx->ddckSrcColorkey.dwColorSpaceLowValue;
6910 keyhigh = fx->ddckSrcColorkey.dwColorSpaceHighValue;
6913 if (flags & WINEDDBLT_KEYDEST)
6915 /* Destination color keys are taken from the source surface! */
6916 destkeylow = src_surface->DestBltCKey.dwColorSpaceLowValue;
6917 destkeyhigh = src_surface->DestBltCKey.dwColorSpaceHighValue;
6919 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
6921 destkeylow = fx->ddckDestColorkey.dwColorSpaceLowValue;
6922 destkeyhigh = fx->ddckDestColorkey.dwColorSpaceHighValue;
6931 keymask = src_format->red_mask
6932 | src_format->green_mask
6933 | src_format->blue_mask;
6935 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
6938 if (flags & WINEDDBLT_DDFX)
6940 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
6943 dTopRight = dbuf + ((dstwidth - 1) * bpp);
6944 dBottomLeft = dTopLeft + ((dstheight - 1) * dlock.Pitch);
6945 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
6947 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
6949 /* I don't think we need to do anything about this flag */
6950 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6952 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
6955 dTopRight = dTopLeft;
6958 dBottomRight = dBottomLeft;
6960 dstxinc = dstxinc * -1;
6962 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
6965 dTopLeft = dBottomLeft;
6968 dTopRight = dBottomRight;
6970 dstyinc = dstyinc * -1;
6972 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
6974 /* I don't think we need to do anything about this flag */
6975 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
6977 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
6980 dBottomRight = dTopLeft;
6983 dBottomLeft = dTopRight;
6985 dstxinc = dstxinc * -1;
6986 dstyinc = dstyinc * -1;
6988 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
6991 dTopLeft = dBottomLeft;
6992 dBottomLeft = dBottomRight;
6993 dBottomRight = dTopRight;
6998 dstxinc = dstxinc * -1;
7000 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7003 dTopLeft = dTopRight;
7004 dTopRight = dBottomRight;
7005 dBottomRight = dBottomLeft;
7010 dstyinc = dstyinc * -1;
7012 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7014 /* I don't think we need to do anything about this flag */
7015 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7018 flags &= ~(WINEDDBLT_DDFX);
7021 #define COPY_COLORKEY_FX(type) \
7024 type *d = (type *)dbuf, *dx, tmp; \
7025 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7027 s = (const type *)(sbase + (sy >> 16) * slock.Pitch); \
7029 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7031 tmp = s[sx >> 16]; \
7032 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7033 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7037 dx = (type *)(((BYTE *)dx) + dstxinc); \
7039 d = (type *)(((BYTE *)d) + dstyinc); \
7046 COPY_COLORKEY_FX(BYTE);
7049 COPY_COLORKEY_FX(WORD);
7052 COPY_COLORKEY_FX(DWORD);
7057 BYTE *d = dbuf, *dx;
7058 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7060 sbuf = sbase + (sy >> 16) * slock.Pitch;
7062 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7064 DWORD pixel, dpixel = 0;
7065 s = sbuf + 3 * (sx>>16);
7066 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7067 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7068 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7069 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7071 dx[0] = (pixel ) & 0xff;
7072 dx[1] = (pixel >> 8) & 0xff;
7073 dx[2] = (pixel >> 16) & 0xff;
7082 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7083 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7084 hr = WINED3DERR_NOTAVAILABLE;
7086 #undef COPY_COLORKEY_FX
7092 if (flags && FIXME_ON(d3d_surface))
7094 FIXME("\tUnsupported flags: %#x.\n", flags);
7098 IWineD3DSurface_Unmap((IWineD3DSurface *)dst_surface);
7099 if (src_surface && src_surface != dst_surface)
7100 IWineD3DSurface_Unmap((IWineD3DSurface *)src_surface);
7101 /* Release the converted surface, if any. */
7102 if (src_surface && src_surface != orig_src)
7103 IWineD3DSurface_Release((IWineD3DSurface *)src_surface);
7108 static HRESULT surface_cpu_bltfast(IWineD3DSurfaceImpl *dst_surface, DWORD dst_x, DWORD dst_y,
7109 IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, DWORD trans)
7111 const struct wined3d_format *src_format, *dst_format;
7112 RECT lock_src, lock_dst, lock_union;
7113 WINED3DLOCKED_RECT dlock, slock;
7114 HRESULT hr = WINED3D_OK;
7115 int bpp, w, h, x, y;
7120 TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
7121 dst_surface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect), trans);
7123 if ((dst_surface->flags & SFLAG_LOCKED) || (src_surface->flags & SFLAG_LOCKED))
7125 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
7126 return WINEDDERR_SURFACEBUSY;
7131 WARN("src_rect is NULL!\n");
7134 rsrc2.right = src_surface->resource.width;
7135 rsrc2.bottom = src_surface->resource.height;
7139 /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate. */
7140 if ((src_rect->bottom > src_surface->resource.height) || (src_rect->bottom < 0)
7141 || (src_rect->top > src_surface->resource.height) || (src_rect->top < 0)
7142 || (src_rect->left > src_surface->resource.width) || (src_rect->left < 0)
7143 || (src_rect->right > src_surface->resource.width) || (src_rect->right < 0)
7144 || (src_rect->right < src_rect->left) || (src_rect->bottom < src_rect->top))
7146 WARN("Application gave us bad source rectangle for BltFast.\n");
7147 return WINEDDERR_INVALIDRECT;
7150 h = src_rect->bottom - src_rect->top;
7151 if (h > dst_surface->resource.height - dst_y)
7152 h = dst_surface->resource.height - dst_y;
7153 if (h > src_surface->resource.height - src_rect->top)
7154 h = src_surface->resource.height - src_rect->top;
7156 return WINEDDERR_INVALIDRECT;
7158 w = src_rect->right - src_rect->left;
7159 if (w > dst_surface->resource.width - dst_x)
7160 w = dst_surface->resource.width - dst_x;
7161 if (w > src_surface->resource.width - src_rect->left)
7162 w = src_surface->resource.width - src_rect->left;
7164 return WINEDDERR_INVALIDRECT;
7166 /* Now compute the locking rectangle... */
7167 lock_src.left = src_rect->left;
7168 lock_src.top = src_rect->top;
7169 lock_src.right = lock_src.left + w;
7170 lock_src.bottom = lock_src.top + h;
7172 lock_dst.left = dst_x;
7173 lock_dst.top = dst_y;
7174 lock_dst.right = dst_x + w;
7175 lock_dst.bottom = dst_y + h;
7177 bpp = dst_surface->resource.format->byte_count;
7179 /* We need to lock the surfaces, or we won't get refreshes when done. */
7180 if (src_surface == dst_surface)
7184 UnionRect(&lock_union, &lock_src, &lock_dst);
7186 /* Lock the union of the two rectangles */
7187 hr = IWineD3DSurface_Map((IWineD3DSurface *)dst_surface, &dlock, &lock_union, 0);
7191 pitch = dlock.Pitch;
7192 slock.Pitch = dlock.Pitch;
7194 /* Since slock was originally copied from this surface's description, we can just reuse it. */
7195 sbuf = dst_surface->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
7196 dbuf = dst_surface->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
7197 src_format = src_surface->resource.format;
7198 dst_format = src_format;
7202 hr = IWineD3DSurface_Map((IWineD3DSurface *)src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
7205 hr = IWineD3DSurface_Map((IWineD3DSurface *)dst_surface, &dlock, &lock_dst, 0);
7211 TRACE("Dst is at %p, Src is at %p.\n", dbuf, sbuf);
7213 src_format = src_surface->resource.format;
7214 dst_format = dst_surface->resource.format;
7217 /* Handle compressed surfaces first... */
7218 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
7220 UINT row_block_count;
7222 TRACE("compressed -> compressed copy\n");
7224 FIXME("trans arg not supported when a compressed surface is involved\n");
7226 FIXME("offset for destination surface is not supported\n");
7227 if (src_surface->resource.format->id != dst_surface->resource.format->id)
7229 FIXME("compressed -> compressed copy only supported for the same type of surface\n");
7230 hr = WINED3DERR_WRONGTEXTUREFORMAT;
7234 row_block_count = (w + dst_format->block_width - 1) / dst_format->block_width;
7235 for (y = 0; y < h; y += dst_format->block_height)
7237 memcpy(dbuf, sbuf, row_block_count * dst_format->block_byte_count);
7238 dbuf += dlock.Pitch;
7239 sbuf += slock.Pitch;
7244 if ((src_format->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dst_format->flags & WINED3DFMT_FLAG_COMPRESSED))
7246 /* TODO: Use the libtxc_dxtn.so shared library to do software
7248 ERR("Software decompression not supported.\n");
7252 if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
7254 DWORD keylow, keyhigh;
7255 DWORD mask = src_surface->resource.format->red_mask
7256 | src_surface->resource.format->green_mask
7257 | src_surface->resource.format->blue_mask;
7259 /* For some 8-bit formats like L8 and P8 color masks don't make sense */
7260 if (!mask && bpp == 1)
7263 TRACE("Color keyed copy.\n");
7264 if (trans & WINEDDBLTFAST_SRCCOLORKEY)
7266 keylow = src_surface->SrcBltCKey.dwColorSpaceLowValue;
7267 keyhigh = src_surface->SrcBltCKey.dwColorSpaceHighValue;
7271 /* I'm not sure if this is correct. */
7272 FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
7273 keylow = dst_surface->DestBltCKey.dwColorSpaceLowValue;
7274 keyhigh = dst_surface->DestBltCKey.dwColorSpaceHighValue;
7277 #define COPYBOX_COLORKEY(type) \
7279 const type *s = (const type *)sbuf; \
7280 type *d = (type *)dbuf; \
7282 for (y = 0; y < h; y++) \
7284 for (x = 0; x < w; x++) \
7287 if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
7289 s = (const type *)((const BYTE *)s + slock.Pitch); \
7290 d = (type *)((BYTE *)d + dlock.Pitch); \
7297 COPYBOX_COLORKEY(BYTE);
7300 COPYBOX_COLORKEY(WORD);
7303 COPYBOX_COLORKEY(DWORD);
7312 for (y = 0; y < h; ++y)
7314 for (x = 0; x < w * 3; x += 3)
7316 tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
7317 if (tmp < keylow || tmp > keyhigh)
7319 d[x + 0] = s[x + 0];
7320 d[x + 1] = s[x + 1];
7321 d[x + 2] = s[x + 2];
7330 FIXME("Source color key blitting not supported for bpp %u.\n", bpp * 8);
7331 hr = WINED3DERR_NOTAVAILABLE;
7334 #undef COPYBOX_COLORKEY
7335 TRACE("Copy done.\n");
7339 int width = w * bpp;
7340 INT sbufpitch, dbufpitch;
7342 TRACE("No color key copy.\n");
7343 /* Handle overlapping surfaces. */
7346 sbuf += (h - 1) * slock.Pitch;
7347 dbuf += (h - 1) * dlock.Pitch;
7348 sbufpitch = -slock.Pitch;
7349 dbufpitch = -dlock.Pitch;
7353 sbufpitch = slock.Pitch;
7354 dbufpitch = dlock.Pitch;
7356 for (y = 0; y < h; ++y)
7358 /* This is pretty easy, a line for line memcpy. */
7359 memmove(dbuf, sbuf, width);
7363 TRACE("Copy done.\n");
7367 if (src_surface == dst_surface)
7369 IWineD3DSurface_Unmap((IWineD3DSurface *)dst_surface);
7373 IWineD3DSurface_Unmap((IWineD3DSurface *)dst_surface);
7374 IWineD3DSurface_Unmap((IWineD3DSurface *)src_surface);
7380 /* Do not call while under the GL lock. */
7381 static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface,
7382 const RECT *dst_rect, const WINED3DCOLORVALUE *color)
7386 memset(&BltFx, 0, sizeof(BltFx));
7387 BltFx.dwSize = sizeof(BltFx);
7388 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface->resource.format, color);
7389 return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect,
7390 NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
7393 /* Do not call while under the GL lock. */
7394 static HRESULT cpu_blit_depth_fill(IWineD3DDeviceImpl *device,
7395 IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
7397 FIXME("Depth filling not implemented by cpu_blit.\n");
7398 return WINED3DERR_INVALIDCALL;
7401 const struct blit_shader cpu_blit = {
7407 cpu_blit_color_fill,
7408 cpu_blit_depth_fill,
7411 HRESULT surface_init(IWineD3DSurfaceImpl *surface, WINED3DSURFTYPE surface_type, UINT alignment,
7412 UINT width, UINT height, UINT level, BOOL lockable, BOOL discard, WINED3DMULTISAMPLE_TYPE multisample_type,
7413 UINT multisample_quality, IWineD3DDeviceImpl *device, DWORD usage, enum wined3d_format_id format_id,
7414 WINED3DPOOL pool, void *parent, const struct wined3d_parent_ops *parent_ops)
7416 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7417 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7418 unsigned int resource_size;
7421 if (multisample_quality > 0)
7423 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7424 multisample_quality = 0;
7427 /* Quick lockable sanity check.
7428 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7429 * this function is too deep to need to care about things like this.
7430 * Levels need to be checked too, since they all affect what can be done. */
7433 case WINED3DPOOL_SCRATCH:
7436 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7437 "which are mutually exclusive, setting lockable to TRUE.\n");
7442 case WINED3DPOOL_SYSTEMMEM:
7444 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7447 case WINED3DPOOL_MANAGED:
7448 if (usage & WINED3DUSAGE_DYNAMIC)
7449 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7452 case WINED3DPOOL_DEFAULT:
7453 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7454 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7458 FIXME("Unknown pool %#x.\n", pool);
7462 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3DPOOL_DEFAULT)
7463 FIXME("Trying to create a render target that isn't in the default pool.\n");
7465 /* FIXME: Check that the format is supported by the device. */
7467 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7469 return WINED3DERR_INVALIDCALL;
7471 surface->surface_type = surface_type;
7472 surface->lpVtbl = &IWineD3DSurface_Vtbl;
7474 switch (surface_type)
7476 case SURFACE_OPENGL:
7477 surface->surface_ops = &surface_ops;
7481 surface->surface_ops = &gdi_surface_ops;
7485 ERR("Requested unknown surface implementation %#x.\n", surface_type);
7486 return WINED3DERR_INVALIDCALL;
7489 hr = resource_init(&surface->resource, device, WINED3DRTYPE_SURFACE, format,
7490 multisample_type, multisample_quality, usage, pool, width, height, 1,
7491 resource_size, parent, parent_ops, &surface_resource_ops);
7494 WARN("Failed to initialize resource, returning %#x.\n", hr);
7498 /* "Standalone" surface. */
7499 surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7501 surface->texture_level = level;
7502 list_init(&surface->overlays);
7505 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7507 surface->flags |= SFLAG_DISCARD;
7508 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7509 surface->flags |= SFLAG_LOCKABLE;
7511 /* Mark the texture as dirty so that it gets loaded first time around. */
7512 surface_add_dirty_rect(surface, NULL);
7513 list_init(&surface->renderbuffers);
7515 TRACE("surface %p, memory %p, size %u\n",
7516 surface, surface->resource.allocatedMemory, surface->resource.size);
7518 /* Call the private setup routine */
7519 hr = surface->surface_ops->surface_private_setup(surface);
7522 ERR("Private setup failed, returning %#x\n", hr);
7523 surface->surface_ops->surface_cleanup(surface);