2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d);
36 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
37 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
38 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter);
39 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
40 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *fx,
41 enum wined3d_texture_filter_type filter);
43 static void surface_cleanup(struct wined3d_surface *surface)
45 struct wined3d_surface *overlay, *cur;
47 TRACE("surface %p.\n", surface);
49 if (surface->texture_name || (surface->flags & SFLAG_PBO)
50 || surface->rb_multisample || surface->rb_resolved
51 || !list_empty(&surface->renderbuffers))
53 struct wined3d_renderbuffer_entry *entry, *entry2;
54 const struct wined3d_gl_info *gl_info;
55 struct wined3d_context *context;
57 context = context_acquire(surface->resource.device, NULL);
58 gl_info = context->gl_info;
62 if (surface->texture_name)
64 TRACE("Deleting texture %u.\n", surface->texture_name);
65 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name);
68 if (surface->flags & SFLAG_PBO)
70 TRACE("Deleting PBO %u.\n", surface->pbo);
71 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
74 if (surface->rb_multisample)
76 TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
77 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
80 if (surface->rb_resolved)
82 TRACE("Deleting resolved renderbuffer %u.\n", surface->rb_resolved);
83 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
86 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
88 TRACE("Deleting renderbuffer %u.\n", entry->id);
89 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
90 HeapFree(GetProcessHeap(), 0, entry);
95 context_release(context);
98 if (surface->flags & SFLAG_DIBSECTION)
100 DeleteDC(surface->hDC);
101 DeleteObject(surface->dib.DIBsection);
102 surface->dib.bitmap_data = NULL;
103 surface->resource.allocatedMemory = NULL;
106 if (surface->flags & SFLAG_USERPTR)
107 wined3d_surface_set_mem(surface, NULL);
108 if (surface->overlay_dest)
109 list_remove(&surface->overlay_entry);
111 LIST_FOR_EACH_ENTRY_SAFE(overlay, cur, &surface->overlays, struct wined3d_surface, overlay_entry)
113 list_remove(&overlay->overlay_entry);
114 overlay->overlay_dest = NULL;
117 resource_cleanup(&surface->resource);
120 void surface_update_draw_binding(struct wined3d_surface *surface)
122 if (!surface_is_offscreen(surface) || wined3d_settings.offscreen_rendering_mode != ORM_FBO)
123 surface->draw_binding = SFLAG_INDRAWABLE;
124 else if (surface->resource.multisample_type)
125 surface->draw_binding = SFLAG_INRB_MULTISAMPLE;
127 surface->draw_binding = SFLAG_INTEXTURE;
130 void surface_set_container(struct wined3d_surface *surface, enum wined3d_container_type type, void *container)
132 TRACE("surface %p, container %p.\n", surface, container);
134 if (!container && type != WINED3D_CONTAINER_NONE)
135 ERR("Setting NULL container of type %#x.\n", type);
137 if (type == WINED3D_CONTAINER_SWAPCHAIN)
139 surface->get_drawable_size = get_drawable_size_swapchain;
143 switch (wined3d_settings.offscreen_rendering_mode)
146 surface->get_drawable_size = get_drawable_size_fbo;
150 surface->get_drawable_size = get_drawable_size_backbuffer;
154 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
159 surface->container.type = type;
160 surface->container.u.base = container;
161 surface_update_draw_binding(surface);
168 enum tex_types tex_type;
169 GLfloat coords[4][3];
180 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
182 f->l = ((r->left * 2.0f) / w) - 1.0f;
183 f->t = ((r->top * 2.0f) / h) - 1.0f;
184 f->r = ((r->right * 2.0f) / w) - 1.0f;
185 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
188 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
190 GLfloat (*coords)[3] = info->coords;
196 FIXME("Unsupported texture target %#x\n", target);
197 /* Fall back to GL_TEXTURE_2D */
199 info->binding = GL_TEXTURE_BINDING_2D;
200 info->bind_target = GL_TEXTURE_2D;
201 info->tex_type = tex_2d;
202 coords[0][0] = (float)rect->left / w;
203 coords[0][1] = (float)rect->top / h;
206 coords[1][0] = (float)rect->right / w;
207 coords[1][1] = (float)rect->top / h;
210 coords[2][0] = (float)rect->left / w;
211 coords[2][1] = (float)rect->bottom / h;
214 coords[3][0] = (float)rect->right / w;
215 coords[3][1] = (float)rect->bottom / h;
219 case GL_TEXTURE_RECTANGLE_ARB:
220 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
221 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
222 info->tex_type = tex_rect;
223 coords[0][0] = rect->left; coords[0][1] = rect->top; coords[0][2] = 0.0f;
224 coords[1][0] = rect->right; coords[1][1] = rect->top; coords[1][2] = 0.0f;
225 coords[2][0] = rect->left; coords[2][1] = rect->bottom; coords[2][2] = 0.0f;
226 coords[3][0] = rect->right; coords[3][1] = rect->bottom; coords[3][2] = 0.0f;
229 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
230 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
231 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
232 info->tex_type = tex_cube;
233 cube_coords_float(rect, w, h, &f);
235 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
236 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
237 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
238 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
241 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
242 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
243 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
244 info->tex_type = tex_cube;
245 cube_coords_float(rect, w, h, &f);
247 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
248 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
249 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
250 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
253 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
254 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
255 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
256 info->tex_type = tex_cube;
257 cube_coords_float(rect, w, h, &f);
259 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
260 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
261 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
262 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
265 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
266 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
267 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
268 info->tex_type = tex_cube;
269 cube_coords_float(rect, w, h, &f);
271 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
272 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
273 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
274 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
277 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
278 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
279 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
280 info->tex_type = tex_cube;
281 cube_coords_float(rect, w, h, &f);
283 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
284 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
285 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
286 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
289 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
290 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
291 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
292 info->tex_type = tex_cube;
293 cube_coords_float(rect, w, h, &f);
295 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
296 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
297 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
298 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
303 static void surface_get_rect(const struct wined3d_surface *surface, const RECT *rect_in, RECT *rect_out)
306 *rect_out = *rect_in;
311 rect_out->right = surface->resource.width;
312 rect_out->bottom = surface->resource.height;
316 /* GL locking and context activation is done by the caller */
317 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
318 const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter)
320 const struct wined3d_gl_info *gl_info = context->gl_info;
321 struct blt_info info;
323 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
325 gl_info->gl_ops.gl.p_glEnable(info.bind_target);
326 checkGLcall("glEnable(bind_target)");
328 context_bind_texture(context, info.bind_target, src_surface->texture_name);
330 /* Filtering for StretchRect */
331 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
332 wined3d_gl_mag_filter(magLookup, filter));
333 checkGLcall("glTexParameteri");
334 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
335 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
336 checkGLcall("glTexParameteri");
337 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
338 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
339 if (context->gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
340 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
341 gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
342 checkGLcall("glTexEnvi");
345 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
346 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
347 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->top);
349 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
350 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->top);
352 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
353 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->left, dst_rect->bottom);
355 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
356 gl_info->gl_ops.gl.p_glVertex2i(dst_rect->right, dst_rect->bottom);
357 gl_info->gl_ops.gl.p_glEnd();
359 /* Unbind the texture */
360 context_bind_texture(context, info.bind_target, 0);
362 /* We changed the filtering settings on the texture. Inform the
363 * container about this to get the filters reset properly next draw. */
364 if (src_surface->container.type == WINED3D_CONTAINER_TEXTURE)
366 struct wined3d_texture *texture = src_surface->container.u.texture;
367 texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3D_TEXF_POINT;
368 texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3D_TEXF_POINT;
369 texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3D_TEXF_NONE;
370 texture->texture_rgb.states[WINED3DTEXSTA_SRGBTEXTURE] = FALSE;
374 static HRESULT surface_create_dib_section(struct wined3d_surface *surface)
376 const struct wined3d_format *format = surface->resource.format;
382 TRACE("surface %p.\n", surface);
384 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
386 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
387 return WINED3DERR_INVALIDCALL;
390 switch (format->byte_count)
394 /* Allocate extra space to store the RGB bit masks. */
395 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
399 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
403 /* Allocate extra space for a palette. */
404 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
405 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
410 return E_OUTOFMEMORY;
412 /* Some applications access the surface in via DWORDs, and do not take
413 * the necessary care at the end of the surface. So we need at least
414 * 4 extra bytes at the end of the surface. Check against the page size,
415 * if the last page used for the surface has at least 4 spare bytes we're
416 * safe, otherwise add an extra line to the DIB section. */
417 GetSystemInfo(&sysInfo);
418 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
421 TRACE("Adding an extra line to the DIB section.\n");
424 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
425 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
426 b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count;
427 b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
428 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
429 * wined3d_surface_get_pitch(surface);
430 b_info->bmiHeader.biPlanes = 1;
431 b_info->bmiHeader.biBitCount = format->byte_count * 8;
433 b_info->bmiHeader.biXPelsPerMeter = 0;
434 b_info->bmiHeader.biYPelsPerMeter = 0;
435 b_info->bmiHeader.biClrUsed = 0;
436 b_info->bmiHeader.biClrImportant = 0;
438 /* Get the bit masks */
439 masks = (DWORD *)b_info->bmiColors;
440 switch (surface->resource.format->id)
442 case WINED3DFMT_B8G8R8_UNORM:
443 b_info->bmiHeader.biCompression = BI_RGB;
446 case WINED3DFMT_B5G5R5X1_UNORM:
447 case WINED3DFMT_B5G5R5A1_UNORM:
448 case WINED3DFMT_B4G4R4A4_UNORM:
449 case WINED3DFMT_B4G4R4X4_UNORM:
450 case WINED3DFMT_B2G3R3_UNORM:
451 case WINED3DFMT_B2G3R3A8_UNORM:
452 case WINED3DFMT_R10G10B10A2_UNORM:
453 case WINED3DFMT_R8G8B8A8_UNORM:
454 case WINED3DFMT_R8G8B8X8_UNORM:
455 case WINED3DFMT_B10G10R10A2_UNORM:
456 case WINED3DFMT_B5G6R5_UNORM:
457 case WINED3DFMT_R16G16B16A16_UNORM:
458 b_info->bmiHeader.biCompression = BI_BITFIELDS;
459 masks[0] = format->red_mask;
460 masks[1] = format->green_mask;
461 masks[2] = format->blue_mask;
465 /* Don't know palette */
466 b_info->bmiHeader.biCompression = BI_RGB;
470 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
471 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
472 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
473 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
475 if (!surface->dib.DIBsection)
477 ERR("Failed to create DIB section.\n");
478 HeapFree(GetProcessHeap(), 0, b_info);
479 return HRESULT_FROM_WIN32(GetLastError());
482 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
483 /* Copy the existing surface to the dib section. */
484 if (surface->resource.allocatedMemory)
486 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
487 surface->resource.height * wined3d_surface_get_pitch(surface));
491 /* This is to make maps read the GL texture although memory is allocated. */
492 surface->flags &= ~SFLAG_INSYSMEM;
494 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
496 HeapFree(GetProcessHeap(), 0, b_info);
498 /* Now allocate a DC. */
499 surface->hDC = CreateCompatibleDC(0);
500 SelectObject(surface->hDC, surface->dib.DIBsection);
501 TRACE("Using wined3d palette %p.\n", surface->palette);
502 SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
504 surface->flags |= SFLAG_DIBSECTION;
509 static BOOL surface_need_pbo(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
511 if (surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
513 if (!(surface->flags & SFLAG_DYNLOCK))
515 if (surface->flags & (SFLAG_CONVERTED | SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM))
517 if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT])
523 static void surface_load_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
525 struct wined3d_context *context;
528 context = context_acquire(surface->resource.device, NULL);
531 GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
532 error = gl_info->gl_ops.gl.p_glGetError();
533 if (!surface->pbo || error != GL_NO_ERROR)
534 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
536 TRACE("Binding PBO %u.\n", surface->pbo);
538 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
539 checkGLcall("glBindBufferARB");
541 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
542 surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
543 checkGLcall("glBufferDataARB");
545 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
546 checkGLcall("glBindBufferARB");
548 /* We don't need the system memory anymore and we can't even use it for PBOs. */
549 if (!(surface->flags & SFLAG_CLIENT))
551 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
552 surface->resource.heapMemory = NULL;
554 surface->resource.allocatedMemory = NULL;
555 surface->flags |= SFLAG_PBO;
557 context_release(context);
560 static void surface_prepare_system_memory(struct wined3d_surface *surface)
562 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
564 TRACE("surface %p.\n", surface);
566 if (!(surface->flags & SFLAG_PBO) && surface_need_pbo(surface, gl_info))
567 surface_load_pbo(surface, gl_info);
568 else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO))
570 /* Whatever surface we have, make sure that there is memory allocated
571 * for the downloaded copy, or a PBO to map. */
572 if (!surface->resource.heapMemory)
573 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
575 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
576 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
578 if (surface->flags & SFLAG_INSYSMEM)
579 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
583 static void surface_evict_sysmem(struct wined3d_surface *surface)
585 if (surface->resource.map_count || (surface->flags & SFLAG_DONOTFREE))
588 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
589 surface->resource.allocatedMemory = NULL;
590 surface->resource.heapMemory = NULL;
591 surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
594 /* Context activation is done by the caller. */
595 static void surface_bind(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
597 TRACE("surface %p, context %p, srgb %#x.\n", surface, context, srgb);
599 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
601 struct wined3d_texture *texture = surface->container.u.texture;
603 TRACE("Passing to container (%p).\n", texture);
604 texture->texture_ops->texture_bind(texture, context, srgb);
608 const struct wined3d_gl_info *gl_info = context->gl_info;
610 if (surface->texture_level)
612 ERR("Standalone surface %p is non-zero texture level %u.\n",
613 surface, surface->texture_level);
617 ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
621 if (!surface->texture_name)
623 gl_info->gl_ops.gl.p_glGenTextures(1, &surface->texture_name);
624 checkGLcall("glGenTextures");
626 TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
628 context_bind_texture(context, surface->texture_target, surface->texture_name);
629 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
630 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
631 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
632 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
633 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
634 checkGLcall("glTexParameteri");
638 context_bind_texture(context, surface->texture_target, surface->texture_name);
645 /* Context activation is done by the caller. */
646 static void surface_bind_and_dirtify(struct wined3d_surface *surface,
647 struct wined3d_context *context, BOOL srgb)
649 struct wined3d_device *device = surface->resource.device;
650 DWORD active_sampler;
652 /* We don't need a specific texture unit, but after binding the texture
653 * the current unit is dirty. Read the unit back instead of switching to
654 * 0, this avoids messing around with the state manager's GL states. The
655 * current texture unit should always be a valid one.
657 * To be more specific, this is tricky because we can implicitly be
658 * called from sampler() in state.c. This means we can't touch anything
659 * other than whatever happens to be the currently active texture, or we
660 * would risk marking already applied sampler states dirty again. */
661 active_sampler = device->rev_tex_unit_map[context->active_texture];
663 if (active_sampler != WINED3D_UNMAPPED_STAGE)
664 device_invalidate_state(device, STATE_SAMPLER(active_sampler));
665 surface_bind(surface, context, srgb);
668 static void surface_force_reload(struct wined3d_surface *surface)
670 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
673 static void surface_release_client_storage(struct wined3d_surface *surface)
675 struct wined3d_context *context = context_acquire(surface->resource.device, NULL);
676 const struct wined3d_gl_info *gl_info = context->gl_info;
679 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
680 if (surface->texture_name)
682 surface_bind_and_dirtify(surface, context, FALSE);
683 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
684 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
686 if (surface->texture_name_srgb)
688 surface_bind_and_dirtify(surface, context, TRUE);
689 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
690 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
692 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
695 context_release(context);
697 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
698 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
699 surface_force_reload(surface);
702 static HRESULT surface_private_setup(struct wined3d_surface *surface)
704 /* TODO: Check against the maximum texture sizes supported by the video card. */
705 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
706 unsigned int pow2Width, pow2Height;
708 TRACE("surface %p.\n", surface);
710 surface->texture_name = 0;
711 surface->texture_target = GL_TEXTURE_2D;
713 /* Non-power2 support */
714 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
716 pow2Width = surface->resource.width;
717 pow2Height = surface->resource.height;
721 /* Find the nearest pow2 match */
722 pow2Width = pow2Height = 1;
723 while (pow2Width < surface->resource.width)
725 while (pow2Height < surface->resource.height)
728 surface->pow2Width = pow2Width;
729 surface->pow2Height = pow2Height;
731 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
733 /* TODO: Add support for non power two compressed textures. */
734 if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
736 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
737 surface, surface->resource.width, surface->resource.height);
738 return WINED3DERR_NOTAVAILABLE;
742 if (pow2Width != surface->resource.width
743 || pow2Height != surface->resource.height)
745 surface->flags |= SFLAG_NONPOW2;
748 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
749 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
751 /* One of three options:
752 * 1: Do the same as we do with NPOT and scale the texture, (any
753 * texture ops would require the texture to be scaled which is
755 * 2: Set the texture to the maximum size (bad idea).
756 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
757 * 4: Create the surface, but allow it to be used only for DirectDraw
758 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
759 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
760 * the render target. */
761 if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED)
763 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
764 return WINED3DERR_NOTAVAILABLE;
767 /* We should never use this surface in combination with OpenGL! */
768 TRACE("Creating an oversized surface: %ux%u.\n",
769 surface->pow2Width, surface->pow2Height);
773 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
774 * and EXT_PALETTED_TEXTURE is used in combination with texture
775 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
776 * EXT_PALETTED_TEXTURE doesn't work in combination with
777 * ARB_TEXTURE_RECTANGLE. */
778 if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
779 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
780 && gl_info->supported[EXT_PALETTED_TEXTURE]
781 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
783 surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
784 surface->pow2Width = surface->resource.width;
785 surface->pow2Height = surface->resource.height;
786 surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
790 switch (wined3d_settings.offscreen_rendering_mode)
793 surface->get_drawable_size = get_drawable_size_fbo;
797 surface->get_drawable_size = get_drawable_size_backbuffer;
801 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
802 return WINED3DERR_INVALIDCALL;
805 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
806 surface->flags |= SFLAG_DISCARDED;
811 static void surface_realize_palette(struct wined3d_surface *surface)
813 struct wined3d_palette *palette = surface->palette;
815 TRACE("surface %p.\n", surface);
817 if (!palette) return;
819 if (surface->resource.format->id == WINED3DFMT_P8_UINT
820 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
822 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
824 /* Make sure the texture is up to date. This call doesn't do
825 * anything if the texture is already up to date. */
826 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
828 /* We want to force a palette refresh, so mark the drawable as not being up to date */
829 if (!surface_is_offscreen(surface))
830 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
834 if (!(surface->flags & SFLAG_INSYSMEM))
836 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
837 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
839 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
843 if (surface->flags & SFLAG_DIBSECTION)
848 TRACE("Updating the DC's palette.\n");
850 for (i = 0; i < 256; ++i)
852 col[i].rgbRed = palette->palents[i].peRed;
853 col[i].rgbGreen = palette->palents[i].peGreen;
854 col[i].rgbBlue = palette->palents[i].peBlue;
855 col[i].rgbReserved = 0;
857 SetDIBColorTable(surface->hDC, 0, 256, col);
860 /* Propagate the changes to the drawable when we have a palette. */
861 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
862 surface_load_location(surface, surface->draw_binding, NULL);
865 static HRESULT surface_draw_overlay(struct wined3d_surface *surface)
869 /* If there's no destination surface there is nothing to do. */
870 if (!surface->overlay_dest)
873 /* Blt calls ModifyLocation on the dest surface, which in turn calls
874 * DrawOverlay to update the overlay. Prevent an endless recursion. */
875 if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
878 surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
879 hr = wined3d_surface_blt(surface->overlay_dest, &surface->overlay_destrect, surface,
880 &surface->overlay_srcrect, WINEDDBLT_WAIT, NULL, WINED3D_TEXF_LINEAR);
881 surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
886 static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
888 struct wined3d_device *device = surface->resource.device;
889 const RECT *pass_rect = rect;
891 TRACE("surface %p, rect %s, flags %#x.\n",
892 surface, wine_dbgstr_rect(rect), flags);
894 if (flags & WINED3D_MAP_DISCARD)
896 TRACE("WINED3D_MAP_DISCARD flag passed, marking SYSMEM as up to date.\n");
897 surface_prepare_system_memory(surface);
898 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
902 /* surface_load_location() does not check if the rectangle specifies
903 * the full surface. Most callers don't need that, so do it here. */
904 if (rect && !rect->top && !rect->left
905 && rect->right == surface->resource.width
906 && rect->bottom == surface->resource.height)
908 surface_load_location(surface, SFLAG_INSYSMEM, pass_rect);
911 if (surface->flags & SFLAG_PBO)
913 const struct wined3d_gl_info *gl_info;
914 struct wined3d_context *context;
916 context = context_acquire(device, NULL);
917 gl_info = context->gl_info;
920 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
921 checkGLcall("glBindBufferARB");
923 /* This shouldn't happen but could occur if some other function
924 * didn't handle the PBO properly. */
925 if (surface->resource.allocatedMemory)
926 ERR("The surface already has PBO memory allocated.\n");
928 surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
929 checkGLcall("glMapBufferARB");
931 /* Make sure the PBO isn't set anymore in order not to break non-PBO
933 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
934 checkGLcall("glBindBufferARB");
937 context_release(context);
940 if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
943 surface_add_dirty_rect(surface, NULL);
946 struct wined3d_box b;
950 b.right = rect->right;
951 b.bottom = rect->bottom;
954 surface_add_dirty_rect(surface, &b);
959 static void surface_unmap(struct wined3d_surface *surface)
961 struct wined3d_device *device = surface->resource.device;
964 TRACE("surface %p.\n", surface);
966 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
968 if (surface->flags & SFLAG_PBO)
970 const struct wined3d_gl_info *gl_info;
971 struct wined3d_context *context;
973 TRACE("Freeing PBO memory.\n");
975 context = context_acquire(device, NULL);
976 gl_info = context->gl_info;
979 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
980 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
981 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
982 checkGLcall("glUnmapBufferARB");
984 context_release(context);
986 surface->resource.allocatedMemory = NULL;
989 TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
991 if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
993 TRACE("Not dirtified, nothing to do.\n");
997 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
998 && surface->container.u.swapchain->front_buffer == surface)
1000 if (!surface->dirtyRect.left && !surface->dirtyRect.top
1001 && surface->dirtyRect.right == surface->resource.width
1002 && surface->dirtyRect.bottom == surface->resource.height)
1008 /* TODO: Proper partial rectangle tracking. */
1009 fullsurface = FALSE;
1010 surface->flags |= SFLAG_INSYSMEM;
1013 surface_load_location(surface, surface->draw_binding, fullsurface ? NULL : &surface->dirtyRect);
1015 /* Partial rectangle tracking is not commonly implemented, it is only
1016 * done for render targets. INSYSMEM was set before to tell
1017 * surface_load_location() where to read the rectangle from.
1018 * Indrawable is set because all modifications from the partial
1019 * sysmem copy are written back to the drawable, thus the surface is
1020 * merged again in the drawable. The sysmem copy is not fully up to
1021 * date because only a subrectangle was read in Map(). */
1024 surface_modify_location(surface, surface->draw_binding, TRUE);
1025 surface_evict_sysmem(surface);
1028 surface->dirtyRect.left = surface->resource.width;
1029 surface->dirtyRect.top = surface->resource.height;
1030 surface->dirtyRect.right = 0;
1031 surface->dirtyRect.bottom = 0;
1033 else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1035 FIXME("Depth / stencil buffer locking is not implemented.\n");
1039 /* Overlays have to be redrawn manually after changes with the GL implementation */
1040 if (surface->overlay_dest)
1041 surface_draw_overlay(surface);
1044 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
1046 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
1048 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
1053 static void wined3d_surface_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_surface *src_surface,
1054 const RECT *src_rect, struct wined3d_surface *dst_surface, const RECT *dst_rect)
1056 const struct wined3d_gl_info *gl_info;
1057 struct wined3d_context *context;
1058 DWORD src_mask, dst_mask;
1061 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
1062 device, src_surface, wine_dbgstr_rect(src_rect),
1063 dst_surface, wine_dbgstr_rect(dst_rect));
1065 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1066 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1068 if (src_mask != dst_mask)
1070 ERR("Incompatible formats %s and %s.\n",
1071 debug_d3dformat(src_surface->resource.format->id),
1072 debug_d3dformat(dst_surface->resource.format->id));
1078 ERR("Not a depth / stencil format: %s.\n",
1079 debug_d3dformat(src_surface->resource.format->id));
1084 if (src_mask & WINED3DFMT_FLAG_DEPTH)
1085 gl_mask |= GL_DEPTH_BUFFER_BIT;
1086 if (src_mask & WINED3DFMT_FLAG_STENCIL)
1087 gl_mask |= GL_STENCIL_BUFFER_BIT;
1089 /* Make sure the locations are up-to-date. Loading the destination
1090 * surface isn't required if the entire surface is overwritten. */
1091 surface_load_location(src_surface, SFLAG_INTEXTURE, NULL);
1092 if (!surface_is_full_rect(dst_surface, dst_rect))
1093 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
1095 context = context_acquire(device, NULL);
1096 if (!context->valid)
1098 context_release(context);
1099 WARN("Invalid context, skipping blit.\n");
1103 gl_info = context->gl_info;
1107 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, SFLAG_INTEXTURE);
1108 gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
1109 checkGLcall("glReadBuffer()");
1110 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1112 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, SFLAG_INTEXTURE);
1113 context_set_draw_buffer(context, GL_NONE);
1114 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1115 context_invalidate_state(context, STATE_FRAMEBUFFER);
1117 if (gl_mask & GL_DEPTH_BUFFER_BIT)
1119 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
1120 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
1122 if (gl_mask & GL_STENCIL_BUFFER_BIT)
1124 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
1126 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1127 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
1129 gl_info->gl_ops.gl.p_glStencilMask(~0U);
1130 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1133 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1134 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1136 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
1137 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
1138 checkGLcall("glBlitFramebuffer()");
1142 if (wined3d_settings.strict_draw_ordering)
1143 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
1145 context_release(context);
1148 /* Blit between surface locations. Onscreen on different swapchains is not supported.
1149 * Depth / stencil is not supported. */
1150 static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_texture_filter_type filter,
1151 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
1152 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
1154 const struct wined3d_gl_info *gl_info;
1155 struct wined3d_context *context;
1156 RECT src_rect, dst_rect;
1160 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
1161 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1162 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
1163 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1164 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
1166 src_rect = *src_rect_in;
1167 dst_rect = *dst_rect_in;
1171 case WINED3D_TEXF_LINEAR:
1172 gl_filter = GL_LINEAR;
1176 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
1177 case WINED3D_TEXF_NONE:
1178 case WINED3D_TEXF_POINT:
1179 gl_filter = GL_NEAREST;
1183 /* Resolve the source surface first if needed. */
1184 if (src_location == SFLAG_INRB_MULTISAMPLE
1185 && (src_surface->resource.format->id != dst_surface->resource.format->id
1186 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
1187 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
1188 src_location = SFLAG_INRB_RESOLVED;
1190 /* Make sure the locations are up-to-date. Loading the destination
1191 * surface isn't required if the entire surface is overwritten. (And is
1192 * in fact harmful if we're being called by surface_load_location() with
1193 * the purpose of loading the destination surface.) */
1194 surface_load_location(src_surface, src_location, NULL);
1195 if (!surface_is_full_rect(dst_surface, &dst_rect))
1196 surface_load_location(dst_surface, dst_location, NULL);
1198 if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
1199 else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
1200 else context = context_acquire(device, NULL);
1202 if (!context->valid)
1204 context_release(context);
1205 WARN("Invalid context, skipping blit.\n");
1209 gl_info = context->gl_info;
1211 if (src_location == SFLAG_INDRAWABLE)
1213 TRACE("Source surface %p is onscreen.\n", src_surface);
1214 buffer = surface_get_gl_buffer(src_surface);
1215 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
1219 TRACE("Source surface %p is offscreen.\n", src_surface);
1220 buffer = GL_COLOR_ATTACHMENT0;
1224 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
1225 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1226 checkGLcall("glReadBuffer()");
1227 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1230 if (dst_location == SFLAG_INDRAWABLE)
1232 TRACE("Destination surface %p is onscreen.\n", dst_surface);
1233 buffer = surface_get_gl_buffer(dst_surface);
1234 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
1238 TRACE("Destination surface %p is offscreen.\n", dst_surface);
1239 buffer = GL_COLOR_ATTACHMENT0;
1243 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
1244 context_set_draw_buffer(context, buffer);
1245 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1246 context_invalidate_state(context, STATE_FRAMEBUFFER);
1248 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1249 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
1250 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
1251 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
1252 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
1254 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1255 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1257 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
1258 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
1259 checkGLcall("glBlitFramebuffer()");
1263 if (wined3d_settings.strict_draw_ordering
1264 || (dst_location == SFLAG_INDRAWABLE
1265 && dst_surface->container.u.swapchain->front_buffer == dst_surface))
1266 gl_info->gl_ops.gl.p_glFlush();
1268 context_release(context);
1271 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
1272 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
1273 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
1275 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1278 /* Source and/or destination need to be on the GL side */
1279 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
1284 case WINED3D_BLIT_OP_COLOR_BLIT:
1285 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
1287 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
1291 case WINED3D_BLIT_OP_DEPTH_BLIT:
1292 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1294 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1302 if (!(src_format->id == dst_format->id
1303 || (is_identity_fixup(src_format->color_fixup)
1304 && is_identity_fixup(dst_format->color_fixup))))
1310 /* This function checks if the primary render target uses the 8bit paletted format. */
1311 static BOOL primary_render_target_is_p8(const struct wined3d_device *device)
1313 if (device->fb.render_targets && device->fb.render_targets[0])
1315 const struct wined3d_surface *render_target = device->fb.render_targets[0];
1316 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
1317 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
1323 static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface,
1324 DWORD color, struct wined3d_color *float_color)
1326 const struct wined3d_format *format = surface->resource.format;
1327 const struct wined3d_device *device = surface->resource.device;
1331 case WINED3DFMT_P8_UINT:
1332 if (surface->palette)
1334 float_color->r = surface->palette->palents[color].peRed / 255.0f;
1335 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
1336 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
1340 float_color->r = 0.0f;
1341 float_color->g = 0.0f;
1342 float_color->b = 0.0f;
1344 float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
1347 case WINED3DFMT_B5G6R5_UNORM:
1348 float_color->r = ((color >> 11) & 0x1f) / 31.0f;
1349 float_color->g = ((color >> 5) & 0x3f) / 63.0f;
1350 float_color->b = (color & 0x1f) / 31.0f;
1351 float_color->a = 1.0f;
1354 case WINED3DFMT_B8G8R8_UNORM:
1355 case WINED3DFMT_B8G8R8X8_UNORM:
1356 float_color->r = D3DCOLOR_R(color);
1357 float_color->g = D3DCOLOR_G(color);
1358 float_color->b = D3DCOLOR_B(color);
1359 float_color->a = 1.0f;
1362 case WINED3DFMT_B8G8R8A8_UNORM:
1363 float_color->r = D3DCOLOR_R(color);
1364 float_color->g = D3DCOLOR_G(color);
1365 float_color->b = D3DCOLOR_B(color);
1366 float_color->a = D3DCOLOR_A(color);
1370 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1377 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
1379 const struct wined3d_format *format = surface->resource.format;
1383 case WINED3DFMT_S1_UINT_D15_UNORM:
1384 *float_depth = depth / (float)0x00007fff;
1387 case WINED3DFMT_D16_UNORM:
1388 *float_depth = depth / (float)0x0000ffff;
1391 case WINED3DFMT_D24_UNORM_S8_UINT:
1392 case WINED3DFMT_X8D24_UNORM:
1393 *float_depth = depth / (float)0x00ffffff;
1396 case WINED3DFMT_D32_UNORM:
1397 *float_depth = depth / (float)0xffffffff;
1401 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1408 /* Do not call while under the GL lock. */
1409 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
1411 const struct wined3d_resource *resource = &surface->resource;
1412 struct wined3d_device *device = resource->device;
1413 const struct blit_shader *blitter;
1415 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
1416 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
1419 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1420 return WINED3DERR_INVALIDCALL;
1423 return blitter->depth_fill(device, surface, rect, depth);
1426 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, const RECT *src_rect,
1427 struct wined3d_surface *dst_surface, const RECT *dst_rect)
1429 struct wined3d_device *device = src_surface->resource.device;
1431 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
1432 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1433 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1434 return WINED3DERR_INVALIDCALL;
1436 wined3d_surface_depth_blt_fbo(device, src_surface, src_rect, dst_surface, dst_rect);
1438 surface_modify_ds_location(dst_surface, SFLAG_INTEXTURE,
1439 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
1444 /* Do not call while under the GL lock. */
1445 HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
1446 struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
1447 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
1449 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
1450 struct wined3d_device *device = dst_surface->resource.device;
1451 DWORD src_ds_flags, dst_ds_flags;
1452 RECT src_rect, dst_rect;
1453 BOOL scale, convert;
1455 static const DWORD simple_blit = WINEDDBLT_ASYNC
1456 | WINEDDBLT_COLORFILL
1458 | WINEDDBLT_DEPTHFILL
1459 | WINEDDBLT_DONOTWAIT;
1461 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1462 dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
1463 flags, fx, debug_d3dtexturefiltertype(filter));
1464 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
1468 TRACE("dwSize %#x.\n", fx->dwSize);
1469 TRACE("dwDDFX %#x.\n", fx->dwDDFX);
1470 TRACE("dwROP %#x.\n", fx->dwROP);
1471 TRACE("dwDDROP %#x.\n", fx->dwDDROP);
1472 TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle);
1473 TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode);
1474 TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow);
1475 TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh);
1476 TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest);
1477 TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth);
1478 TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest);
1479 TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth);
1480 TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc);
1481 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth);
1482 TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend);
1483 TRACE("dwReserved %#x.\n", fx->dwReserved);
1484 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth);
1485 TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest);
1486 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth);
1487 TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc);
1488 TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern);
1489 TRACE("ddckDestColorkey {%#x, %#x}.\n",
1490 fx->ddckDestColorkey.color_space_low_value,
1491 fx->ddckDestColorkey.color_space_high_value);
1492 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
1493 fx->ddckSrcColorkey.color_space_low_value,
1494 fx->ddckSrcColorkey.color_space_high_value);
1497 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
1499 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1500 return WINEDDERR_SURFACEBUSY;
1503 surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
1505 if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom
1506 || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0
1507 || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0
1508 || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0
1509 || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0)
1511 WARN("The application gave us a bad destination rectangle.\n");
1512 return WINEDDERR_INVALIDRECT;
1517 surface_get_rect(src_surface, src_rect_in, &src_rect);
1519 if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom
1520 || src_rect.left > src_surface->resource.width || src_rect.left < 0
1521 || src_rect.top > src_surface->resource.height || src_rect.top < 0
1522 || src_rect.right > src_surface->resource.width || src_rect.right < 0
1523 || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0)
1525 WARN("Application gave us bad source rectangle for Blt.\n");
1526 return WINEDDERR_INVALIDRECT;
1531 memset(&src_rect, 0, sizeof(src_rect));
1534 if (!fx || !(fx->dwDDFX))
1535 flags &= ~WINEDDBLT_DDFX;
1537 if (flags & WINEDDBLT_WAIT)
1538 flags &= ~WINEDDBLT_WAIT;
1540 if (flags & WINEDDBLT_ASYNC)
1542 static unsigned int once;
1545 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1546 flags &= ~WINEDDBLT_ASYNC;
1549 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1550 if (flags & WINEDDBLT_DONOTWAIT)
1552 static unsigned int once;
1555 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1556 flags &= ~WINEDDBLT_DONOTWAIT;
1559 if (!device->d3d_initialized)
1561 WARN("D3D not initialized, using fallback.\n");
1565 /* We want to avoid invalidating the sysmem location for converted
1566 * surfaces, since otherwise we'd have to convert the data back when
1568 if (dst_surface->flags & SFLAG_CONVERTED)
1570 WARN("Converted surface, using CPU blit.\n");
1571 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1574 if (flags & ~simple_blit)
1576 WARN("Using fallback for complex blit (%#x).\n", flags);
1580 if (src_surface && src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1581 src_swapchain = src_surface->container.u.swapchain;
1583 src_swapchain = NULL;
1585 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1586 dst_swapchain = dst_surface->container.u.swapchain;
1588 dst_swapchain = NULL;
1590 /* This isn't strictly needed. FBO blits for example could deal with
1591 * cross-swapchain blits by first downloading the source to a texture
1592 * before switching to the destination context. We just have this here to
1593 * not have to deal with the issue, since cross-swapchain blits should be
1595 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
1597 FIXME("Using fallback for cross-swapchain blit.\n");
1602 && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
1603 || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top);
1604 convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
1606 dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1608 src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1612 if (src_ds_flags || dst_ds_flags)
1614 if (flags & WINEDDBLT_DEPTHFILL)
1618 TRACE("Depth fill.\n");
1620 if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
1621 return WINED3DERR_INVALIDCALL;
1623 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth)))
1628 if (src_ds_flags != dst_ds_flags)
1630 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1631 return WINED3DERR_INVALIDCALL;
1634 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, &src_rect, dst_surface, &dst_rect)))
1640 /* In principle this would apply to depth blits as well, but we don't
1641 * implement those in the CPU blitter at the moment. */
1642 if ((dst_surface->flags & SFLAG_INSYSMEM)
1643 && (!src_surface || (src_surface->flags & SFLAG_INSYSMEM)))
1646 TRACE("Not doing sysmem blit because of scaling.\n");
1648 TRACE("Not doing sysmem blit because of format conversion.\n");
1650 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1653 if (flags & WINEDDBLT_COLORFILL)
1655 struct wined3d_color color;
1657 TRACE("Color fill.\n");
1659 if (!surface_convert_color_to_float(dst_surface, fx->u5.dwFillColor, &color))
1662 if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
1667 TRACE("Color blit.\n");
1670 if ((src_surface->flags & SFLAG_INSYSMEM) && !(dst_surface->flags & SFLAG_INSYSMEM))
1673 TRACE("Not doing upload because of scaling.\n");
1675 TRACE("Not doing upload because of format conversion.\n");
1678 POINT dst_point = {dst_rect.left, dst_rect.top};
1680 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect)))
1682 if (!surface_is_offscreen(dst_surface))
1683 surface_load_location(dst_surface, dst_surface->draw_binding, NULL);
1689 /* Use present for back -> front blits. The idea behind this is
1690 * that present is potentially faster than a blit, in particular
1691 * when FBO blits aren't available. Some ddraw applications like
1692 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
1693 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
1694 * applications can't blit directly to the frontbuffer. */
1695 if (dst_swapchain && dst_swapchain->back_buffers
1696 && dst_surface == dst_swapchain->front_buffer
1697 && src_surface == dst_swapchain->back_buffers[0])
1699 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
1701 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1703 /* Set the swap effect to COPY, we don't want the backbuffer
1704 * to become undefined. */
1705 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
1706 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
1707 dst_swapchain->desc.swap_effect = swap_effect;
1712 if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1713 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1714 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1716 TRACE("Using FBO blit.\n");
1718 surface_blt_fbo(device, filter,
1719 src_surface, src_surface->draw_binding, &src_rect,
1720 dst_surface, dst_surface->draw_binding, &dst_rect);
1721 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
1725 if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1726 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1727 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1729 TRACE("Using arbfp blit.\n");
1731 if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
1739 /* Special cases for render targets. */
1740 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1741 || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)))
1743 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface, &dst_rect,
1744 src_surface, &src_rect, flags, fx, filter)))
1750 /* For the rest call the X11 surface implementation. For render targets
1751 * this should be implemented OpenGL accelerated in BltOverride, other
1752 * blits are rather rare. */
1753 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1756 HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *surface,
1757 struct wined3d_surface *render_target)
1759 TRACE("surface %p, render_target %p.\n", surface, render_target);
1761 /* TODO: Check surface sizes, pools, etc. */
1763 if (render_target->resource.multisample_type)
1764 return WINED3DERR_INVALIDCALL;
1766 return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT);
1769 /* Context activation is done by the caller. */
1770 static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
1772 if (surface->flags & SFLAG_DIBSECTION)
1774 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1778 if (!surface->resource.heapMemory)
1779 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
1780 else if (!(surface->flags & SFLAG_CLIENT))
1781 ERR("Surface %p has heapMemory %p and flags %#x.\n",
1782 surface, surface->resource.heapMemory, surface->flags);
1784 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
1785 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1789 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
1790 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1791 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
1792 surface->resource.size, surface->resource.allocatedMemory));
1793 checkGLcall("glGetBufferSubDataARB");
1794 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
1795 checkGLcall("glDeleteBuffersARB");
1799 surface->flags &= ~SFLAG_PBO;
1802 static BOOL surface_init_sysmem(struct wined3d_surface *surface)
1804 if (!surface->resource.allocatedMemory)
1806 if (!surface->resource.heapMemory)
1808 if (!(surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1809 surface->resource.size + RESOURCE_ALIGNMENT)))
1811 ERR("Failed to allocate memory.\n");
1815 else if (!(surface->flags & SFLAG_CLIENT))
1817 ERR("Surface %p has heapMemory %p and flags %#x.\n",
1818 surface, surface->resource.heapMemory, surface->flags);
1821 surface->resource.allocatedMemory =
1822 (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1826 memset(surface->resource.allocatedMemory, 0, surface->resource.size);
1829 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1834 /* Do not call while under the GL lock. */
1835 static void surface_unload(struct wined3d_resource *resource)
1837 struct wined3d_surface *surface = surface_from_resource(resource);
1838 struct wined3d_renderbuffer_entry *entry, *entry2;
1839 struct wined3d_device *device = resource->device;
1840 const struct wined3d_gl_info *gl_info;
1841 struct wined3d_context *context;
1843 TRACE("surface %p.\n", surface);
1845 if (resource->pool == WINED3D_POOL_DEFAULT)
1847 /* Default pool resources are supposed to be destroyed before Reset is called.
1848 * Implicit resources stay however. So this means we have an implicit render target
1849 * or depth stencil. The content may be destroyed, but we still have to tear down
1850 * opengl resources, so we cannot leave early.
1852 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1853 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1854 * or the depth stencil into an FBO the texture or render buffer will be removed
1855 * and all flags get lost
1857 if (!(surface->flags & SFLAG_PBO))
1858 surface_init_sysmem(surface);
1859 /* We also get here when the ddraw swapchain is destroyed, for example
1860 * for a mode switch. In this case this surface won't necessarily be
1861 * an implicit surface. We have to mark it lost so that the
1862 * application can restore it after the mode switch. */
1863 surface->flags |= SFLAG_LOST;
1867 /* Load the surface into system memory */
1868 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1869 surface_modify_location(surface, surface->draw_binding, FALSE);
1871 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
1872 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
1873 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1875 context = context_acquire(device, NULL);
1876 gl_info = context->gl_info;
1878 /* Destroy PBOs, but load them into real sysmem before */
1879 if (surface->flags & SFLAG_PBO)
1880 surface_remove_pbo(surface, gl_info);
1882 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1883 * all application-created targets the application has to release the surface
1884 * before calling _Reset
1886 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1889 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1891 list_remove(&entry->entry);
1892 HeapFree(GetProcessHeap(), 0, entry);
1894 list_init(&surface->renderbuffers);
1895 surface->current_renderbuffer = NULL;
1899 /* If we're in a texture, the texture name belongs to the texture.
1900 * Otherwise, destroy it. */
1901 if (surface->container.type != WINED3D_CONTAINER_TEXTURE)
1903 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name);
1904 surface->texture_name = 0;
1905 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name_srgb);
1906 surface->texture_name_srgb = 0;
1908 if (surface->rb_multisample)
1910 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
1911 surface->rb_multisample = 0;
1913 if (surface->rb_resolved)
1915 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
1916 surface->rb_resolved = 0;
1921 context_release(context);
1923 resource_unload(resource);
1926 static const struct wined3d_resource_ops surface_resource_ops =
1931 static const struct wined3d_surface_ops surface_ops =
1933 surface_private_setup,
1934 surface_realize_palette,
1939 /*****************************************************************************
1940 * Initializes the GDI surface, aka creates the DIB section we render to
1941 * The DIB section creation is done by calling GetDC, which will create the
1942 * section and releasing the dc to allow the app to use it. The dib section
1943 * will stay until the surface is released
1945 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1946 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1947 * avoid confusion in the shared surface code.
1950 * WINED3D_OK on success
1951 * The return values of called methods on failure
1953 *****************************************************************************/
1954 static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface)
1958 TRACE("surface %p.\n", surface);
1960 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
1962 ERR("Overlays not yet supported by GDI surfaces.\n");
1963 return WINED3DERR_INVALIDCALL;
1966 /* Sysmem textures have memory already allocated - release it,
1967 * this avoids an unnecessary memcpy. */
1968 hr = surface_create_dib_section(surface);
1971 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
1972 surface->resource.heapMemory = NULL;
1973 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1976 /* We don't mind the nonpow2 stuff in GDI. */
1977 surface->pow2Width = surface->resource.width;
1978 surface->pow2Height = surface->resource.height;
1983 static void gdi_surface_realize_palette(struct wined3d_surface *surface)
1985 struct wined3d_palette *palette = surface->palette;
1987 TRACE("surface %p.\n", surface);
1989 if (!palette) return;
1991 if (surface->flags & SFLAG_DIBSECTION)
1996 TRACE("Updating the DC's palette.\n");
1998 for (i = 0; i < 256; ++i)
2000 col[i].rgbRed = palette->palents[i].peRed;
2001 col[i].rgbGreen = palette->palents[i].peGreen;
2002 col[i].rgbBlue = palette->palents[i].peBlue;
2003 col[i].rgbReserved = 0;
2005 SetDIBColorTable(surface->hDC, 0, 256, col);
2008 /* Update the image because of the palette change. Some games like e.g.
2009 * Red Alert call SetEntries a lot to implement fading. */
2010 /* Tell the swapchain to update the screen. */
2011 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
2013 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2014 if (surface == swapchain->front_buffer)
2016 x11_copy_to_screen(swapchain, NULL);
2021 static void gdi_surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
2023 TRACE("surface %p, rect %s, flags %#x.\n",
2024 surface, wine_dbgstr_rect(rect), flags);
2026 if (!(surface->flags & SFLAG_DIBSECTION))
2030 /* This happens on gdi surfaces if the application set a user pointer
2031 * and resets it. Recreate the DIB section. */
2032 if (FAILED(hr = surface_create_dib_section(surface)))
2034 ERR("Failed to create dib section, hr %#x.\n", hr);
2037 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
2038 surface->resource.heapMemory = NULL;
2039 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2043 static void gdi_surface_unmap(struct wined3d_surface *surface)
2045 TRACE("surface %p.\n", surface);
2047 /* Tell the swapchain to update the screen. */
2048 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
2050 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2051 if (surface == swapchain->front_buffer)
2053 x11_copy_to_screen(swapchain, &surface->lockedRect);
2057 memset(&surface->lockedRect, 0, sizeof(RECT));
2060 static const struct wined3d_surface_ops gdi_surface_ops =
2062 gdi_surface_private_setup,
2063 gdi_surface_realize_palette,
2068 void surface_set_texture_name(struct wined3d_surface *surface, GLuint new_name, BOOL srgb)
2073 TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
2077 name = &surface->texture_name_srgb;
2078 flag = SFLAG_INSRGBTEX;
2082 name = &surface->texture_name;
2083 flag = SFLAG_INTEXTURE;
2086 if (!*name && new_name)
2088 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2089 * surface has no texture name yet. See if we can get rid of this. */
2090 if (surface->flags & flag)
2092 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
2093 surface_modify_location(surface, flag, FALSE);
2098 surface_force_reload(surface);
2101 void surface_set_texture_target(struct wined3d_surface *surface, GLenum target)
2103 TRACE("surface %p, target %#x.\n", surface, target);
2105 if (surface->texture_target != target)
2107 if (target == GL_TEXTURE_RECTANGLE_ARB)
2109 surface->flags &= ~SFLAG_NORMCOORD;
2111 else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2113 surface->flags |= SFLAG_NORMCOORD;
2116 surface->texture_target = target;
2117 surface_force_reload(surface);
2120 /* This call just downloads data, the caller is responsible for binding the
2121 * correct texture. */
2122 /* Context activation is done by the caller. */
2123 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2125 const struct wined3d_format *format = surface->resource.format;
2127 /* Only support read back of converted P8 surfaces. */
2128 if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
2130 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
2136 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2138 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2139 surface, surface->texture_level, format->glFormat, format->glType,
2140 surface->resource.allocatedMemory);
2142 if (surface->flags & SFLAG_PBO)
2144 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2145 checkGLcall("glBindBufferARB");
2146 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
2147 checkGLcall("glGetCompressedTexImageARB");
2148 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2149 checkGLcall("glBindBufferARB");
2153 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
2154 surface->texture_level, surface->resource.allocatedMemory));
2155 checkGLcall("glGetCompressedTexImageARB");
2163 GLenum gl_format = format->glFormat;
2164 GLenum gl_type = format->glType;
2168 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2169 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device))
2171 gl_format = GL_ALPHA;
2172 gl_type = GL_UNSIGNED_BYTE;
2175 if (surface->flags & SFLAG_NONPOW2)
2177 unsigned char alignment = surface->resource.device->surface_alignment;
2178 src_pitch = format->byte_count * surface->pow2Width;
2179 dst_pitch = wined3d_surface_get_pitch(surface);
2180 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
2181 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
2185 mem = surface->resource.allocatedMemory;
2188 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2189 surface, surface->texture_level, gl_format, gl_type, mem);
2191 if (surface->flags & SFLAG_PBO)
2193 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2194 checkGLcall("glBindBufferARB");
2196 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2197 gl_format, gl_type, NULL);
2198 checkGLcall("glGetTexImage");
2200 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2201 checkGLcall("glBindBufferARB");
2205 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2206 gl_format, gl_type, mem);
2207 checkGLcall("glGetTexImage");
2211 if (surface->flags & SFLAG_NONPOW2)
2213 const BYTE *src_data;
2217 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2218 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2219 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2221 * We're doing this...
2223 * instead of boxing the texture :
2224 * |<-texture width ->| -->pow2width| /\
2225 * |111111111111111111| | |
2226 * |222 Texture 222222| boxed empty | texture height
2227 * |3333 Data 33333333| | |
2228 * |444444444444444444| | \/
2229 * ----------------------------------- |
2230 * | boxed empty | boxed empty | pow2height
2232 * -----------------------------------
2235 * we're repacking the data to the expected texture width
2237 * |<-texture width ->| -->pow2width| /\
2238 * |111111111111111111222222222222222| |
2239 * |222333333333333333333444444444444| texture height
2243 * | empty | pow2height
2245 * -----------------------------------
2249 * |<-texture width ->| /\
2250 * |111111111111111111|
2251 * |222222222222222222|texture height
2252 * |333333333333333333|
2253 * |444444444444444444| \/
2254 * --------------------
2256 * this also means that any references to allocatedMemory should work with the data as if were a
2257 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2259 * internally the texture is still stored in a boxed format so any references to textureName will
2260 * get a boxed texture with width pow2width and not a texture of width resource.width.
2262 * Performance should not be an issue, because applications normally do not lock the surfaces when
2263 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2264 * and doesn't have to be re-read. */
2266 dst_data = surface->resource.allocatedMemory;
2267 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
2268 for (y = 1; y < surface->resource.height; ++y)
2270 /* skip the first row */
2271 src_data += src_pitch;
2272 dst_data += dst_pitch;
2273 memcpy(dst_data, src_data, dst_pitch);
2276 HeapFree(GetProcessHeap(), 0, mem);
2280 /* Surface has now been downloaded */
2281 surface->flags |= SFLAG_INSYSMEM;
2284 /* This call just uploads data, the caller is responsible for binding the
2285 * correct texture. */
2286 /* Context activation is done by the caller. */
2287 static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2288 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
2289 BOOL srgb, const struct wined3d_bo_address *data)
2291 UINT update_w = src_rect->right - src_rect->left;
2292 UINT update_h = src_rect->bottom - src_rect->top;
2294 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
2295 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
2296 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
2298 if (surface->resource.map_count)
2300 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
2301 surface->flags |= SFLAG_PIN_SYSMEM;
2304 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2306 update_h *= format->height_scale.numerator;
2307 update_h /= format->height_scale.denominator;
2312 if (data->buffer_object)
2314 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
2315 checkGLcall("glBindBufferARB");
2318 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2320 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1);
2321 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
2322 const BYTE *addr = data->addr;
2325 addr += (src_rect->top / format->block_height) * src_pitch;
2326 addr += (src_rect->left / format->block_width) * format->block_byte_count;
2329 internal = format->glGammaInternal;
2330 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2331 internal = format->rtInternal;
2333 internal = format->glInternal;
2335 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2336 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
2337 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
2339 if (row_length == src_pitch)
2341 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2342 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
2348 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2349 * can't use the unpack row length like below. */
2350 for (row = 0, y = dst_point->y; row < row_count; ++row)
2352 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2353 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
2354 y += format->block_height;
2358 checkGLcall("glCompressedTexSubImage2DARB");
2362 const BYTE *addr = data->addr;
2364 addr += src_rect->top * src_pitch;
2365 addr += src_rect->left * format->byte_count;
2367 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2368 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
2369 update_w, update_h, format->glFormat, format->glType, addr);
2371 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
2372 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
2373 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
2374 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2375 checkGLcall("glTexSubImage2D");
2378 if (data->buffer_object)
2380 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2381 checkGLcall("glBindBufferARB");
2386 if (wined3d_settings.strict_draw_ordering)
2387 gl_info->gl_ops.gl.p_glFlush();
2389 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2391 struct wined3d_device *device = surface->resource.device;
2394 for (i = 0; i < device->context_count; ++i)
2396 context_surface_update(device->contexts[i], surface);
2401 static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
2402 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
2404 BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2405 const struct wined3d_device *device = surface->resource.device;
2406 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2407 BOOL blit_supported = FALSE;
2409 /* Copy the default values from the surface. Below we might perform fixups */
2410 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2411 *format = *surface->resource.format;
2412 *conversion_type = WINED3D_CT_NONE;
2414 /* Ok, now look if we have to do any conversion */
2415 switch (surface->resource.format->id)
2417 case WINED3DFMT_P8_UINT:
2418 /* Below the call to blit_supported is disabled for Wine 1.2
2419 * because the function isn't operating correctly yet. At the
2420 * moment 8-bit blits are handled in software and if certain GL
2421 * extensions are around, surface conversion is performed at
2422 * upload time. The blit_supported call recognizes it as a
2423 * destination fixup. This type of upload 'fixup' and 8-bit to
2424 * 8-bit blits need to be handled by the blit_shader.
2425 * TODO: get rid of this #if 0. */
2427 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2428 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
2429 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
2431 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2433 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2434 * texturing. Further also use conversion in case of color keying.
2435 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2436 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2437 * conflicts with this.
2439 if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
2440 || colorkey_active || !use_texturing)
2442 format->glFormat = GL_RGBA;
2443 format->glInternal = GL_RGBA;
2444 format->glType = GL_UNSIGNED_BYTE;
2445 format->conv_byte_count = 4;
2446 if (colorkey_active)
2447 *conversion_type = WINED3D_CT_PALETTED_CK;
2449 *conversion_type = WINED3D_CT_PALETTED;
2453 case WINED3DFMT_B2G3R3_UNORM:
2454 /* **********************
2455 GL_UNSIGNED_BYTE_3_3_2
2456 ********************** */
2457 if (colorkey_active) {
2458 /* This texture format will never be used.. So do not care about color keying
2459 up until the point in time it will be needed :-) */
2460 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2464 case WINED3DFMT_B5G6R5_UNORM:
2465 if (colorkey_active)
2467 *conversion_type = WINED3D_CT_CK_565;
2468 format->glFormat = GL_RGBA;
2469 format->glInternal = GL_RGB5_A1;
2470 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2471 format->conv_byte_count = 2;
2475 case WINED3DFMT_B5G5R5X1_UNORM:
2476 if (colorkey_active)
2478 *conversion_type = WINED3D_CT_CK_5551;
2479 format->glFormat = GL_BGRA;
2480 format->glInternal = GL_RGB5_A1;
2481 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2482 format->conv_byte_count = 2;
2486 case WINED3DFMT_B8G8R8_UNORM:
2487 if (colorkey_active)
2489 *conversion_type = WINED3D_CT_CK_RGB24;
2490 format->glFormat = GL_RGBA;
2491 format->glInternal = GL_RGBA8;
2492 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2493 format->conv_byte_count = 4;
2497 case WINED3DFMT_B8G8R8X8_UNORM:
2498 if (colorkey_active)
2500 *conversion_type = WINED3D_CT_RGB32_888;
2501 format->glFormat = GL_RGBA;
2502 format->glInternal = GL_RGBA8;
2503 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2504 format->conv_byte_count = 4;
2508 case WINED3DFMT_B8G8R8A8_UNORM:
2509 if (colorkey_active)
2511 *conversion_type = WINED3D_CT_CK_ARGB32;
2512 format->conv_byte_count = 4;
2520 if (*conversion_type != WINED3D_CT_NONE)
2522 format->rtInternal = format->glInternal;
2523 format->glGammaInternal = format->glInternal;
2529 static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
2531 UINT width_mask, height_mask;
2533 if (!rect->left && !rect->top
2534 && rect->right == surface->resource.width
2535 && rect->bottom == surface->resource.height)
2538 /* This assumes power of two block sizes, but NPOT block sizes would be
2540 width_mask = surface->resource.format->block_width - 1;
2541 height_mask = surface->resource.format->block_height - 1;
2543 if (!(rect->left & width_mask) && !(rect->top & height_mask)
2544 && !(rect->right & width_mask) && !(rect->bottom & height_mask))
2550 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
2551 struct wined3d_surface *src_surface, const RECT *src_rect)
2553 const struct wined3d_format *src_format;
2554 const struct wined3d_format *dst_format;
2555 const struct wined3d_gl_info *gl_info;
2556 enum wined3d_conversion_type convert;
2557 struct wined3d_context *context;
2558 struct wined3d_bo_address data;
2559 struct wined3d_format format;
2560 UINT update_w, update_h;
2566 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2567 dst_surface, wine_dbgstr_point(dst_point),
2568 src_surface, wine_dbgstr_rect(src_rect));
2570 src_format = src_surface->resource.format;
2571 dst_format = dst_surface->resource.format;
2573 if (src_format->id != dst_format->id)
2575 WARN("Source and destination surfaces should have the same format.\n");
2576 return WINED3DERR_INVALIDCALL;
2585 else if (dst_point->x < 0 || dst_point->y < 0)
2587 WARN("Invalid destination point.\n");
2588 return WINED3DERR_INVALIDCALL;
2595 r.right = src_surface->resource.width;
2596 r.bottom = src_surface->resource.height;
2599 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
2600 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
2602 WARN("Invalid source rectangle.\n");
2603 return WINED3DERR_INVALIDCALL;
2606 dst_w = dst_surface->resource.width;
2607 dst_h = dst_surface->resource.height;
2609 update_w = src_rect->right - src_rect->left;
2610 update_h = src_rect->bottom - src_rect->top;
2612 if (update_w > dst_w || dst_point->x > dst_w - update_w
2613 || update_h > dst_h || dst_point->y > dst_h - update_h)
2615 WARN("Destination out of bounds.\n");
2616 return WINED3DERR_INVALIDCALL;
2619 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
2621 WARN("Source rectangle not block-aligned.\n");
2622 return WINED3DERR_INVALIDCALL;
2625 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
2626 if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
2628 WARN("Destination rectangle not block-aligned.\n");
2629 return WINED3DERR_INVALIDCALL;
2632 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2633 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
2634 if (convert != WINED3D_CT_NONE || format.convert)
2635 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
2637 context = context_acquire(dst_surface->resource.device, NULL);
2638 gl_info = context->gl_info;
2640 /* Only load the surface for partial updates. For newly allocated texture
2641 * the texture wouldn't be the current location, and we'd upload zeroes
2642 * just to overwrite them again. */
2643 if (update_w == dst_w && update_h == dst_h)
2644 surface_prepare_texture(dst_surface, context, FALSE);
2646 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
2647 surface_bind(dst_surface, context, FALSE);
2649 data.buffer_object = src_surface->pbo;
2650 data.addr = src_surface->resource.allocatedMemory;
2651 src_pitch = wined3d_surface_get_pitch(src_surface);
2653 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
2655 invalidate_active_texture(dst_surface->resource.device, context);
2657 context_release(context);
2659 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2663 /* This call just allocates the texture, the caller is responsible for binding
2664 * the correct texture. */
2665 /* Context activation is done by the caller. */
2666 static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2667 const struct wined3d_format *format, BOOL srgb)
2669 BOOL enable_client_storage = FALSE;
2670 GLsizei width = surface->pow2Width;
2671 GLsizei height = surface->pow2Height;
2672 const BYTE *mem = NULL;
2677 internal = format->glGammaInternal;
2679 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2681 internal = format->rtInternal;
2685 internal = format->glInternal;
2689 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2691 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2693 height *= format->height_scale.numerator;
2694 height /= format->height_scale.denominator;
2697 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",
2698 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
2699 internal, width, height, format->glFormat, format->glType);
2703 if (gl_info->supported[APPLE_CLIENT_STORAGE])
2705 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2706 || !surface->resource.allocatedMemory)
2708 /* In some cases we want to disable client storage.
2709 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2710 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2711 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2712 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2714 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2715 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2716 surface->flags &= ~SFLAG_CLIENT;
2717 enable_client_storage = TRUE;
2721 surface->flags |= SFLAG_CLIENT;
2723 /* Point OpenGL to our allocated texture memory. Do not use
2724 * resource.allocatedMemory here because it might point into a
2725 * PBO. Instead use heapMemory, but get the alignment right. */
2726 mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2727 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2731 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
2733 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
2734 internal, width, height, 0, surface->resource.size, mem));
2735 checkGLcall("glCompressedTexImage2DARB");
2739 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
2740 internal, width, height, 0, format->glFormat, format->glType, mem);
2741 checkGLcall("glTexImage2D");
2744 if (enable_client_storage)
2746 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2747 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2752 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2753 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2754 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2755 /* GL locking is done by the caller */
2756 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
2758 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
2759 struct wined3d_renderbuffer_entry *entry;
2760 GLuint renderbuffer = 0;
2761 unsigned int src_width, src_height;
2762 unsigned int width, height;
2764 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
2766 width = rt->pow2Width;
2767 height = rt->pow2Height;
2771 width = surface->pow2Width;
2772 height = surface->pow2Height;
2775 src_width = surface->pow2Width;
2776 src_height = surface->pow2Height;
2778 /* A depth stencil smaller than the render target is not valid */
2779 if (width > src_width || height > src_height) return;
2781 /* Remove any renderbuffer set if the sizes match */
2782 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
2783 || (width == src_width && height == src_height))
2785 surface->current_renderbuffer = NULL;
2789 /* Look if we've already got a renderbuffer of the correct dimensions */
2790 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2792 if (entry->width == width && entry->height == height)
2794 renderbuffer = entry->id;
2795 surface->current_renderbuffer = entry;
2802 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
2803 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
2804 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
2805 surface->resource.format->glInternal, width, height);
2807 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
2808 entry->width = width;
2809 entry->height = height;
2810 entry->id = renderbuffer;
2811 list_add_head(&surface->renderbuffers, &entry->entry);
2813 surface->current_renderbuffer = entry;
2816 checkGLcall("set_compatible_renderbuffer");
2819 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
2821 const struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2823 TRACE("surface %p.\n", surface);
2825 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
2827 ERR("Surface %p is not on a swapchain.\n", surface);
2831 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
2833 if (swapchain->render_to_fbo)
2835 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2836 return GL_COLOR_ATTACHMENT0;
2838 TRACE("Returning GL_BACK\n");
2841 else if (surface == swapchain->front_buffer)
2843 TRACE("Returning GL_FRONT\n");
2847 FIXME("Higher back buffer, returning GL_BACK\n");
2851 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2852 void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
2854 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
2856 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
2857 /* No partial locking for textures yet. */
2858 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2860 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2863 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
2864 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
2865 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
2866 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
2870 surface->dirtyRect.left = 0;
2871 surface->dirtyRect.top = 0;
2872 surface->dirtyRect.right = surface->resource.width;
2873 surface->dirtyRect.bottom = surface->resource.height;
2876 /* if the container is a texture then mark it dirty. */
2877 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
2879 TRACE("Passing to container.\n");
2880 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
2884 HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
2886 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2889 TRACE("surface %p, srgb %#x.\n", surface, srgb);
2891 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
2893 ERR("Not supported on scratch surfaces.\n");
2894 return WINED3DERR_INVALIDCALL;
2897 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2899 /* Reload if either the texture and sysmem have different ideas about the
2900 * color key, or the actual key values changed. */
2901 if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
2902 && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
2903 || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
2905 TRACE("Reloading because of color keying\n");
2906 /* To perform the color key conversion we need a sysmem copy of
2907 * the surface. Make sure we have it. */
2909 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2910 /* Make sure the texture is reloaded because of the color key change,
2911 * this kills performance though :( */
2912 /* TODO: This is not necessarily needed with hw palettized texture support. */
2913 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2914 /* Switching color keying on / off may change the internal format. */
2916 surface_force_reload(surface);
2918 else if (!(surface->flags & flag))
2920 TRACE("Reloading because surface is dirty.\n");
2924 TRACE("surface is already in texture\n");
2928 /* No partial locking for textures yet. */
2929 surface_load_location(surface, flag, NULL);
2930 surface_evict_sysmem(surface);
2935 /* See also float_16_to_32() in wined3d_private.h */
2936 static inline unsigned short float_32_to_16(const float *in)
2939 float tmp = fabsf(*in);
2940 unsigned int mantissa;
2943 /* Deal with special numbers */
2949 return (*in < 0.0f ? 0xfc00 : 0x7c00);
2951 if (tmp < powf(2, 10))
2957 } while (tmp < powf(2, 10));
2959 else if (tmp >= powf(2, 11))
2965 } while (tmp >= powf(2, 11));
2968 mantissa = (unsigned int)tmp;
2969 if (tmp - mantissa >= 0.5f)
2970 ++mantissa; /* Round to nearest, away from zero. */
2972 exp += 10; /* Normalize the mantissa. */
2973 exp += 15; /* Exponent is encoded with excess 15. */
2975 if (exp > 30) /* too big */
2977 ret = 0x7c00; /* INF */
2981 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2984 mantissa = mantissa >> 1;
2987 ret = mantissa & 0x3ff;
2991 ret = (exp << 10) | (mantissa & 0x3ff);
2994 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
2998 ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
3002 TRACE("Surface %p, container %p of type %#x.\n",
3003 surface, surface->container.u.base, surface->container.type);
3005 switch (surface->container.type)
3007 case WINED3D_CONTAINER_TEXTURE:
3008 return wined3d_texture_incref(surface->container.u.texture);
3010 case WINED3D_CONTAINER_SWAPCHAIN:
3011 return wined3d_swapchain_incref(surface->container.u.swapchain);
3014 ERR("Unhandled container type %#x.\n", surface->container.type);
3015 case WINED3D_CONTAINER_NONE:
3019 refcount = InterlockedIncrement(&surface->resource.ref);
3020 TRACE("%p increasing refcount to %u.\n", surface, refcount);
3025 /* Do not call while under the GL lock. */
3026 ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
3030 TRACE("Surface %p, container %p of type %#x.\n",
3031 surface, surface->container.u.base, surface->container.type);
3033 switch (surface->container.type)
3035 case WINED3D_CONTAINER_TEXTURE:
3036 return wined3d_texture_decref(surface->container.u.texture);
3038 case WINED3D_CONTAINER_SWAPCHAIN:
3039 return wined3d_swapchain_decref(surface->container.u.swapchain);
3042 ERR("Unhandled container type %#x.\n", surface->container.type);
3043 case WINED3D_CONTAINER_NONE:
3047 refcount = InterlockedDecrement(&surface->resource.ref);
3048 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3052 surface_cleanup(surface);
3053 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3055 TRACE("Destroyed surface %p.\n", surface);
3056 HeapFree(GetProcessHeap(), 0, surface);
3062 DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
3064 return resource_set_priority(&surface->resource, priority);
3067 DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
3069 return resource_get_priority(&surface->resource);
3072 void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
3074 TRACE("surface %p.\n", surface);
3076 if (!surface->resource.device->d3d_initialized)
3078 ERR("D3D not initialized.\n");
3082 surface_internal_preload(surface, SRGB_ANY);
3085 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
3087 TRACE("surface %p.\n", surface);
3089 return surface->resource.parent;
3092 struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
3094 TRACE("surface %p.\n", surface);
3096 return &surface->resource;
3099 HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
3101 TRACE("surface %p, flags %#x.\n", surface, flags);
3105 case WINEDDGBS_CANBLT:
3106 case WINEDDGBS_ISBLTDONE:
3110 return WINED3DERR_INVALIDCALL;
3114 HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
3116 TRACE("surface %p, flags %#x.\n", surface, flags);
3118 /* XXX: DDERR_INVALIDSURFACETYPE */
3122 case WINEDDGFS_CANFLIP:
3123 case WINEDDGFS_ISFLIPDONE:
3127 return WINED3DERR_INVALIDCALL;
3131 HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
3133 TRACE("surface %p.\n", surface);
3135 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
3136 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3139 HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
3141 TRACE("surface %p.\n", surface);
3143 surface->flags &= ~SFLAG_LOST;
3147 HRESULT CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
3149 TRACE("surface %p, palette %p.\n", surface, palette);
3151 if (surface->palette == palette)
3153 TRACE("Nop palette change.\n");
3157 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
3158 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3160 surface->palette = palette;
3164 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3165 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
3167 surface->surface_ops->surface_realize_palette(surface);
3173 HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3174 DWORD flags, const struct wined3d_color_key *color_key)
3176 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3178 if (flags & WINEDDCKEY_COLORSPACE)
3180 FIXME(" colorkey value not supported (%08x) !\n", flags);
3181 return WINED3DERR_INVALIDCALL;
3184 /* Dirtify the surface, but only if a key was changed. */
3187 switch (flags & ~WINEDDCKEY_COLORSPACE)
3189 case WINEDDCKEY_DESTBLT:
3190 surface->dst_blt_color_key = *color_key;
3191 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3194 case WINEDDCKEY_DESTOVERLAY:
3195 surface->dst_overlay_color_key = *color_key;
3196 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3199 case WINEDDCKEY_SRCOVERLAY:
3200 surface->src_overlay_color_key = *color_key;
3201 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3204 case WINEDDCKEY_SRCBLT:
3205 surface->src_blt_color_key = *color_key;
3206 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3212 switch (flags & ~WINEDDCKEY_COLORSPACE)
3214 case WINEDDCKEY_DESTBLT:
3215 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3218 case WINEDDCKEY_DESTOVERLAY:
3219 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3222 case WINEDDCKEY_SRCOVERLAY:
3223 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3226 case WINEDDCKEY_SRCBLT:
3227 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3235 struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3237 TRACE("surface %p.\n", surface);
3239 return surface->palette;
3242 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3244 const struct wined3d_format *format = surface->resource.format;
3247 TRACE("surface %p.\n", surface);
3249 if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3251 /* Since compressed formats are block based, pitch means the amount of
3252 * bytes to the next row of block rather than the next row of pixels. */
3253 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3254 pitch = row_block_count * format->block_byte_count;
3258 unsigned char alignment = surface->resource.device->surface_alignment;
3259 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
3260 pitch = (pitch + alignment - 1) & ~(alignment - 1);
3263 TRACE("Returning %u.\n", pitch);
3268 HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem)
3270 TRACE("surface %p, mem %p.\n", surface, mem);
3272 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3274 WARN("Surface is mapped or the DC is in use.\n");
3275 return WINED3DERR_INVALIDCALL;
3278 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3279 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3281 ERR("Not supported on render targets.\n");
3282 return WINED3DERR_INVALIDCALL;
3285 if (mem && mem != surface->resource.allocatedMemory)
3287 void *release = NULL;
3289 /* Do I have to copy the old surface content? */
3290 if (surface->flags & SFLAG_DIBSECTION)
3292 DeleteDC(surface->hDC);
3293 DeleteObject(surface->dib.DIBsection);
3294 surface->dib.bitmap_data = NULL;
3295 surface->resource.allocatedMemory = NULL;
3296 surface->hDC = NULL;
3297 surface->flags &= ~SFLAG_DIBSECTION;
3299 else if (!(surface->flags & SFLAG_USERPTR))
3301 release = surface->resource.heapMemory;
3302 surface->resource.heapMemory = NULL;
3304 surface->resource.allocatedMemory = mem;
3305 surface->flags |= SFLAG_USERPTR;
3307 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3308 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3310 /* For client textures OpenGL has to be notified. */
3311 if (surface->flags & SFLAG_CLIENT)
3312 surface_release_client_storage(surface);
3314 /* Now free the old memory if any. */
3315 HeapFree(GetProcessHeap(), 0, release);
3317 else if (surface->flags & SFLAG_USERPTR)
3319 /* HeapMemory should be NULL already. */
3320 if (surface->resource.heapMemory)
3321 ERR("User pointer surface has heap memory allocated.\n");
3325 surface->resource.allocatedMemory = NULL;
3326 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3328 if (surface->flags & SFLAG_CLIENT)
3329 surface_release_client_storage(surface);
3331 surface_prepare_system_memory(surface);
3334 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3340 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3344 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3346 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3348 WARN("Not an overlay surface.\n");
3349 return WINEDDERR_NOTAOVERLAYSURFACE;
3352 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3353 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3354 surface->overlay_destrect.left = x;
3355 surface->overlay_destrect.top = y;
3356 surface->overlay_destrect.right = x + w;
3357 surface->overlay_destrect.bottom = y + h;
3359 surface_draw_overlay(surface);
3364 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3366 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3368 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3370 TRACE("Not an overlay surface.\n");
3371 return WINEDDERR_NOTAOVERLAYSURFACE;
3374 if (!surface->overlay_dest)
3376 TRACE("Overlay not visible.\n");
3379 return WINEDDERR_OVERLAYNOTVISIBLE;
3382 *x = surface->overlay_destrect.left;
3383 *y = surface->overlay_destrect.top;
3385 TRACE("Returning position %d, %d.\n", *x, *y);
3390 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3391 DWORD flags, struct wined3d_surface *ref)
3393 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3395 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3397 TRACE("Not an overlay surface.\n");
3398 return WINEDDERR_NOTAOVERLAYSURFACE;
3404 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3405 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3407 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3408 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3410 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3412 WARN("Not an overlay surface.\n");
3413 return WINEDDERR_NOTAOVERLAYSURFACE;
3415 else if (!dst_surface)
3417 WARN("Dest surface is NULL.\n");
3418 return WINED3DERR_INVALIDCALL;
3423 surface->overlay_srcrect = *src_rect;
3427 surface->overlay_srcrect.left = 0;
3428 surface->overlay_srcrect.top = 0;
3429 surface->overlay_srcrect.right = surface->resource.width;
3430 surface->overlay_srcrect.bottom = surface->resource.height;
3435 surface->overlay_destrect = *dst_rect;
3439 surface->overlay_destrect.left = 0;
3440 surface->overlay_destrect.top = 0;
3441 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3442 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3445 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3447 surface->overlay_dest = NULL;
3448 list_remove(&surface->overlay_entry);
3451 if (flags & WINEDDOVER_SHOW)
3453 if (surface->overlay_dest != dst_surface)
3455 surface->overlay_dest = dst_surface;
3456 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3459 else if (flags & WINEDDOVER_HIDE)
3461 /* tests show that the rectangles are erased on hide */
3462 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3463 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3464 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3465 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3466 surface->overlay_dest = NULL;
3469 surface_draw_overlay(surface);
3474 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3475 UINT width, UINT height, enum wined3d_format_id format_id,
3476 enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3478 struct wined3d_device *device = surface->resource.device;
3479 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3480 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3481 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3483 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3484 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3487 return WINED3DERR_INVALIDCALL;
3489 if (device->d3d_initialized)
3490 surface->resource.resource_ops->resource_unload(&surface->resource);
3492 if (surface->flags & SFLAG_DIBSECTION)
3494 DeleteDC(surface->hDC);
3495 DeleteObject(surface->dib.DIBsection);
3496 surface->dib.bitmap_data = NULL;
3497 surface->flags &= ~SFLAG_DIBSECTION;
3500 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3501 surface->resource.allocatedMemory = NULL;
3502 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3503 surface->resource.heapMemory = NULL;
3505 surface->resource.width = width;
3506 surface->resource.height = height;
3507 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3508 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3510 surface->pow2Width = width;
3511 surface->pow2Height = height;
3515 surface->pow2Width = surface->pow2Height = 1;
3516 while (surface->pow2Width < width)
3517 surface->pow2Width <<= 1;
3518 while (surface->pow2Height < height)
3519 surface->pow2Height <<= 1;
3522 if (surface->pow2Width != width || surface->pow2Height != height)
3523 surface->flags |= SFLAG_NONPOW2;
3525 surface->flags &= ~SFLAG_NONPOW2;
3527 surface->resource.format = format;
3528 surface->resource.multisample_type = multisample_type;
3529 surface->resource.multisample_quality = multisample_quality;
3530 surface->resource.size = resource_size;
3532 if (!surface_init_sysmem(surface))
3533 return E_OUTOFMEMORY;
3538 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3539 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3541 unsigned short *dst_s;
3545 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3547 for (y = 0; y < h; ++y)
3549 src_f = (const float *)(src + y * pitch_in);
3550 dst_s = (unsigned short *) (dst + y * pitch_out);
3551 for (x = 0; x < w; ++x)
3553 dst_s[x] = float_32_to_16(src_f + x);
3558 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3559 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3561 static const unsigned char convert_5to8[] =
3563 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3564 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3565 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3566 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3568 static const unsigned char convert_6to8[] =
3570 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3571 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3572 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3573 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3574 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3575 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3576 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3577 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3581 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3583 for (y = 0; y < h; ++y)
3585 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3586 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3587 for (x = 0; x < w; ++x)
3589 WORD pixel = src_line[x];
3590 dst_line[x] = 0xff000000
3591 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3592 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3593 | convert_5to8[(pixel & 0x001f)];
3598 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3599 * in both cases we're just setting the X / Alpha channel to 0xff. */
3600 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3601 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3605 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3607 for (y = 0; y < h; ++y)
3609 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3610 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3612 for (x = 0; x < w; ++x)
3614 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3619 static inline BYTE cliptobyte(int x)
3621 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3624 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3625 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3627 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3630 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3632 for (y = 0; y < h; ++y)
3634 const BYTE *src_line = src + y * pitch_in;
3635 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3636 for (x = 0; x < w; ++x)
3638 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3639 * C = Y - 16; D = U - 128; E = V - 128;
3640 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3641 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3642 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3643 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3644 * U and V are shared between the pixels. */
3645 if (!(x & 1)) /* For every even pixel, read new U and V. */
3647 d = (int) src_line[1] - 128;
3648 e = (int) src_line[3] - 128;
3650 g2 = - 100 * d - 208 * e + 128;
3653 c2 = 298 * ((int) src_line[0] - 16);
3654 dst_line[x] = 0xff000000
3655 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3656 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3657 | cliptobyte((c2 + b2) >> 8); /* blue */
3658 /* Scale RGB values to 0..255 range,
3659 * then clip them if still not in range (may be negative),
3660 * then shift them within DWORD if necessary. */
3666 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3667 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3670 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3672 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3674 for (y = 0; y < h; ++y)
3676 const BYTE *src_line = src + y * pitch_in;
3677 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3678 for (x = 0; x < w; ++x)
3680 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3681 * C = Y - 16; D = U - 128; E = V - 128;
3682 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3683 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3684 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3685 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3686 * U and V are shared between the pixels. */
3687 if (!(x & 1)) /* For every even pixel, read new U and V. */
3689 d = (int) src_line[1] - 128;
3690 e = (int) src_line[3] - 128;
3692 g2 = - 100 * d - 208 * e + 128;
3695 c2 = 298 * ((int) src_line[0] - 16);
3696 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3697 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3698 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3699 /* Scale RGB values to 0..255 range,
3700 * then clip them if still not in range (may be negative),
3701 * then shift them within DWORD if necessary. */
3707 struct d3dfmt_convertor_desc
3709 enum wined3d_format_id from, to;
3710 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3713 static const struct d3dfmt_convertor_desc convertors[] =
3715 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3716 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3717 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3718 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3719 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3720 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3723 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from,
3724 enum wined3d_format_id to)
3728 for (i = 0; i < (sizeof(convertors) / sizeof(*convertors)); ++i)
3730 if (convertors[i].from == from && convertors[i].to == to)
3731 return &convertors[i];
3737 /*****************************************************************************
3738 * surface_convert_format
3740 * Creates a duplicate of a surface in a different format. Is used by Blt to
3741 * blit between surfaces with different formats.
3744 * source: Source surface
3745 * fmt: Requested destination format
3747 *****************************************************************************/
3748 static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
3750 struct wined3d_map_desc src_map, dst_map;
3751 const struct d3dfmt_convertor_desc *conv;
3752 struct wined3d_surface *ret = NULL;
3755 conv = find_convertor(source->resource.format->id, to_fmt);
3758 FIXME("Cannot find a conversion function from format %s to %s.\n",
3759 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
3763 wined3d_surface_create(source->resource.device, source->resource.width,
3764 source->resource.height, to_fmt, 0 /* level */, 0 /* usage */, WINED3D_POOL_SCRATCH,
3765 WINED3D_MULTISAMPLE_NONE /* TODO: Multisampled conversion */, 0 /* MultiSampleQuality */,
3766 source->surface_type, WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD,
3767 NULL /* parent */, &wined3d_null_parent_ops, &ret);
3770 ERR("Failed to create a destination surface for conversion.\n");
3774 memset(&src_map, 0, sizeof(src_map));
3775 memset(&dst_map, 0, sizeof(dst_map));
3777 if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
3779 ERR("Failed to lock the source surface.\n");
3780 wined3d_surface_decref(ret);
3783 if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
3785 ERR("Failed to lock the destination surface.\n");
3786 wined3d_surface_unmap(source);
3787 wined3d_surface_decref(ret);
3791 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
3792 source->resource.width, source->resource.height);
3794 wined3d_surface_unmap(ret);
3795 wined3d_surface_unmap(source);
3800 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
3801 unsigned int bpp, UINT pitch, DWORD color)
3808 #define COLORFILL_ROW(type) \
3810 type *d = (type *)buf; \
3811 for (x = 0; x < width; ++x) \
3812 d[x] = (type)color; \
3818 COLORFILL_ROW(BYTE);
3822 COLORFILL_ROW(WORD);
3828 for (x = 0; x < width; ++x, d += 3)
3830 d[0] = (color ) & 0xff;
3831 d[1] = (color >> 8) & 0xff;
3832 d[2] = (color >> 16) & 0xff;
3837 COLORFILL_ROW(DWORD);
3841 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
3842 return WINED3DERR_NOTAVAILABLE;
3845 #undef COLORFILL_ROW
3847 /* Now copy first row. */
3849 for (y = 1; y < height; ++y)
3852 memcpy(buf, first, width * bpp);
3858 struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
3860 return surface_from_resource(resource);
3863 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
3865 TRACE("surface %p.\n", surface);
3867 if (!surface->resource.map_count)
3869 WARN("Trying to unmap unmapped surface.\n");
3870 return WINEDDERR_NOTLOCKED;
3872 --surface->resource.map_count;
3874 surface->surface_ops->surface_unmap(surface);
3879 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
3880 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
3882 const struct wined3d_format *format = surface->resource.format;
3884 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
3885 surface, map_desc, wine_dbgstr_rect(rect), flags);
3887 if (surface->resource.map_count)
3889 WARN("Surface is already mapped.\n");
3890 return WINED3DERR_INVALIDCALL;
3893 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
3894 && !surface_check_block_align(surface, rect))
3896 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
3897 wine_dbgstr_rect(rect), format->block_width, format->block_height);
3899 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
3900 return WINED3DERR_INVALIDCALL;
3903 ++surface->resource.map_count;
3905 if (!(surface->flags & SFLAG_LOCKABLE))
3906 WARN("Trying to lock unlockable surface.\n");
3908 /* Performance optimization: Count how often a surface is mapped, if it is
3909 * mapped regularly do not throw away the system memory copy. This avoids
3910 * the need to download the surface from OpenGL all the time. The surface
3911 * is still downloaded if the OpenGL texture is changed. */
3912 if (!(surface->flags & SFLAG_DYNLOCK))
3914 if (++surface->lockCount > MAXLOCKCOUNT)
3916 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3917 surface->flags |= SFLAG_DYNLOCK;
3921 surface->surface_ops->surface_map(surface, rect, flags);
3923 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
3924 map_desc->row_pitch = surface->resource.width * format->byte_count;
3926 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
3927 map_desc->slice_pitch = 0;
3931 map_desc->data = surface->resource.allocatedMemory;
3932 surface->lockedRect.left = 0;
3933 surface->lockedRect.top = 0;
3934 surface->lockedRect.right = surface->resource.width;
3935 surface->lockedRect.bottom = surface->resource.height;
3939 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
3941 /* Compressed textures are block based, so calculate the offset of
3942 * the block that contains the top-left pixel of the locked rectangle. */
3943 map_desc->data = surface->resource.allocatedMemory
3944 + ((rect->top / format->block_height) * map_desc->row_pitch)
3945 + ((rect->left / format->block_width) * format->block_byte_count);
3949 map_desc->data = surface->resource.allocatedMemory
3950 + (map_desc->row_pitch * rect->top)
3951 + (rect->left * format->byte_count);
3953 surface->lockedRect.left = rect->left;
3954 surface->lockedRect.top = rect->top;
3955 surface->lockedRect.right = rect->right;
3956 surface->lockedRect.bottom = rect->bottom;
3959 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3960 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
3965 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
3967 struct wined3d_map_desc map;
3970 TRACE("surface %p, dc %p.\n", surface, dc);
3972 if (surface->flags & SFLAG_USERPTR)
3974 ERR("Not supported on surfaces with application-provided memory.\n");
3975 return WINEDDERR_NODC;
3978 /* Give more detailed info for ddraw. */
3979 if (surface->flags & SFLAG_DCINUSE)
3980 return WINEDDERR_DCALREADYCREATED;
3982 /* Can't GetDC if the surface is locked. */
3983 if (surface->resource.map_count)
3984 return WINED3DERR_INVALIDCALL;
3986 /* Create a DIB section if there isn't a dc yet. */
3989 if (surface->flags & SFLAG_CLIENT)
3991 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3992 surface_release_client_storage(surface);
3994 hr = surface_create_dib_section(surface);
3996 return WINED3DERR_INVALIDCALL;
3998 /* Use the DIB section from now on if we are not using a PBO. */
3999 if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
4001 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
4002 surface->resource.heapMemory = NULL;
4003 surface->resource.allocatedMemory = surface->dib.bitmap_data;
4007 /* Map the surface. */
4008 hr = wined3d_surface_map(surface, &map, NULL, 0);
4011 ERR("Map failed, hr %#x.\n", hr);
4015 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4016 * activates the allocatedMemory. */
4017 if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4018 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4020 if (surface->resource.format->id == WINED3DFMT_P8_UINT
4021 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4023 /* GetDC on palettized formats is unsupported in D3D9, and the method
4024 * is missing in D3D8, so this should only be used for DX <=7
4025 * surfaces (with non-device palettes). */
4026 const PALETTEENTRY *pal = NULL;
4028 if (surface->palette)
4030 pal = surface->palette->palents;
4034 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4035 struct wined3d_surface *dds_primary = swapchain->front_buffer;
4037 if (dds_primary && dds_primary->palette)
4038 pal = dds_primary->palette->palents;
4046 for (i = 0; i < 256; ++i)
4048 col[i].rgbRed = pal[i].peRed;
4049 col[i].rgbGreen = pal[i].peGreen;
4050 col[i].rgbBlue = pal[i].peBlue;
4051 col[i].rgbReserved = 0;
4053 SetDIBColorTable(surface->hDC, 0, 256, col);
4057 surface->flags |= SFLAG_DCINUSE;
4060 TRACE("Returning dc %p.\n", *dc);
4065 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4067 TRACE("surface %p, dc %p.\n", surface, dc);
4069 if (!(surface->flags & SFLAG_DCINUSE))
4070 return WINEDDERR_NODC;
4072 if (surface->hDC != dc)
4074 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4076 return WINEDDERR_NODC;
4079 /* Copy the contents of the DIB over to the PBO. */
4080 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4081 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4083 /* We locked first, so unlock now. */
4084 wined3d_surface_unmap(surface);
4086 surface->flags &= ~SFLAG_DCINUSE;
4091 HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4093 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4099 FIXME("Ignoring flags %#x.\n", flags);
4101 WARN("Ignoring flags %#x.\n", flags);
4104 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
4106 ERR("Not supported on swapchain surfaces.\n");
4107 return WINEDDERR_NOTFLIPPABLE;
4110 /* Flipping is only supported on render targets and overlays. */
4111 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
4113 WARN("Tried to flip a non-render target, non-overlay surface.\n");
4114 return WINEDDERR_NOTFLIPPABLE;
4117 flip_surface(surface, override);
4119 /* Update overlays if they're visible. */
4120 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4121 return surface_draw_overlay(surface);
4126 /* Do not call while under the GL lock. */
4127 void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4129 struct wined3d_device *device = surface->resource.device;
4131 TRACE("iface %p, srgb %#x.\n", surface, srgb);
4133 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4135 struct wined3d_texture *texture = surface->container.u.texture;
4137 TRACE("Passing to container (%p).\n", texture);
4138 texture->texture_ops->texture_preload(texture, srgb);
4142 struct wined3d_context *context;
4144 TRACE("(%p) : About to load surface\n", surface);
4146 /* TODO: Use already acquired context when possible. */
4147 context = context_acquire(device, NULL);
4149 surface_load(surface, srgb == SRGB_SRGB);
4151 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4153 /* Tell opengl to try and keep this texture in video ram (well mostly) */
4157 context->gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &surface->texture_name, &tmp);
4161 context_release(context);
4165 /* Read the framebuffer back into the surface */
4166 static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4168 struct wined3d_device *device = surface->resource.device;
4169 const struct wined3d_gl_info *gl_info;
4170 struct wined3d_context *context;
4174 BYTE *row, *top, *bottom;
4178 BOOL srcIsUpsideDown;
4183 context = context_acquire(device, surface);
4184 context_apply_blit_state(context, device);
4185 gl_info = context->gl_info;
4189 /* Select the correct read buffer, and give some debug output.
4190 * There is no need to keep track of the current read buffer or reset it, every part of the code
4191 * that reads sets the read buffer as desired.
4193 if (surface_is_offscreen(surface))
4195 /* Mapping the primary render target which is not on a swapchain.
4196 * Read from the back buffer. */
4197 TRACE("Mapping offscreen render target.\n");
4198 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4199 srcIsUpsideDown = TRUE;
4203 /* Onscreen surfaces are always part of a swapchain */
4204 GLenum buffer = surface_get_gl_buffer(surface);
4205 TRACE("Mapping %#x buffer.\n", buffer);
4206 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
4207 checkGLcall("glReadBuffer");
4208 srcIsUpsideDown = FALSE;
4211 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4214 local_rect.left = 0;
4216 local_rect.right = surface->resource.width;
4217 local_rect.bottom = surface->resource.height;
4223 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4225 switch (surface->resource.format->id)
4227 case WINED3DFMT_P8_UINT:
4229 if (primary_render_target_is_p8(device))
4231 /* In case of P8 render targets the index is stored in the alpha component */
4233 type = GL_UNSIGNED_BYTE;
4235 bpp = surface->resource.format->byte_count;
4239 /* GL can't return palettized data, so read ARGB pixels into a
4240 * separate block of memory and convert them into palettized format
4241 * in software. Slow, but if the app means to use palettized render
4242 * targets and locks it...
4244 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4245 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4246 * for the color channels when palettizing the colors.
4249 type = GL_UNSIGNED_BYTE;
4251 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4254 ERR("Out of memory\n");
4258 bpp = surface->resource.format->byte_count * 3;
4265 fmt = surface->resource.format->glFormat;
4266 type = surface->resource.format->glType;
4267 bpp = surface->resource.format->byte_count;
4270 if (surface->flags & SFLAG_PBO)
4272 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4273 checkGLcall("glBindBufferARB");
4276 ERR("mem not null for pbo -- unexpected\n");
4281 /* Save old pixel store pack state */
4282 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4283 checkGLcall("glGetIntegerv");
4284 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4285 checkGLcall("glGetIntegerv");
4286 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4287 checkGLcall("glGetIntegerv");
4289 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4290 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4291 checkGLcall("glPixelStorei");
4292 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4293 checkGLcall("glPixelStorei");
4294 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4295 checkGLcall("glPixelStorei");
4297 gl_info->gl_ops.gl.p_glReadPixels(local_rect.left,
4298 !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4299 local_rect.right - local_rect.left,
4300 local_rect.bottom - local_rect.top,
4302 checkGLcall("glReadPixels");
4304 /* Reset previous pixel store pack state */
4305 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4306 checkGLcall("glPixelStorei");
4307 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4308 checkGLcall("glPixelStorei");
4309 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4310 checkGLcall("glPixelStorei");
4312 if (surface->flags & SFLAG_PBO)
4314 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4315 checkGLcall("glBindBufferARB");
4317 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4318 * to get a pointer to it and perform the flipping in software. This is a lot
4319 * faster than calling glReadPixels for each line. In case we want more speed
4320 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4321 if (!srcIsUpsideDown)
4323 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4324 checkGLcall("glBindBufferARB");
4326 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4327 checkGLcall("glMapBufferARB");
4331 /* TODO: Merge this with the palettization loop below for P8 targets */
4332 if(!srcIsUpsideDown) {
4334 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4335 Flip the lines in software */
4336 len = (local_rect.right - local_rect.left) * bpp;
4337 off = local_rect.left * bpp;
4339 row = HeapAlloc(GetProcessHeap(), 0, len);
4341 ERR("Out of memory\n");
4342 if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4343 HeapFree(GetProcessHeap(), 0, mem);
4348 top = mem + pitch * local_rect.top;
4349 bottom = mem + pitch * (local_rect.bottom - 1);
4350 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4351 memcpy(row, top + off, len);
4352 memcpy(top + off, bottom + off, len);
4353 memcpy(bottom + off, row, len);
4357 HeapFree(GetProcessHeap(), 0, row);
4359 /* Unmap the temp PBO buffer */
4360 if (surface->flags & SFLAG_PBO)
4362 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4363 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4368 context_release(context);
4370 /* For P8 textures we need to perform an inverse palette lookup. This is
4371 * done by searching for a palette index which matches the RGB value.
4372 * Note this isn't guaranteed to work when there are multiple entries for
4373 * the same color but we have no choice. In case of P8 render targets,
4374 * the index is stored in the alpha component so no conversion is needed. */
4375 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4377 const PALETTEENTRY *pal = NULL;
4378 DWORD width = pitch / 3;
4381 if (surface->palette)
4383 pal = surface->palette->palents;
4387 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4388 HeapFree(GetProcessHeap(), 0, mem);
4392 for(y = local_rect.top; y < local_rect.bottom; y++) {
4393 for(x = local_rect.left; x < local_rect.right; x++) {
4394 /* start lines pixels */
4395 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4396 const BYTE *green = blue + 1;
4397 const BYTE *red = green + 1;
4399 for(c = 0; c < 256; c++) {
4400 if(*red == pal[c].peRed &&
4401 *green == pal[c].peGreen &&
4402 *blue == pal[c].peBlue)
4404 *((BYTE *) dest + y * width + x) = c;
4410 HeapFree(GetProcessHeap(), 0, mem);
4414 /* Read the framebuffer contents into a texture. Note that this function
4415 * doesn't do any kind of flipping. Using this on an onscreen surface will
4416 * result in a flipped D3D texture. */
4417 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4419 struct wined3d_device *device = surface->resource.device;
4420 const struct wined3d_gl_info *gl_info;
4421 struct wined3d_context *context;
4423 context = context_acquire(device, surface);
4424 gl_info = context->gl_info;
4425 device_invalidate_state(device, STATE_FRAMEBUFFER);
4427 surface_prepare_texture(surface, context, srgb);
4428 surface_bind_and_dirtify(surface, context, srgb);
4430 TRACE("Reading back offscreen render target %p.\n", surface);
4434 if (surface_is_offscreen(surface))
4435 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4437 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
4438 checkGLcall("glReadBuffer");
4440 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4441 0, 0, 0, 0, surface->resource.width, surface->resource.height);
4442 checkGLcall("glCopyTexSubImage2D");
4446 context_release(context);
4449 /* Context activation is done by the caller. */
4450 static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4451 struct wined3d_context *context, BOOL srgb)
4453 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4454 enum wined3d_conversion_type convert;
4455 struct wined3d_format format;
4457 if (surface->flags & alloc_flag) return;
4459 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4460 if (convert != WINED3D_CT_NONE || format.convert)
4461 surface->flags |= SFLAG_CONVERTED;
4462 else surface->flags &= ~SFLAG_CONVERTED;
4464 surface_bind_and_dirtify(surface, context, srgb);
4465 surface_allocate_surface(surface, context->gl_info, &format, srgb);
4466 surface->flags |= alloc_flag;
4469 /* Context activation is done by the caller. */
4470 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4472 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4474 struct wined3d_texture *texture = surface->container.u.texture;
4475 UINT sub_count = texture->level_count * texture->layer_count;
4478 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4480 for (i = 0; i < sub_count; ++i)
4482 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4483 surface_prepare_texture_internal(s, context, srgb);
4489 surface_prepare_texture_internal(surface, context, srgb);
4492 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4496 if (surface->rb_multisample)
4499 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4500 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4501 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4502 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4503 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4507 if (surface->rb_resolved)
4510 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4511 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4512 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4513 surface->pow2Width, surface->pow2Height);
4514 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4518 static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4519 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4521 struct wined3d_device *device = surface->resource.device;
4522 UINT pitch = wined3d_surface_get_pitch(surface);
4523 const struct wined3d_gl_info *gl_info;
4524 struct wined3d_context *context;
4528 surface_get_rect(surface, rect, &local_rect);
4530 mem += local_rect.top * pitch + local_rect.left * bpp;
4531 w = local_rect.right - local_rect.left;
4532 h = local_rect.bottom - local_rect.top;
4534 /* Activate the correct context for the render target */
4535 context = context_acquire(device, surface);
4536 context_apply_blit_state(context, device);
4537 gl_info = context->gl_info;
4541 if (!surface_is_offscreen(surface))
4543 GLenum buffer = surface_get_gl_buffer(surface);
4544 TRACE("Unlocking %#x buffer.\n", buffer);
4545 context_set_draw_buffer(context, buffer);
4547 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4548 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, -1.0f);
4552 /* Primary offscreen render target */
4553 TRACE("Offscreen render target.\n");
4554 context_set_draw_buffer(context, device->offscreenBuffer);
4556 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, 1.0f);
4559 gl_info->gl_ops.gl.p_glRasterPos3i(local_rect.left, local_rect.top, 1);
4560 checkGLcall("glRasterPos3i");
4562 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4563 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4565 if (surface->flags & SFLAG_PBO)
4567 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4568 checkGLcall("glBindBufferARB");
4571 gl_info->gl_ops.gl.p_glDrawPixels(w, h, fmt, type, mem);
4572 checkGLcall("glDrawPixels");
4574 if (surface->flags & SFLAG_PBO)
4576 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4577 checkGLcall("glBindBufferARB");
4580 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4581 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4585 if (wined3d_settings.strict_draw_ordering
4586 || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4587 && surface->container.u.swapchain->front_buffer == surface))
4588 gl_info->gl_ops.gl.p_glFlush();
4590 context_release(context);
4593 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4595 /* FIXME: Is this really how color keys are supposed to work? I think it
4596 * makes more sense to compare the individual channels. */
4597 return color >= color_key->color_space_low_value
4598 && color <= color_key->color_space_high_value;
4601 void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4603 const struct wined3d_device *device = surface->resource.device;
4604 const struct wined3d_palette *pal = surface->palette;
4605 BOOL index_in_alpha = FALSE;
4608 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4609 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4610 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4611 * duplicate entries. Store the color key in the unused alpha component to speed the
4612 * download up and to make conversion unneeded. */
4613 index_in_alpha = primary_render_target_is_p8(device);
4617 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4620 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4621 * there's no palette at this time. */
4622 for (i = 0; i < 256; i++) table[i][3] = i;
4627 TRACE("Using surface palette %p\n", pal);
4628 /* Get the surface's palette */
4629 for (i = 0; i < 256; ++i)
4631 table[i][0] = pal->palents[i].peRed;
4632 table[i][1] = pal->palents[i].peGreen;
4633 table[i][2] = pal->palents[i].peBlue;
4635 /* When index_in_alpha is set the palette index is stored in the
4636 * alpha component. In case of a readback we can then read
4637 * GL_ALPHA. Color keying is handled in BltOverride using a
4638 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4639 * color key itself is passed to glAlphaFunc in other cases the
4640 * alpha component of pixels that should be masked away is set to 0. */
4643 else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4645 else if (pal->flags & WINEDDPCAPS_ALPHA)
4646 table[i][3] = pal->palents[i].peFlags;
4653 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4654 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4659 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4660 src, dst, pitch, width, height, outpitch, conversion_type, surface);
4662 switch (conversion_type)
4664 case WINED3D_CT_NONE:
4666 memcpy(dst, src, pitch * height);
4670 case WINED3D_CT_PALETTED:
4671 case WINED3D_CT_PALETTED_CK:
4676 d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4678 for (y = 0; y < height; y++)
4680 source = src + pitch * y;
4681 dest = dst + outpitch * y;
4682 /* This is an 1 bpp format, using the width here is fine */
4683 for (x = 0; x < width; x++) {
4684 BYTE color = *source++;
4685 *dest++ = table[color][0];
4686 *dest++ = table[color][1];
4687 *dest++ = table[color][2];
4688 *dest++ = table[color][3];
4694 case WINED3D_CT_CK_565:
4696 /* Converting the 565 format in 5551 packed to emulate color-keying.
4698 Note : in all these conversion, it would be best to average the averaging
4699 pixels to get the color of the pixel that will be color-keyed to
4700 prevent 'color bleeding'. This will be done later on if ever it is
4703 Note2: Nvidia documents say that their driver does not support alpha + color keying
4704 on the same surface and disables color keying in such a case
4710 TRACE("Color keyed 565\n");
4712 for (y = 0; y < height; y++) {
4713 Source = (const WORD *)(src + y * pitch);
4714 Dest = (WORD *) (dst + y * outpitch);
4715 for (x = 0; x < width; x++ ) {
4716 WORD color = *Source++;
4717 *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
4718 if (!color_in_range(&surface->src_blt_color_key, color))
4726 case WINED3D_CT_CK_5551:
4728 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4732 TRACE("Color keyed 5551\n");
4733 for (y = 0; y < height; y++) {
4734 Source = (const WORD *)(src + y * pitch);
4735 Dest = (WORD *) (dst + y * outpitch);
4736 for (x = 0; x < width; x++ ) {
4737 WORD color = *Source++;
4739 if (!color_in_range(&surface->src_blt_color_key, color))
4742 *Dest &= ~(1 << 15);
4749 case WINED3D_CT_CK_RGB24:
4751 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4753 for (y = 0; y < height; y++)
4755 source = src + pitch * y;
4756 dest = dst + outpitch * y;
4757 for (x = 0; x < width; x++) {
4758 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4759 DWORD dstcolor = color << 8;
4760 if (!color_in_range(&surface->src_blt_color_key, color))
4762 *(DWORD*)dest = dstcolor;
4770 case WINED3D_CT_RGB32_888:
4772 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4774 for (y = 0; y < height; y++)
4776 source = src + pitch * y;
4777 dest = dst + outpitch * y;
4778 for (x = 0; x < width; x++) {
4779 DWORD color = 0xffffff & *(const DWORD*)source;
4780 DWORD dstcolor = color << 8;
4781 if (!color_in_range(&surface->src_blt_color_key, color))
4783 *(DWORD*)dest = dstcolor;
4791 case WINED3D_CT_CK_ARGB32:
4794 for (y = 0; y < height; ++y)
4796 source = src + pitch * y;
4797 dest = dst + outpitch * y;
4798 for (x = 0; x < width; ++x)
4800 DWORD color = *(const DWORD *)source;
4801 if (color_in_range(&surface->src_blt_color_key, color))
4802 color &= ~0xff000000;
4803 *(DWORD*)dest = color;
4812 ERR("Unsupported conversion type %#x.\n", conversion_type);
4817 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
4819 /* Flip the surface contents */
4824 front->hDC = back->hDC;
4828 /* Flip the DIBsection */
4830 HBITMAP tmp = front->dib.DIBsection;
4831 front->dib.DIBsection = back->dib.DIBsection;
4832 back->dib.DIBsection = tmp;
4835 /* Flip the surface data */
4839 tmp = front->dib.bitmap_data;
4840 front->dib.bitmap_data = back->dib.bitmap_data;
4841 back->dib.bitmap_data = tmp;
4843 tmp = front->resource.allocatedMemory;
4844 front->resource.allocatedMemory = back->resource.allocatedMemory;
4845 back->resource.allocatedMemory = tmp;
4847 tmp = front->resource.heapMemory;
4848 front->resource.heapMemory = back->resource.heapMemory;
4849 back->resource.heapMemory = tmp;
4854 GLuint tmp_pbo = front->pbo;
4855 front->pbo = back->pbo;
4856 back->pbo = tmp_pbo;
4859 /* Flip the opengl texture */
4863 tmp = back->texture_name;
4864 back->texture_name = front->texture_name;
4865 front->texture_name = tmp;
4867 tmp = back->texture_name_srgb;
4868 back->texture_name_srgb = front->texture_name_srgb;
4869 front->texture_name_srgb = tmp;
4871 tmp = back->rb_multisample;
4872 back->rb_multisample = front->rb_multisample;
4873 front->rb_multisample = tmp;
4875 tmp = back->rb_resolved;
4876 back->rb_resolved = front->rb_resolved;
4877 front->rb_resolved = tmp;
4879 resource_unload(&back->resource);
4880 resource_unload(&front->resource);
4884 DWORD tmp_flags = back->flags;
4885 back->flags = front->flags;
4886 front->flags = tmp_flags;
4890 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4891 * pixel copy calls. */
4892 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
4893 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
4895 struct wined3d_device *device = dst_surface->resource.device;
4896 const struct wined3d_gl_info *gl_info;
4899 struct wined3d_context *context;
4900 BOOL upsidedown = FALSE;
4901 RECT dst_rect = *dst_rect_in;
4904 if (dst_surface->container.type == WINED3D_CONTAINER_TEXTURE)
4905 dst_target = dst_surface->container.u.texture->target;
4907 dst_target = dst_surface->texture_target;
4909 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4910 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4912 if(dst_rect.top > dst_rect.bottom) {
4913 UINT tmp = dst_rect.bottom;
4914 dst_rect.bottom = dst_rect.top;
4919 context = context_acquire(device, src_surface);
4920 gl_info = context->gl_info;
4921 context_apply_blit_state(context, device);
4922 surface_internal_preload(dst_surface, SRGB_RGB);
4925 /* Bind the target texture */
4926 context_bind_texture(context, dst_target, dst_surface->texture_name);
4927 if (surface_is_offscreen(src_surface))
4929 TRACE("Reading from an offscreen target\n");
4930 upsidedown = !upsidedown;
4931 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4935 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
4937 checkGLcall("glReadBuffer");
4939 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
4940 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
4942 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4944 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4946 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4947 ERR("Texture filtering not supported in direct blit.\n");
4949 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4950 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4952 ERR("Texture filtering not supported in direct blit\n");
4956 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4957 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4959 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
4960 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4961 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
4962 src_rect->left, src_surface->resource.height - src_rect->bottom,
4963 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4967 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
4968 /* I have to process this row by row to swap the image,
4969 * otherwise it would be upside down, so stretching in y direction
4970 * doesn't cost extra time
4972 * However, stretching in x direction can be avoided if not necessary
4974 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
4975 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4977 /* Well, that stuff works, but it's very slow.
4978 * find a better way instead
4982 for (col = dst_rect.left; col < dst_rect.right; ++col)
4984 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4985 dst_rect.left + col /* x offset */, row /* y offset */,
4986 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
4991 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4992 dst_rect.left /* x offset */, row /* y offset */,
4993 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
4997 checkGLcall("glCopyTexSubImage2D");
5000 context_release(context);
5002 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5003 * path is never entered
5005 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5008 /* Uses the hardware to stretch and flip the image */
5009 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5010 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5012 struct wined3d_device *device = dst_surface->resource.device;
5013 struct wined3d_swapchain *src_swapchain = NULL;
5014 GLuint src, backup = 0;
5015 float left, right, top, bottom; /* Texture coordinates */
5016 UINT fbwidth = src_surface->resource.width;
5017 UINT fbheight = src_surface->resource.height;
5018 const struct wined3d_gl_info *gl_info;
5019 struct wined3d_context *context;
5020 GLenum drawBuffer = GL_BACK;
5021 GLenum texture_target;
5022 BOOL noBackBufferBackup;
5024 BOOL upsidedown = FALSE;
5025 RECT dst_rect = *dst_rect_in;
5027 TRACE("Using hwstretch blit\n");
5028 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5029 context = context_acquire(device, src_surface);
5030 gl_info = context->gl_info;
5031 context_apply_blit_state(context, device);
5032 surface_internal_preload(dst_surface, SRGB_RGB);
5034 src_offscreen = surface_is_offscreen(src_surface);
5035 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5036 if (!noBackBufferBackup && !src_surface->texture_name)
5038 /* Get it a description */
5039 surface_internal_preload(src_surface, SRGB_RGB);
5043 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5044 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5046 if (context->aux_buffers >= 2)
5048 /* Got more than one aux buffer? Use the 2nd aux buffer */
5049 drawBuffer = GL_AUX1;
5051 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5053 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5054 drawBuffer = GL_AUX0;
5057 if (noBackBufferBackup)
5059 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
5060 checkGLcall("glGenTextures");
5061 context_bind_texture(context, GL_TEXTURE_2D, backup);
5062 texture_target = GL_TEXTURE_2D;
5066 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5067 * we are reading from the back buffer, the backup can be used as source texture
5069 texture_target = src_surface->texture_target;
5070 context_bind_texture(context, texture_target, src_surface->texture_name);
5071 gl_info->gl_ops.gl.p_glEnable(texture_target);
5072 checkGLcall("glEnable(texture_target)");
5074 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5075 src_surface->flags &= ~SFLAG_INTEXTURE;
5078 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5079 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5081 if(dst_rect.top > dst_rect.bottom) {
5082 UINT tmp = dst_rect.bottom;
5083 dst_rect.bottom = dst_rect.top;
5090 TRACE("Reading from an offscreen target\n");
5091 upsidedown = !upsidedown;
5092 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5096 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5099 /* TODO: Only back up the part that will be overwritten */
5100 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
5102 checkGLcall("glCopyTexSubImage2D");
5104 /* No issue with overriding these - the sampler is dirty due to blit usage */
5105 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5106 wined3d_gl_mag_filter(magLookup, filter));
5107 checkGLcall("glTexParameteri");
5108 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5109 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5110 checkGLcall("glTexParameteri");
5112 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5113 src_swapchain = src_surface->container.u.swapchain;
5114 if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
5116 src = backup ? backup : src_surface->texture_name;
5120 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
5121 checkGLcall("glReadBuffer(GL_FRONT)");
5123 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
5124 checkGLcall("glGenTextures(1, &src)");
5125 context_bind_texture(context, GL_TEXTURE_2D, src);
5127 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5128 * out for power of 2 sizes
5130 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5131 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5132 checkGLcall("glTexImage2D");
5133 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
5135 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5136 checkGLcall("glTexParameteri");
5137 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5138 checkGLcall("glTexParameteri");
5140 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
5141 checkGLcall("glReadBuffer(GL_BACK)");
5143 if (texture_target != GL_TEXTURE_2D)
5145 gl_info->gl_ops.gl.p_glDisable(texture_target);
5146 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5147 texture_target = GL_TEXTURE_2D;
5150 checkGLcall("glEnd and previous");
5152 left = src_rect->left;
5153 right = src_rect->right;
5157 top = src_surface->resource.height - src_rect->top;
5158 bottom = src_surface->resource.height - src_rect->bottom;
5162 top = src_surface->resource.height - src_rect->bottom;
5163 bottom = src_surface->resource.height - src_rect->top;
5166 if (src_surface->flags & SFLAG_NORMCOORD)
5168 left /= src_surface->pow2Width;
5169 right /= src_surface->pow2Width;
5170 top /= src_surface->pow2Height;
5171 bottom /= src_surface->pow2Height;
5174 /* draw the source texture stretched and upside down. The correct surface is bound already */
5175 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5176 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5178 context_set_draw_buffer(context, drawBuffer);
5179 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
5181 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5183 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
5184 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5187 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
5188 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
5191 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
5192 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5195 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
5196 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
5197 gl_info->gl_ops.gl.p_glEnd();
5198 checkGLcall("glEnd and previous");
5200 if (texture_target != dst_surface->texture_target)
5202 gl_info->gl_ops.gl.p_glDisable(texture_target);
5203 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
5204 texture_target = dst_surface->texture_target;
5207 /* Now read the stretched and upside down image into the destination texture */
5208 context_bind_texture(context, texture_target, dst_surface->texture_name);
5209 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
5211 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5212 0, 0, /* We blitted the image to the origin */
5213 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5214 checkGLcall("glCopyTexSubImage2D");
5216 if (drawBuffer == GL_BACK)
5218 /* Write the back buffer backup back. */
5221 if (texture_target != GL_TEXTURE_2D)
5223 gl_info->gl_ops.gl.p_glDisable(texture_target);
5224 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5225 texture_target = GL_TEXTURE_2D;
5227 context_bind_texture(context, GL_TEXTURE_2D, backup);
5231 if (texture_target != src_surface->texture_target)
5233 gl_info->gl_ops.gl.p_glDisable(texture_target);
5234 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
5235 texture_target = src_surface->texture_target;
5237 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5240 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5242 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
5243 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
5246 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5247 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5250 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5251 (float)fbheight / (float)src_surface->pow2Height);
5252 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
5255 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5256 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
5257 gl_info->gl_ops.gl.p_glEnd();
5259 gl_info->gl_ops.gl.p_glDisable(texture_target);
5260 checkGLcall("glDisable(texture_target)");
5263 if (src != src_surface->texture_name && src != backup)
5265 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
5266 checkGLcall("glDeleteTextures(1, &src)");
5270 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
5271 checkGLcall("glDeleteTextures(1, &backup)");
5276 if (wined3d_settings.strict_draw_ordering)
5277 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5279 context_release(context);
5281 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5282 * path is never entered
5284 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5287 /* Front buffer coordinates are always full screen coordinates, but our GL
5288 * drawable is limited to the window's client area. The sysmem and texture
5289 * copies do have the full screen size. Note that GL has a bottom-left
5290 * origin, while D3D has a top-left origin. */
5291 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5293 UINT drawable_height;
5295 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5296 && surface == surface->container.u.swapchain->front_buffer)
5298 POINT offset = {0, 0};
5301 ScreenToClient(window, &offset);
5302 OffsetRect(rect, offset.x, offset.y);
5304 GetClientRect(window, &windowsize);
5305 drawable_height = windowsize.bottom - windowsize.top;
5309 drawable_height = surface->resource.height;
5312 rect->top = drawable_height - rect->top;
5313 rect->bottom = drawable_height - rect->bottom;
5316 static void surface_blt_to_drawable(const struct wined3d_device *device,
5317 enum wined3d_texture_filter_type filter, BOOL color_key,
5318 struct wined3d_surface *src_surface, const RECT *src_rect_in,
5319 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5321 const struct wined3d_gl_info *gl_info;
5322 struct wined3d_context *context;
5323 RECT src_rect, dst_rect;
5325 src_rect = *src_rect_in;
5326 dst_rect = *dst_rect_in;
5328 /* Make sure the surface is up-to-date. This should probably use
5329 * surface_load_location() and worry about the destination surface too,
5330 * unless we're overwriting it completely. */
5331 surface_internal_preload(src_surface, SRGB_RGB);
5333 /* Activate the destination context, set it up for blitting */
5334 context = context_acquire(device, dst_surface);
5335 gl_info = context->gl_info;
5336 context_apply_blit_state(context, device);
5338 if (!surface_is_offscreen(dst_surface))
5339 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5341 device->blitter->set_shader(device->blit_priv, context, src_surface);
5347 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
5348 checkGLcall("glEnable(GL_ALPHA_TEST)");
5350 /* When the primary render target uses P8, the alpha component
5351 * contains the palette index. Which means that the colorkey is one of
5352 * the palette entries. In other cases pixels that should be masked
5353 * away have alpha set to 0. */
5354 if (primary_render_target_is_p8(device))
5355 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
5356 (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5358 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
5359 checkGLcall("glAlphaFunc");
5363 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5364 checkGLcall("glDisable(GL_ALPHA_TEST)");
5367 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5371 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5372 checkGLcall("glDisable(GL_ALPHA_TEST)");
5377 /* Leave the opengl state valid for blitting */
5378 device->blitter->unset_shader(context->gl_info);
5380 if (wined3d_settings.strict_draw_ordering
5381 || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5382 && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5383 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5385 context_release(context);
5388 /* Do not call while under the GL lock. */
5389 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5391 struct wined3d_device *device = s->resource.device;
5392 const struct blit_shader *blitter;
5394 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5395 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5398 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5399 return WINED3DERR_INVALIDCALL;
5402 return blitter->color_fill(device, s, rect, color);
5405 /* Do not call while under the GL lock. */
5406 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5407 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5408 enum wined3d_texture_filter_type filter)
5410 struct wined3d_device *device = dst_surface->resource.device;
5411 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5412 struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5414 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5415 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5416 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5418 /* Get the swapchain. One of the surfaces has to be a primary surface */
5419 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5421 WARN("Destination is in sysmem, rejecting gl blt\n");
5422 return WINED3DERR_INVALIDCALL;
5425 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5426 dstSwapchain = dst_surface->container.u.swapchain;
5430 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5432 WARN("Src is in sysmem, rejecting gl blt\n");
5433 return WINED3DERR_INVALIDCALL;
5436 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5437 srcSwapchain = src_surface->container.u.swapchain;
5440 /* Early sort out of cases where no render target is used */
5441 if (!dstSwapchain && !srcSwapchain
5442 && src_surface != device->fb.render_targets[0]
5443 && dst_surface != device->fb.render_targets[0])
5445 TRACE("No surface is render target, not using hardware blit.\n");
5446 return WINED3DERR_INVALIDCALL;
5449 /* No destination color keying supported */
5450 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5452 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5453 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5454 return WINED3DERR_INVALIDCALL;
5457 if (dstSwapchain && dstSwapchain == srcSwapchain)
5459 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5460 return WINED3DERR_INVALIDCALL;
5463 if (dstSwapchain && srcSwapchain)
5465 FIXME("Implement hardware blit between two different swapchains\n");
5466 return WINED3DERR_INVALIDCALL;
5471 /* Handled with regular texture -> swapchain blit */
5472 if (src_surface == device->fb.render_targets[0])
5473 TRACE("Blit from active render target to a swapchain\n");
5475 else if (srcSwapchain && dst_surface == device->fb.render_targets[0])
5477 FIXME("Implement blit from a swapchain to the active render target\n");
5478 return WINED3DERR_INVALIDCALL;
5481 if ((srcSwapchain || src_surface == device->fb.render_targets[0]) && !dstSwapchain)
5483 /* Blit from render target to texture */
5486 /* P8 read back is not implemented */
5487 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5488 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5490 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5491 return WINED3DERR_INVALIDCALL;
5494 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5496 TRACE("Color keying not supported by frame buffer to texture blit\n");
5497 return WINED3DERR_INVALIDCALL;
5498 /* Destination color key is checked above */
5501 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5506 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5507 * flip the image nor scale it.
5509 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5510 * -> If the app wants a image width an unscaled width, copy it line per line
5511 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5512 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5513 * back buffer. This is slower than reading line per line, thus not used for flipping
5514 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5515 * pixel by pixel. */
5516 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5517 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5519 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5520 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5524 TRACE("Using hardware stretching to flip / stretch the texture.\n");
5525 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5528 if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5530 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5531 dst_surface->resource.allocatedMemory = NULL;
5532 dst_surface->resource.heapMemory = NULL;
5536 dst_surface->flags &= ~SFLAG_INSYSMEM;
5541 else if (src_surface)
5543 /* Blit from offscreen surface to render target */
5544 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5545 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5547 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5549 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5550 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5551 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5553 FIXME("Unsupported blit operation falling back to software\n");
5554 return WINED3DERR_INVALIDCALL;
5557 /* Color keying: Check if we have to do a color keyed blt,
5558 * and if not check if a color key is activated.
5560 * Just modify the color keying parameters in the surface and restore them afterwards
5561 * The surface keeps track of the color key last used to load the opengl surface.
5562 * PreLoad will catch the change to the flags and color key and reload if necessary.
5564 if (flags & WINEDDBLT_KEYSRC)
5566 /* Use color key from surface */
5568 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5570 /* Use color key from DDBltFx */
5571 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5572 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5576 /* Do not use color key */
5577 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5580 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5581 src_surface, src_rect, dst_surface, dst_rect);
5583 /* Restore the color key parameters */
5584 src_surface->CKeyFlags = oldCKeyFlags;
5585 src_surface->src_blt_color_key = old_blt_key;
5587 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5592 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5593 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5594 return WINED3DERR_INVALIDCALL;
5597 /* GL locking is done by the caller */
5598 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5599 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5601 struct wined3d_device *device = surface->resource.device;
5602 const struct wined3d_gl_info *gl_info = context->gl_info;
5603 GLint compare_mode = GL_NONE;
5604 struct blt_info info;
5605 GLint old_binding = 0;
5608 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5610 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
5611 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
5612 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5613 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
5614 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
5615 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
5616 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
5617 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5618 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5619 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
5620 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
5622 SetRect(&rect, 0, h, w, 0);
5623 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5624 context_active_texture(context, context->gl_info, 0);
5625 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
5626 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
5627 if (gl_info->supported[ARB_SHADOW])
5629 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5630 if (compare_mode != GL_NONE)
5631 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5634 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5635 gl_info, info.tex_type, &surface->ds_current_size);
5637 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
5638 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
5639 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
5640 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
5641 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
5642 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
5643 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
5644 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
5645 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
5646 gl_info->gl_ops.gl.p_glEnd();
5648 if (compare_mode != GL_NONE)
5649 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5650 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
5652 gl_info->gl_ops.gl.p_glPopAttrib();
5654 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5657 void surface_modify_ds_location(struct wined3d_surface *surface,
5658 DWORD location, UINT w, UINT h)
5660 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5662 if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5663 FIXME("Invalid location (%#x) specified.\n", location);
5665 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5666 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5668 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5670 TRACE("Passing to container.\n");
5671 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5675 surface->ds_current_size.cx = w;
5676 surface->ds_current_size.cy = h;
5677 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5678 surface->flags |= location;
5681 /* Context activation is done by the caller. */
5682 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5684 const struct wined3d_gl_info *gl_info = context->gl_info;
5685 struct wined3d_device *device = surface->resource.device;
5688 TRACE("surface %p, new location %#x.\n", surface, location);
5690 /* TODO: Make this work for modes other than FBO */
5691 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5693 if (!(surface->flags & location))
5695 w = surface->ds_current_size.cx;
5696 h = surface->ds_current_size.cy;
5697 surface->ds_current_size.cx = 0;
5698 surface->ds_current_size.cy = 0;
5702 w = surface->resource.width;
5703 h = surface->resource.height;
5706 if (surface->ds_current_size.cx == surface->resource.width
5707 && surface->ds_current_size.cy == surface->resource.height)
5709 TRACE("Location (%#x) is already up to date.\n", location);
5713 if (surface->current_renderbuffer)
5715 FIXME("Not supported with fixed up depth stencil.\n");
5719 if (surface->flags & SFLAG_DISCARDED)
5721 TRACE("Surface was discarded, no need copy data.\n");
5724 case SFLAG_INTEXTURE:
5725 surface_prepare_texture(surface, context, FALSE);
5727 case SFLAG_INRB_MULTISAMPLE:
5728 surface_prepare_rb(surface, gl_info, TRUE);
5730 case SFLAG_INDRAWABLE:
5734 FIXME("Unhandled location %#x\n", location);
5736 surface->flags &= ~SFLAG_DISCARDED;
5737 surface->flags |= location;
5738 surface->ds_current_size.cx = surface->resource.width;
5739 surface->ds_current_size.cy = surface->resource.height;
5743 if (!(surface->flags & SFLAG_LOCATIONS))
5745 FIXME("No up to date depth stencil location.\n");
5746 surface->flags |= location;
5747 surface->ds_current_size.cx = surface->resource.width;
5748 surface->ds_current_size.cy = surface->resource.height;
5752 if (location == SFLAG_INTEXTURE)
5754 GLint old_binding = 0;
5757 /* The render target is allowed to be smaller than the depth/stencil
5758 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5759 * than the offscreen surface. Don't overwrite the offscreen surface
5760 * with undefined data. */
5761 w = min(w, context->swapchain->desc.backbuffer_width);
5762 h = min(h, context->swapchain->desc.backbuffer_height);
5764 TRACE("Copying onscreen depth buffer to depth texture.\n");
5768 if (!device->depth_blt_texture)
5769 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
5771 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5772 * directly on the FBO texture. That's because we need to flip. */
5773 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5774 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5775 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
5777 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5778 bind_target = GL_TEXTURE_RECTANGLE_ARB;
5782 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5783 bind_target = GL_TEXTURE_2D;
5785 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
5786 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5787 * internal format, because the internal format might include stencil
5788 * data. In principle we should copy stencil data as well, but unless
5789 * the driver supports stencil export it's hard to do, and doesn't
5790 * seem to be needed in practice. If the hardware doesn't support
5791 * writing stencil data, the glCopyTexImage2D() call might trigger
5792 * software fallbacks. */
5793 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
5794 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5795 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5796 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5797 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5798 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
5799 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5800 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
5802 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5803 NULL, surface, SFLAG_INTEXTURE);
5804 context_set_draw_buffer(context, GL_NONE);
5805 gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
5807 /* Do the actual blit */
5808 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
5809 checkGLcall("depth_blt");
5811 context_invalidate_state(context, STATE_FRAMEBUFFER);
5815 if (wined3d_settings.strict_draw_ordering)
5816 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5818 else if (location == SFLAG_INDRAWABLE)
5820 TRACE("Copying depth texture to onscreen depth buffer.\n");
5824 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5825 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5826 surface_depth_blt(surface, context, surface->texture_name,
5827 0, surface->pow2Height - h, w, h, surface->texture_target);
5828 checkGLcall("depth_blt");
5830 context_invalidate_state(context, STATE_FRAMEBUFFER);
5834 if (wined3d_settings.strict_draw_ordering)
5835 gl_info->gl_ops.gl.p_glFlush(); /* 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(struct wined3d_surface *surface, DWORD location, BOOL persistent)
5849 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
5850 struct wined3d_surface *overlay;
5852 TRACE("surface %p, location %s, persistent %#x.\n",
5853 surface, debug_surflocation(location), persistent);
5855 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
5856 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
5857 && (location & SFLAG_INDRAWABLE))
5858 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5860 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
5861 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
5862 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
5866 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5867 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
5869 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5871 TRACE("Passing to container.\n");
5872 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5875 surface->flags &= ~SFLAG_LOCATIONS;
5876 surface->flags |= location;
5878 /* Redraw emulated overlays, if any */
5879 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
5881 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
5883 surface_draw_overlay(overlay);
5889 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
5891 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5893 TRACE("Passing to container\n");
5894 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5897 surface->flags &= ~location;
5900 if (!(surface->flags & SFLAG_LOCATIONS))
5902 ERR("Surface %p does not have any up to date location.\n", surface);
5906 static DWORD resource_access_from_location(DWORD location)
5910 case SFLAG_INSYSMEM:
5911 return WINED3D_RESOURCE_ACCESS_CPU;
5913 case SFLAG_INDRAWABLE:
5914 case SFLAG_INSRGBTEX:
5915 case SFLAG_INTEXTURE:
5916 case SFLAG_INRB_MULTISAMPLE:
5917 case SFLAG_INRB_RESOLVED:
5918 return WINED3D_RESOURCE_ACCESS_GPU;
5921 FIXME("Unhandled location %#x.\n", location);
5926 static void surface_load_sysmem(struct wined3d_surface *surface,
5927 const struct wined3d_gl_info *gl_info, const RECT *rect)
5929 surface_prepare_system_memory(surface);
5931 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
5932 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5934 /* Download the surface to system memory. */
5935 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
5937 struct wined3d_device *device = surface->resource.device;
5938 struct wined3d_context *context;
5940 /* TODO: Use already acquired context when possible. */
5941 context = context_acquire(device, NULL);
5943 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
5944 surface_download_data(surface, gl_info);
5946 context_release(context);
5951 if (surface->flags & SFLAG_INDRAWABLE)
5953 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
5954 wined3d_surface_get_pitch(surface));
5958 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
5959 surface, surface->flags & SFLAG_LOCATIONS);
5962 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
5963 const struct wined3d_gl_info *gl_info, const RECT *rect)
5965 struct wined3d_device *device = surface->resource.device;
5966 enum wined3d_conversion_type convert;
5967 struct wined3d_format format;
5971 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
5973 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5974 return WINED3DERR_INVALIDCALL;
5977 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
5978 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5980 if (surface->flags & SFLAG_INTEXTURE)
5984 surface_get_rect(surface, rect, &r);
5985 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
5990 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
5992 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5993 * path through sysmem. */
5994 surface_load_location(surface, SFLAG_INSYSMEM, rect);
5997 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
5999 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6000 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
6002 if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
6004 struct wined3d_context *context;
6006 TRACE("Removing the pbo attached to surface %p.\n", surface);
6008 /* TODO: Use already acquired context when possible. */
6009 context = context_acquire(device, NULL);
6011 surface_remove_pbo(surface, gl_info);
6013 context_release(context);
6016 if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
6018 UINT height = surface->resource.height;
6019 UINT width = surface->resource.width;
6020 UINT src_pitch, dst_pitch;
6022 byte_count = format.conv_byte_count;
6023 src_pitch = wined3d_surface_get_pitch(surface);
6025 /* Stick to the alignment for the converted surface too, makes it
6026 * easier to load the surface. */
6027 dst_pitch = width * byte_count;
6028 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6030 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6032 ERR("Out of memory (%u).\n", dst_pitch * height);
6033 return E_OUTOFMEMORY;
6036 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6037 src_pitch, width, height, dst_pitch, convert, surface);
6039 surface->flags |= SFLAG_CONVERTED;
6043 surface->flags &= ~SFLAG_CONVERTED;
6044 mem = surface->resource.allocatedMemory;
6045 byte_count = format.byte_count;
6048 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6050 /* Don't delete PBO memory. */
6051 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6052 HeapFree(GetProcessHeap(), 0, mem);
6057 static HRESULT surface_load_texture(struct wined3d_surface *surface,
6058 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6060 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6061 struct wined3d_device *device = surface->resource.device;
6062 enum wined3d_conversion_type convert;
6063 struct wined3d_context *context;
6064 UINT width, src_pitch, dst_pitch;
6065 struct wined3d_bo_address data;
6066 struct wined3d_format format;
6067 POINT dst_point = {0, 0};
6070 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6071 && surface_is_offscreen(surface)
6072 && (surface->flags & SFLAG_INDRAWABLE))
6074 surface_load_fb_texture(surface, srgb);
6079 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6080 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6081 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6082 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6083 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6086 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6087 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6089 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6090 &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6095 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6096 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6097 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6098 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6099 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6101 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6102 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6103 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6105 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6106 &rect, surface, dst_location, &rect);
6111 /* Upload from system memory */
6113 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6114 TRUE /* We will use textures */, &format, &convert);
6118 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6120 /* Performance warning... */
6121 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6122 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6127 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6129 /* Performance warning... */
6130 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6131 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6135 if (!(surface->flags & SFLAG_INSYSMEM))
6137 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6138 /* Lets hope we get it from somewhere... */
6139 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6142 /* TODO: Use already acquired context when possible. */
6143 context = context_acquire(device, NULL);
6145 surface_prepare_texture(surface, context, srgb);
6146 surface_bind_and_dirtify(surface, context, srgb);
6148 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6150 surface->flags |= SFLAG_GLCKEY;
6151 surface->gl_color_key = surface->src_blt_color_key;
6153 else surface->flags &= ~SFLAG_GLCKEY;
6155 width = surface->resource.width;
6156 src_pitch = wined3d_surface_get_pitch(surface);
6158 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6159 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6161 if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6163 TRACE("Removing the pbo attached to surface %p.\n", surface);
6164 surface_remove_pbo(surface, gl_info);
6169 /* This code is entered for texture formats which need a fixup. */
6170 UINT height = surface->resource.height;
6172 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6173 dst_pitch = width * format.conv_byte_count;
6174 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6176 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6178 ERR("Out of memory (%u).\n", dst_pitch * height);
6179 context_release(context);
6180 return E_OUTOFMEMORY;
6182 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6183 format.byte_count = format.conv_byte_count;
6184 src_pitch = dst_pitch;
6186 else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6188 /* This code is only entered for color keying fixups */
6189 UINT height = surface->resource.height;
6191 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6192 dst_pitch = width * format.conv_byte_count;
6193 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6195 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6197 ERR("Out of memory (%u).\n", dst_pitch * height);
6198 context_release(context);
6199 return E_OUTOFMEMORY;
6201 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6202 width, height, dst_pitch, convert, surface);
6203 format.byte_count = format.conv_byte_count;
6204 src_pitch = dst_pitch;
6208 mem = surface->resource.allocatedMemory;
6211 data.buffer_object = surface->pbo;
6213 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6215 context_release(context);
6217 /* Don't delete PBO memory. */
6218 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6219 HeapFree(GetProcessHeap(), 0, mem);
6224 static void surface_multisample_resolve(struct wined3d_surface *surface)
6226 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6228 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6229 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6231 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6232 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6235 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6237 struct wined3d_device *device = surface->resource.device;
6238 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6241 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6243 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6245 if (location == SFLAG_INTEXTURE)
6247 struct wined3d_context *context = context_acquire(device, NULL);
6248 surface_load_ds_location(surface, context, location);
6249 context_release(context);
6254 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location));
6255 return WINED3DERR_INVALIDCALL;
6259 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6260 location = SFLAG_INTEXTURE;
6262 if (surface->flags & location)
6264 TRACE("Location already up to date.\n");
6266 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6267 && surface_need_pbo(surface, gl_info))
6268 surface_load_pbo(surface, gl_info);
6273 if (WARN_ON(d3d_surface))
6275 DWORD required_access = resource_access_from_location(location);
6276 if ((surface->resource.access_flags & required_access) != required_access)
6277 WARN("Operation requires %#x access, but surface only has %#x.\n",
6278 required_access, surface->resource.access_flags);
6281 if (!(surface->flags & SFLAG_LOCATIONS))
6283 ERR("Surface %p does not have any up to date location.\n", surface);
6284 surface->flags |= SFLAG_LOST;
6285 return WINED3DERR_DEVICELOST;
6290 case SFLAG_INSYSMEM:
6291 surface_load_sysmem(surface, gl_info, rect);
6294 case SFLAG_INDRAWABLE:
6295 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6299 case SFLAG_INRB_RESOLVED:
6300 surface_multisample_resolve(surface);
6303 case SFLAG_INTEXTURE:
6304 case SFLAG_INSRGBTEX:
6305 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6310 ERR("Don't know how to handle location %#x.\n", location);
6316 surface->flags |= location;
6318 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6319 surface_evict_sysmem(surface);
6322 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6323 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6325 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6331 BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6333 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6335 /* Not on a swapchain - must be offscreen */
6336 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6338 /* The front buffer is always onscreen */
6339 if (surface == swapchain->front_buffer) return FALSE;
6341 /* If the swapchain is rendered to an FBO, the backbuffer is
6342 * offscreen, otherwise onscreen */
6343 return swapchain->render_to_fbo;
6346 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6347 /* Context activation is done by the caller. */
6348 static void ffp_blit_free(struct wined3d_device *device) { }
6350 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6351 /* Context activation is done by the caller. */
6352 static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6355 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) != 0;
6358 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6359 target = surface->container.u.texture->target;
6361 target = surface->texture_target;
6363 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6365 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6367 GL_EXTCALL(glColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6371 /* Context activation is done by the caller. */
6372 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6374 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6375 const struct wined3d_gl_info *gl_info = context->gl_info;
6378 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6379 target = surface->container.u.texture->target;
6381 target = surface->texture_target;
6383 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6384 * else the surface is converted in software at upload time in LoadLocation.
6386 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6387 && gl_info->supported[EXT_PALETTED_TEXTURE])
6388 ffp_blit_p8_upload_palette(surface, gl_info);
6391 gl_info->gl_ops.gl.p_glEnable(target);
6392 checkGLcall("glEnable(target)");
6397 /* Context activation is done by the caller. */
6398 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6401 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
6402 checkGLcall("glDisable(GL_TEXTURE_2D)");
6403 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6405 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6406 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6408 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6410 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
6411 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6416 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6417 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6418 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6420 enum complex_fixup src_fixup;
6424 case WINED3D_BLIT_OP_COLOR_BLIT:
6425 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6428 src_fixup = get_complex_fixup(src_format->color_fixup);
6429 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6431 TRACE("Checking support for fixup:\n");
6432 dump_color_fixup_desc(src_format->color_fixup);
6435 if (!is_identity_fixup(dst_format->color_fixup))
6437 TRACE("Destination fixups are not supported\n");
6441 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6443 TRACE("P8 fixup supported\n");
6447 /* We only support identity conversions. */
6448 if (is_identity_fixup(src_format->color_fixup))
6454 TRACE("[FAILED]\n");
6457 case WINED3D_BLIT_OP_COLOR_FILL:
6458 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6461 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6463 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6466 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6468 TRACE("Color fill not supported\n");
6472 /* FIXME: We should reject color fills on formats with fixups,
6473 * but this would break P8 color fills for example. */
6477 case WINED3D_BLIT_OP_DEPTH_FILL:
6481 TRACE("Unsupported blit_op=%d\n", blit_op);
6486 /* Do not call while under the GL lock. */
6487 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6488 const RECT *dst_rect, const struct wined3d_color *color)
6490 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6491 struct wined3d_fb_state fb = {&dst_surface, NULL};
6493 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6498 /* Do not call while under the GL lock. */
6499 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6500 struct wined3d_surface *surface, const RECT *rect, float depth)
6502 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6503 struct wined3d_fb_state fb = {NULL, surface};
6505 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6510 const struct blit_shader ffp_blit = {
6516 ffp_blit_color_fill,
6517 ffp_blit_depth_fill,
6520 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6525 /* Context activation is done by the caller. */
6526 static void cpu_blit_free(struct wined3d_device *device)
6530 /* Context activation is done by the caller. */
6531 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6536 /* Context activation is done by the caller. */
6537 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6541 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6542 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6543 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6545 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6553 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6554 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6555 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6557 UINT row_block_count;
6558 const BYTE *src_row;
6565 row_block_count = (update_w + format->block_width - 1) / format->block_width;
6569 for (y = 0; y < update_h; y += format->block_height)
6571 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6572 src_row += src_pitch;
6573 dst_row += dst_pitch;
6579 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6581 src_row += (((update_h / format->block_height) - 1) * src_pitch);
6585 case WINED3DFMT_DXT1:
6586 for (y = 0; y < update_h; y += format->block_height)
6591 BYTE control_row[4];
6594 const struct block *s = (const struct block *)src_row;
6595 struct block *d = (struct block *)dst_row;
6597 for (x = 0; x < row_block_count; ++x)
6599 d[x].color[0] = s[x].color[0];
6600 d[x].color[1] = s[x].color[1];
6601 d[x].control_row[0] = s[x].control_row[3];
6602 d[x].control_row[1] = s[x].control_row[2];
6603 d[x].control_row[2] = s[x].control_row[1];
6604 d[x].control_row[3] = s[x].control_row[0];
6606 src_row -= src_pitch;
6607 dst_row += dst_pitch;
6611 case WINED3DFMT_DXT3:
6612 for (y = 0; y < update_h; y += format->block_height)
6618 BYTE control_row[4];
6621 const struct block *s = (const struct block *)src_row;
6622 struct block *d = (struct block *)dst_row;
6624 for (x = 0; x < row_block_count; ++x)
6626 d[x].alpha_row[0] = s[x].alpha_row[3];
6627 d[x].alpha_row[1] = s[x].alpha_row[2];
6628 d[x].alpha_row[2] = s[x].alpha_row[1];
6629 d[x].alpha_row[3] = s[x].alpha_row[0];
6630 d[x].color[0] = s[x].color[0];
6631 d[x].color[1] = s[x].color[1];
6632 d[x].control_row[0] = s[x].control_row[3];
6633 d[x].control_row[1] = s[x].control_row[2];
6634 d[x].control_row[2] = s[x].control_row[1];
6635 d[x].control_row[3] = s[x].control_row[0];
6637 src_row -= src_pitch;
6638 dst_row += dst_pitch;
6643 FIXME("Compressed flip not implemented for format %s.\n",
6644 debug_d3dformat(format->id));
6649 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
6650 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
6655 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
6656 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
6657 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
6659 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
6660 const struct wined3d_format *src_format, *dst_format;
6661 struct wined3d_surface *orig_src = src_surface;
6662 struct wined3d_map_desc dst_map, src_map;
6663 const BYTE *sbase = NULL;
6664 HRESULT hr = WINED3D_OK;
6669 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6670 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
6671 flags, fx, debug_d3dtexturefiltertype(filter));
6673 if (src_surface == dst_surface)
6675 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
6677 src_format = dst_surface->resource.format;
6678 dst_format = src_format;
6682 dst_format = dst_surface->resource.format;
6685 if (dst_surface->resource.format->id != src_surface->resource.format->id)
6687 src_surface = surface_convert_format(src_surface, dst_format->id);
6690 /* The conv function writes a FIXME */
6691 WARN("Cannot convert source surface format to dest format.\n");
6695 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
6696 src_format = src_surface->resource.format;
6700 src_format = dst_format;
6703 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
6706 bpp = dst_surface->resource.format->byte_count;
6707 srcheight = src_rect->bottom - src_rect->top;
6708 srcwidth = src_rect->right - src_rect->left;
6709 dstheight = dst_rect->bottom - dst_rect->top;
6710 dstwidth = dst_rect->right - dst_rect->left;
6711 width = (dst_rect->right - dst_rect->left) * bpp;
6714 sbase = (BYTE *)src_map.data
6715 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
6716 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
6717 if (src_surface != dst_surface)
6718 dbuf = dst_map.data;
6720 dbuf = (BYTE *)dst_map.data
6721 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
6722 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
6724 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
6726 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
6728 if (src_surface == dst_surface)
6730 FIXME("Only plain blits supported on compressed surfaces.\n");
6735 if (srcheight != dstheight || srcwidth != dstwidth)
6737 WARN("Stretching not supported on compressed surfaces.\n");
6738 hr = WINED3DERR_INVALIDCALL;
6742 if (!surface_check_block_align(src_surface, src_rect))
6744 WARN("Source rectangle not block-aligned.\n");
6745 hr = WINED3DERR_INVALIDCALL;
6749 if (!surface_check_block_align(dst_surface, dst_rect))
6751 WARN("Destination rectangle not block-aligned.\n");
6752 hr = WINED3DERR_INVALIDCALL;
6756 hr = surface_cpu_blt_compressed(sbase, dbuf,
6757 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
6758 src_format, flags, fx);
6762 /* First, all the 'source-less' blits */
6763 if (flags & WINEDDBLT_COLORFILL)
6765 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
6766 flags &= ~WINEDDBLT_COLORFILL;
6769 if (flags & WINEDDBLT_DEPTHFILL)
6771 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6773 if (flags & WINEDDBLT_ROP)
6775 /* Catch some degenerate cases here. */
6779 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
6781 case 0xaa0029: /* No-op */
6784 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
6786 case SRCCOPY: /* Well, we do that below? */
6789 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
6792 flags &= ~WINEDDBLT_ROP;
6794 if (flags & WINEDDBLT_DDROPS)
6796 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
6798 /* Now the 'with source' blits. */
6801 int sx, xinc, sy, yinc;
6803 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
6806 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
6807 && (srcwidth != dstwidth || srcheight != dstheight))
6809 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6810 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
6813 xinc = (srcwidth << 16) / dstwidth;
6814 yinc = (srcheight << 16) / dstheight;
6818 /* No effects, we can cheat here. */
6819 if (dstwidth == srcwidth)
6821 if (dstheight == srcheight)
6823 /* No stretching in either direction. This needs to be as
6824 * fast as possible. */
6827 /* Check for overlapping surfaces. */
6828 if (src_surface != dst_surface || dst_rect->top < src_rect->top
6829 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
6831 /* No overlap, or dst above src, so copy from top downwards. */
6832 for (y = 0; y < dstheight; ++y)
6834 memcpy(dbuf, sbuf, width);
6835 sbuf += src_map.row_pitch;
6836 dbuf += dst_map.row_pitch;
6839 else if (dst_rect->top > src_rect->top)
6841 /* Copy from bottom upwards. */
6842 sbuf += src_map.row_pitch * dstheight;
6843 dbuf += dst_map.row_pitch * dstheight;
6844 for (y = 0; y < dstheight; ++y)
6846 sbuf -= src_map.row_pitch;
6847 dbuf -= dst_map.row_pitch;
6848 memcpy(dbuf, sbuf, width);
6853 /* Src and dst overlapping on the same line, use memmove. */
6854 for (y = 0; y < dstheight; ++y)
6856 memmove(dbuf, sbuf, width);
6857 sbuf += src_map.row_pitch;
6858 dbuf += dst_map.row_pitch;
6864 /* Stretching in y direction only. */
6865 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6867 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6868 memcpy(dbuf, sbuf, width);
6869 dbuf += dst_map.row_pitch;
6875 /* Stretching in X direction. */
6877 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6879 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6881 if ((sy >> 16) == (last_sy >> 16))
6883 /* This source row is the same as last source row -
6884 * Copy the already stretched row. */
6885 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
6889 #define STRETCH_ROW(type) \
6891 const type *s = (const type *)sbuf; \
6892 type *d = (type *)dbuf; \
6893 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6894 d[x] = s[sx >> 16]; \
6912 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
6916 s = sbuf + 3 * (sx >> 16);
6917 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
6918 d[0] = (pixel ) & 0xff;
6919 d[1] = (pixel >> 8) & 0xff;
6920 d[2] = (pixel >> 16) & 0xff;
6926 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
6927 hr = WINED3DERR_NOTAVAILABLE;
6932 dbuf += dst_map.row_pitch;
6939 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
6940 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
6941 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
6942 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
6944 /* The color keying flags are checked for correctness in ddraw */
6945 if (flags & WINEDDBLT_KEYSRC)
6947 keylow = src_surface->src_blt_color_key.color_space_low_value;
6948 keyhigh = src_surface->src_blt_color_key.color_space_high_value;
6950 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6952 keylow = fx->ddckSrcColorkey.color_space_low_value;
6953 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
6956 if (flags & WINEDDBLT_KEYDEST)
6958 /* Destination color keys are taken from the source surface! */
6959 destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
6960 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
6962 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
6964 destkeylow = fx->ddckDestColorkey.color_space_low_value;
6965 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
6974 keymask = src_format->red_mask
6975 | src_format->green_mask
6976 | src_format->blue_mask;
6978 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
6981 if (flags & WINEDDBLT_DDFX)
6983 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
6986 dTopRight = dbuf + ((dstwidth - 1) * bpp);
6987 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
6988 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
6990 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
6992 /* I don't think we need to do anything about this flag */
6993 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6995 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
6998 dTopRight = dTopLeft;
7001 dBottomRight = dBottomLeft;
7003 dstxinc = dstxinc * -1;
7005 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
7008 dTopLeft = dBottomLeft;
7011 dTopRight = dBottomRight;
7013 dstyinc = dstyinc * -1;
7015 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
7017 /* I don't think we need to do anything about this flag */
7018 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
7020 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
7023 dBottomRight = dTopLeft;
7026 dBottomLeft = dTopRight;
7028 dstxinc = dstxinc * -1;
7029 dstyinc = dstyinc * -1;
7031 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
7034 dTopLeft = dBottomLeft;
7035 dBottomLeft = dBottomRight;
7036 dBottomRight = dTopRight;
7041 dstxinc = dstxinc * -1;
7043 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7046 dTopLeft = dTopRight;
7047 dTopRight = dBottomRight;
7048 dBottomRight = dBottomLeft;
7053 dstyinc = dstyinc * -1;
7055 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7057 /* I don't think we need to do anything about this flag */
7058 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7061 flags &= ~(WINEDDBLT_DDFX);
7064 #define COPY_COLORKEY_FX(type) \
7067 type *d = (type *)dbuf, *dx, tmp; \
7068 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7070 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7072 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7074 tmp = s[sx >> 16]; \
7075 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7076 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7080 dx = (type *)(((BYTE *)dx) + dstxinc); \
7082 d = (type *)(((BYTE *)d) + dstyinc); \
7089 COPY_COLORKEY_FX(BYTE);
7092 COPY_COLORKEY_FX(WORD);
7095 COPY_COLORKEY_FX(DWORD);
7100 BYTE *d = dbuf, *dx;
7101 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7103 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7105 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7107 DWORD pixel, dpixel = 0;
7108 s = sbuf + 3 * (sx>>16);
7109 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7110 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7111 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7112 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7114 dx[0] = (pixel ) & 0xff;
7115 dx[1] = (pixel >> 8) & 0xff;
7116 dx[2] = (pixel >> 16) & 0xff;
7125 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7126 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7127 hr = WINED3DERR_NOTAVAILABLE;
7129 #undef COPY_COLORKEY_FX
7135 if (flags && FIXME_ON(d3d_surface))
7137 FIXME("\tUnsupported flags: %#x.\n", flags);
7141 wined3d_surface_unmap(dst_surface);
7142 if (src_surface && src_surface != dst_surface)
7143 wined3d_surface_unmap(src_surface);
7144 /* Release the converted surface, if any. */
7145 if (src_surface && src_surface != orig_src)
7146 wined3d_surface_decref(src_surface);
7151 /* Do not call while under the GL lock. */
7152 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7153 const RECT *dst_rect, const struct wined3d_color *color)
7155 static const RECT src_rect;
7158 memset(&BltFx, 0, sizeof(BltFx));
7159 BltFx.dwSize = sizeof(BltFx);
7160 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7161 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7162 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7165 /* Do not call while under the GL lock. */
7166 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7167 struct wined3d_surface *surface, const RECT *rect, float depth)
7169 FIXME("Depth filling not implemented by cpu_blit.\n");
7170 return WINED3DERR_INVALIDCALL;
7173 const struct blit_shader cpu_blit = {
7179 cpu_blit_color_fill,
7180 cpu_blit_depth_fill,
7183 static HRESULT surface_init(struct wined3d_surface *surface, enum wined3d_surface_type surface_type, UINT alignment,
7184 UINT width, UINT height, UINT level, enum wined3d_multisample_type multisample_type,
7185 UINT multisample_quality, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7186 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops)
7188 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7189 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7190 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7191 unsigned int resource_size;
7194 if (multisample_quality > 0)
7196 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7197 multisample_quality = 0;
7200 /* Quick lockable sanity check.
7201 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7202 * this function is too deep to need to care about things like this.
7203 * Levels need to be checked too, since they all affect what can be done. */
7206 case WINED3D_POOL_SCRATCH:
7209 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7210 "which are mutually exclusive, setting lockable to TRUE.\n");
7215 case WINED3D_POOL_SYSTEM_MEM:
7217 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7220 case WINED3D_POOL_MANAGED:
7221 if (usage & WINED3DUSAGE_DYNAMIC)
7222 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7225 case WINED3D_POOL_DEFAULT:
7226 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7227 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7231 FIXME("Unknown pool %#x.\n", pool);
7235 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7236 FIXME("Trying to create a render target that isn't in the default pool.\n");
7238 /* FIXME: Check that the format is supported by the device. */
7240 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7242 return WINED3DERR_INVALIDCALL;
7244 surface->surface_type = surface_type;
7246 switch (surface_type)
7248 case WINED3D_SURFACE_TYPE_OPENGL:
7249 surface->surface_ops = &surface_ops;
7252 case WINED3D_SURFACE_TYPE_GDI:
7253 surface->surface_ops = &gdi_surface_ops;
7257 ERR("Requested unknown surface implementation %#x.\n", surface_type);
7258 return WINED3DERR_INVALIDCALL;
7261 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7262 multisample_type, multisample_quality, usage, pool, width, height, 1,
7263 resource_size, parent, parent_ops, &surface_resource_ops);
7266 WARN("Failed to initialize resource, returning %#x.\n", hr);
7270 /* "Standalone" surface. */
7271 surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7273 surface->texture_level = level;
7274 list_init(&surface->overlays);
7277 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7278 if (flags & WINED3D_SURFACE_DISCARD)
7279 surface->flags |= SFLAG_DISCARD;
7280 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7281 surface->flags |= SFLAG_PIN_SYSMEM;
7282 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7283 surface->flags |= SFLAG_LOCKABLE;
7284 /* I'm not sure if this qualifies as a hack or as an optimization. It
7285 * seems reasonable to assume that lockable render targets will get
7286 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7287 * creation. However, the other reason we want to do this is that several
7288 * ddraw applications access surface memory while the surface isn't
7289 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7290 * future locks prevents these from crashing. */
7291 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7292 surface->flags |= SFLAG_DYNLOCK;
7294 /* Mark the texture as dirty so that it gets loaded first time around. */
7295 surface_add_dirty_rect(surface, NULL);
7296 list_init(&surface->renderbuffers);
7298 TRACE("surface %p, memory %p, size %u\n",
7299 surface, surface->resource.allocatedMemory, surface->resource.size);
7301 /* Call the private setup routine */
7302 hr = surface->surface_ops->surface_private_setup(surface);
7305 ERR("Private setup failed, returning %#x\n", hr);
7306 surface_cleanup(surface);
7310 /* Similar to lockable rendertargets above, creating the DIB section
7311 * during surface initialization prevents the sysmem pointer from changing
7312 * after a wined3d_surface_getdc() call. */
7313 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7314 && SUCCEEDED(surface_create_dib_section(surface)))
7316 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7317 surface->resource.heapMemory = NULL;
7318 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7324 HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
7325 enum wined3d_format_id format_id, UINT level, DWORD usage, enum wined3d_pool pool,
7326 enum wined3d_multisample_type multisample_type, DWORD multisample_quality,
7327 enum wined3d_surface_type surface_type, DWORD flags, void *parent,
7328 const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface)
7330 struct wined3d_surface *object;
7333 TRACE("device %p, width %u, height %u, format %s, level %u\n",
7334 device, width, height, debug_d3dformat(format_id), level);
7335 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7336 surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
7337 TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type, flags, parent, parent_ops);
7339 if (surface_type == WINED3D_SURFACE_TYPE_OPENGL && !device->adapter)
7341 ERR("OpenGL surfaces are not available without OpenGL.\n");
7342 return WINED3DERR_NOTAVAILABLE;
7345 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
7348 ERR("Failed to allocate surface memory.\n");
7349 return WINED3DERR_OUTOFVIDEOMEMORY;
7352 hr = surface_init(object, surface_type, device->surface_alignment, width, height, level,
7353 multisample_type, multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops);
7356 WARN("Failed to initialize surface, returning %#x.\n", hr);
7357 HeapFree(GetProcessHeap(), 0, object);
7361 TRACE("Created surface %p.\n", object);