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 /* Works correctly only for <= 4 bpp formats. */
375 static void get_color_masks(const struct wined3d_format *format, DWORD *masks)
377 masks[0] = ((1 << format->red_size) - 1) << format->red_offset;
378 masks[1] = ((1 << format->green_size) - 1) << format->green_offset;
379 masks[2] = ((1 << format->blue_size) - 1) << format->blue_offset;
382 static HRESULT surface_create_dib_section(struct wined3d_surface *surface)
384 const struct wined3d_format *format = surface->resource.format;
390 TRACE("surface %p.\n", surface);
392 if (!(format->flags & WINED3DFMT_FLAG_GETDC))
394 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
395 return WINED3DERR_INVALIDCALL;
398 switch (format->byte_count)
402 /* Allocate extra space to store the RGB bit masks. */
403 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
407 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
411 /* Allocate extra space for a palette. */
412 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
413 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
418 return E_OUTOFMEMORY;
420 /* Some applications access the surface in via DWORDs, and do not take
421 * the necessary care at the end of the surface. So we need at least
422 * 4 extra bytes at the end of the surface. Check against the page size,
423 * if the last page used for the surface has at least 4 spare bytes we're
424 * safe, otherwise add an extra line to the DIB section. */
425 GetSystemInfo(&sysInfo);
426 if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
429 TRACE("Adding an extra line to the DIB section.\n");
432 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
433 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
434 b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count;
435 b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
436 b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
437 * wined3d_surface_get_pitch(surface);
438 b_info->bmiHeader.biPlanes = 1;
439 b_info->bmiHeader.biBitCount = format->byte_count * 8;
441 b_info->bmiHeader.biXPelsPerMeter = 0;
442 b_info->bmiHeader.biYPelsPerMeter = 0;
443 b_info->bmiHeader.biClrUsed = 0;
444 b_info->bmiHeader.biClrImportant = 0;
446 /* Get the bit masks */
447 masks = (DWORD *)b_info->bmiColors;
448 switch (surface->resource.format->id)
450 case WINED3DFMT_B8G8R8_UNORM:
451 b_info->bmiHeader.biCompression = BI_RGB;
454 case WINED3DFMT_B5G5R5X1_UNORM:
455 case WINED3DFMT_B5G5R5A1_UNORM:
456 case WINED3DFMT_B4G4R4A4_UNORM:
457 case WINED3DFMT_B4G4R4X4_UNORM:
458 case WINED3DFMT_B2G3R3_UNORM:
459 case WINED3DFMT_B2G3R3A8_UNORM:
460 case WINED3DFMT_R10G10B10A2_UNORM:
461 case WINED3DFMT_R8G8B8A8_UNORM:
462 case WINED3DFMT_R8G8B8X8_UNORM:
463 case WINED3DFMT_B10G10R10A2_UNORM:
464 case WINED3DFMT_B5G6R5_UNORM:
465 case WINED3DFMT_R16G16B16A16_UNORM:
466 b_info->bmiHeader.biCompression = BI_BITFIELDS;
467 get_color_masks(format, masks);
471 /* Don't know palette */
472 b_info->bmiHeader.biCompression = BI_RGB;
476 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
477 b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
478 b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
479 surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
481 if (!surface->dib.DIBsection)
483 ERR("Failed to create DIB section.\n");
484 HeapFree(GetProcessHeap(), 0, b_info);
485 return HRESULT_FROM_WIN32(GetLastError());
488 TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
489 /* Copy the existing surface to the dib section. */
490 if (surface->resource.allocatedMemory)
492 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
493 surface->resource.height * wined3d_surface_get_pitch(surface));
497 /* This is to make maps read the GL texture although memory is allocated. */
498 surface->flags &= ~SFLAG_INSYSMEM;
500 surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
502 HeapFree(GetProcessHeap(), 0, b_info);
504 /* Now allocate a DC. */
505 surface->hDC = CreateCompatibleDC(0);
506 SelectObject(surface->hDC, surface->dib.DIBsection);
507 TRACE("Using wined3d palette %p.\n", surface->palette);
508 SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
510 surface->flags |= SFLAG_DIBSECTION;
515 static BOOL surface_need_pbo(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
517 if (surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
519 if (!(surface->flags & SFLAG_DYNLOCK))
521 if (surface->flags & (SFLAG_CONVERTED | SFLAG_NONPOW2 | SFLAG_PIN_SYSMEM))
523 if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT])
529 static void surface_load_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
531 struct wined3d_context *context;
534 context = context_acquire(surface->resource.device, NULL);
537 GL_EXTCALL(glGenBuffersARB(1, &surface->pbo));
538 error = gl_info->gl_ops.gl.p_glGetError();
539 if (!surface->pbo || error != GL_NO_ERROR)
540 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
542 TRACE("Binding PBO %u.\n", surface->pbo);
544 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
545 checkGLcall("glBindBufferARB");
547 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->resource.size + 4,
548 surface->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
549 checkGLcall("glBufferDataARB");
551 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
552 checkGLcall("glBindBufferARB");
554 /* We don't need the system memory anymore and we can't even use it for PBOs. */
555 if (!(surface->flags & SFLAG_CLIENT))
557 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
558 surface->resource.heapMemory = NULL;
560 surface->resource.allocatedMemory = NULL;
561 surface->flags |= SFLAG_PBO;
563 context_release(context);
566 static void surface_prepare_system_memory(struct wined3d_surface *surface)
568 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
570 TRACE("surface %p.\n", surface);
572 if (!(surface->flags & SFLAG_PBO) && surface_need_pbo(surface, gl_info))
573 surface_load_pbo(surface, gl_info);
574 else if (!(surface->resource.allocatedMemory || surface->flags & SFLAG_PBO))
576 /* Whatever surface we have, make sure that there is memory allocated
577 * for the downloaded copy, or a PBO to map. */
578 if (!surface->resource.heapMemory)
579 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
581 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
582 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
584 if (surface->flags & SFLAG_INSYSMEM)
585 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
589 static void surface_evict_sysmem(struct wined3d_surface *surface)
591 if (surface->resource.map_count || (surface->flags & SFLAG_DONOTFREE))
594 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
595 surface->resource.allocatedMemory = NULL;
596 surface->resource.heapMemory = NULL;
597 surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
600 /* Context activation is done by the caller. */
601 static void surface_bind(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
603 TRACE("surface %p, context %p, srgb %#x.\n", surface, context, srgb);
605 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
607 struct wined3d_texture *texture = surface->container.u.texture;
609 TRACE("Passing to container (%p).\n", texture);
610 texture->texture_ops->texture_bind(texture, context, srgb);
614 const struct wined3d_gl_info *gl_info = context->gl_info;
616 if (surface->texture_level)
618 ERR("Standalone surface %p is non-zero texture level %u.\n",
619 surface, surface->texture_level);
623 ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
627 if (!surface->texture_name)
629 gl_info->gl_ops.gl.p_glGenTextures(1, &surface->texture_name);
630 checkGLcall("glGenTextures");
632 TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
634 context_bind_texture(context, surface->texture_target, surface->texture_name);
635 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
636 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
637 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
638 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
639 gl_info->gl_ops.gl.p_glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
640 checkGLcall("glTexParameteri");
644 context_bind_texture(context, surface->texture_target, surface->texture_name);
651 /* Context activation is done by the caller. */
652 static void surface_bind_and_dirtify(struct wined3d_surface *surface,
653 struct wined3d_context *context, BOOL srgb)
655 struct wined3d_device *device = surface->resource.device;
656 DWORD active_sampler;
658 /* We don't need a specific texture unit, but after binding the texture
659 * the current unit is dirty. Read the unit back instead of switching to
660 * 0, this avoids messing around with the state manager's GL states. The
661 * current texture unit should always be a valid one.
663 * To be more specific, this is tricky because we can implicitly be
664 * called from sampler() in state.c. This means we can't touch anything
665 * other than whatever happens to be the currently active texture, or we
666 * would risk marking already applied sampler states dirty again. */
667 active_sampler = device->rev_tex_unit_map[context->active_texture];
669 if (active_sampler != WINED3D_UNMAPPED_STAGE)
670 device_invalidate_state(device, STATE_SAMPLER(active_sampler));
671 surface_bind(surface, context, srgb);
674 static void surface_force_reload(struct wined3d_surface *surface)
676 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
679 static void surface_release_client_storage(struct wined3d_surface *surface)
681 struct wined3d_context *context = context_acquire(surface->resource.device, NULL);
682 const struct wined3d_gl_info *gl_info = context->gl_info;
685 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
686 if (surface->texture_name)
688 surface_bind_and_dirtify(surface, context, FALSE);
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 if (surface->texture_name_srgb)
694 surface_bind_and_dirtify(surface, context, TRUE);
695 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
696 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
698 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
701 context_release(context);
703 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
704 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
705 surface_force_reload(surface);
708 static HRESULT surface_private_setup(struct wined3d_surface *surface)
710 /* TODO: Check against the maximum texture sizes supported by the video card. */
711 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
712 unsigned int pow2Width, pow2Height;
714 TRACE("surface %p.\n", surface);
716 surface->texture_name = 0;
717 surface->texture_target = GL_TEXTURE_2D;
719 /* Non-power2 support */
720 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
722 pow2Width = surface->resource.width;
723 pow2Height = surface->resource.height;
727 /* Find the nearest pow2 match */
728 pow2Width = pow2Height = 1;
729 while (pow2Width < surface->resource.width)
731 while (pow2Height < surface->resource.height)
734 surface->pow2Width = pow2Width;
735 surface->pow2Height = pow2Height;
737 if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
739 /* TODO: Add support for non power two compressed textures. */
740 if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
742 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
743 surface, surface->resource.width, surface->resource.height);
744 return WINED3DERR_NOTAVAILABLE;
748 if (pow2Width != surface->resource.width
749 || pow2Height != surface->resource.height)
751 surface->flags |= SFLAG_NONPOW2;
754 if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
755 && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
757 /* One of three options:
758 * 1: Do the same as we do with NPOT and scale the texture, (any
759 * texture ops would require the texture to be scaled which is
761 * 2: Set the texture to the maximum size (bad idea).
762 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
763 * 4: Create the surface, but allow it to be used only for DirectDraw
764 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
765 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
766 * the render target. */
767 if (surface->resource.pool == WINED3D_POOL_DEFAULT || surface->resource.pool == WINED3D_POOL_MANAGED)
769 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
770 return WINED3DERR_NOTAVAILABLE;
773 /* We should never use this surface in combination with OpenGL! */
774 TRACE("Creating an oversized surface: %ux%u.\n",
775 surface->pow2Width, surface->pow2Height);
779 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
780 * and EXT_PALETTED_TEXTURE is used in combination with texture
781 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
782 * EXT_PALETTED_TEXTURE doesn't work in combination with
783 * ARB_TEXTURE_RECTANGLE. */
784 if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
785 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
786 && gl_info->supported[EXT_PALETTED_TEXTURE]
787 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
789 surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
790 surface->pow2Width = surface->resource.width;
791 surface->pow2Height = surface->resource.height;
792 surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
796 switch (wined3d_settings.offscreen_rendering_mode)
799 surface->get_drawable_size = get_drawable_size_fbo;
803 surface->get_drawable_size = get_drawable_size_backbuffer;
807 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
808 return WINED3DERR_INVALIDCALL;
811 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
812 surface->flags |= SFLAG_DISCARDED;
817 static void surface_realize_palette(struct wined3d_surface *surface)
819 struct wined3d_palette *palette = surface->palette;
821 TRACE("surface %p.\n", surface);
823 if (!palette) return;
825 if (surface->resource.format->id == WINED3DFMT_P8_UINT
826 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
828 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
830 /* Make sure the texture is up to date. This call doesn't do
831 * anything if the texture is already up to date. */
832 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
834 /* We want to force a palette refresh, so mark the drawable as not being up to date */
835 if (!surface_is_offscreen(surface))
836 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
840 if (!(surface->flags & SFLAG_INSYSMEM))
842 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
843 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
845 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
849 if (surface->flags & SFLAG_DIBSECTION)
854 TRACE("Updating the DC's palette.\n");
856 for (i = 0; i < 256; ++i)
858 col[i].rgbRed = palette->palents[i].peRed;
859 col[i].rgbGreen = palette->palents[i].peGreen;
860 col[i].rgbBlue = palette->palents[i].peBlue;
861 col[i].rgbReserved = 0;
863 SetDIBColorTable(surface->hDC, 0, 256, col);
866 /* Propagate the changes to the drawable when we have a palette. */
867 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
868 surface_load_location(surface, surface->draw_binding, NULL);
871 static HRESULT surface_draw_overlay(struct wined3d_surface *surface)
875 /* If there's no destination surface there is nothing to do. */
876 if (!surface->overlay_dest)
879 /* Blt calls ModifyLocation on the dest surface, which in turn calls
880 * DrawOverlay to update the overlay. Prevent an endless recursion. */
881 if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
884 surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
885 hr = wined3d_surface_blt(surface->overlay_dest, &surface->overlay_destrect, surface,
886 &surface->overlay_srcrect, WINEDDBLT_WAIT, NULL, WINED3D_TEXF_LINEAR);
887 surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
892 static void surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
894 struct wined3d_device *device = surface->resource.device;
895 const RECT *pass_rect = rect;
897 TRACE("surface %p, rect %s, flags %#x.\n",
898 surface, wine_dbgstr_rect(rect), flags);
900 if (flags & WINED3D_MAP_DISCARD)
902 TRACE("WINED3D_MAP_DISCARD flag passed, marking SYSMEM as up to date.\n");
903 surface_prepare_system_memory(surface);
904 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
908 /* surface_load_location() does not check if the rectangle specifies
909 * the full surface. Most callers don't need that, so do it here. */
910 if (rect && !rect->top && !rect->left
911 && rect->right == surface->resource.width
912 && rect->bottom == surface->resource.height)
914 surface_load_location(surface, SFLAG_INSYSMEM, pass_rect);
917 if (surface->flags & SFLAG_PBO)
919 const struct wined3d_gl_info *gl_info;
920 struct wined3d_context *context;
922 context = context_acquire(device, NULL);
923 gl_info = context->gl_info;
926 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
927 checkGLcall("glBindBufferARB");
929 /* This shouldn't happen but could occur if some other function
930 * didn't handle the PBO properly. */
931 if (surface->resource.allocatedMemory)
932 ERR("The surface already has PBO memory allocated.\n");
934 surface->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
935 checkGLcall("glMapBufferARB");
937 /* Make sure the PBO isn't set anymore in order not to break non-PBO
939 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
940 checkGLcall("glBindBufferARB");
943 context_release(context);
946 if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
949 surface_add_dirty_rect(surface, NULL);
952 struct wined3d_box b;
956 b.right = rect->right;
957 b.bottom = rect->bottom;
960 surface_add_dirty_rect(surface, &b);
965 static void surface_unmap(struct wined3d_surface *surface)
967 struct wined3d_device *device = surface->resource.device;
970 TRACE("surface %p.\n", surface);
972 memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
974 if (surface->flags & SFLAG_PBO)
976 const struct wined3d_gl_info *gl_info;
977 struct wined3d_context *context;
979 TRACE("Freeing PBO memory.\n");
981 context = context_acquire(device, NULL);
982 gl_info = context->gl_info;
985 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
986 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
987 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
988 checkGLcall("glUnmapBufferARB");
990 context_release(context);
992 surface->resource.allocatedMemory = NULL;
995 TRACE("dirtyfied %u.\n", surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
997 if (surface->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
999 TRACE("Not dirtified, nothing to do.\n");
1003 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
1004 && surface->container.u.swapchain->front_buffer == surface)
1006 if (!surface->dirtyRect.left && !surface->dirtyRect.top
1007 && surface->dirtyRect.right == surface->resource.width
1008 && surface->dirtyRect.bottom == surface->resource.height)
1014 /* TODO: Proper partial rectangle tracking. */
1015 fullsurface = FALSE;
1016 surface->flags |= SFLAG_INSYSMEM;
1019 surface_load_location(surface, surface->draw_binding, fullsurface ? NULL : &surface->dirtyRect);
1021 /* Partial rectangle tracking is not commonly implemented, it is only
1022 * done for render targets. INSYSMEM was set before to tell
1023 * surface_load_location() where to read the rectangle from.
1024 * Indrawable is set because all modifications from the partial
1025 * sysmem copy are written back to the drawable, thus the surface is
1026 * merged again in the drawable. The sysmem copy is not fully up to
1027 * date because only a subrectangle was read in Map(). */
1030 surface_modify_location(surface, surface->draw_binding, TRUE);
1031 surface_evict_sysmem(surface);
1034 surface->dirtyRect.left = surface->resource.width;
1035 surface->dirtyRect.top = surface->resource.height;
1036 surface->dirtyRect.right = 0;
1037 surface->dirtyRect.bottom = 0;
1039 else if (surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
1041 FIXME("Depth / stencil buffer locking is not implemented.\n");
1045 /* Overlays have to be redrawn manually after changes with the GL implementation */
1046 if (surface->overlay_dest)
1047 surface_draw_overlay(surface);
1050 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
1052 if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
1054 if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
1059 static void wined3d_surface_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_surface *src_surface,
1060 const RECT *src_rect, struct wined3d_surface *dst_surface, const RECT *dst_rect)
1062 const struct wined3d_gl_info *gl_info;
1063 struct wined3d_context *context;
1064 DWORD src_mask, dst_mask;
1067 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
1068 device, src_surface, wine_dbgstr_rect(src_rect),
1069 dst_surface, wine_dbgstr_rect(dst_rect));
1071 src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1072 dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1074 if (src_mask != dst_mask)
1076 ERR("Incompatible formats %s and %s.\n",
1077 debug_d3dformat(src_surface->resource.format->id),
1078 debug_d3dformat(dst_surface->resource.format->id));
1084 ERR("Not a depth / stencil format: %s.\n",
1085 debug_d3dformat(src_surface->resource.format->id));
1090 if (src_mask & WINED3DFMT_FLAG_DEPTH)
1091 gl_mask |= GL_DEPTH_BUFFER_BIT;
1092 if (src_mask & WINED3DFMT_FLAG_STENCIL)
1093 gl_mask |= GL_STENCIL_BUFFER_BIT;
1095 /* Make sure the locations are up-to-date. Loading the destination
1096 * surface isn't required if the entire surface is overwritten. */
1097 surface_load_location(src_surface, SFLAG_INTEXTURE, NULL);
1098 if (!surface_is_full_rect(dst_surface, dst_rect))
1099 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
1101 context = context_acquire(device, NULL);
1102 if (!context->valid)
1104 context_release(context);
1105 WARN("Invalid context, skipping blit.\n");
1109 gl_info = context->gl_info;
1113 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, SFLAG_INTEXTURE);
1114 gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
1115 checkGLcall("glReadBuffer()");
1116 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1118 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, SFLAG_INTEXTURE);
1119 context_set_draw_buffer(context, GL_NONE);
1120 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1121 context_invalidate_state(context, STATE_FRAMEBUFFER);
1123 if (gl_mask & GL_DEPTH_BUFFER_BIT)
1125 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
1126 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
1128 if (gl_mask & GL_STENCIL_BUFFER_BIT)
1130 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
1132 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
1133 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
1135 gl_info->gl_ops.gl.p_glStencilMask(~0U);
1136 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
1139 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1140 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1142 gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
1143 dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
1144 checkGLcall("glBlitFramebuffer()");
1148 if (wined3d_settings.strict_draw_ordering)
1149 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
1151 context_release(context);
1154 /* Blit between surface locations. Onscreen on different swapchains is not supported.
1155 * Depth / stencil is not supported. */
1156 static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_texture_filter_type filter,
1157 struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect_in,
1158 struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
1160 const struct wined3d_gl_info *gl_info;
1161 struct wined3d_context *context;
1162 RECT src_rect, dst_rect;
1166 TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
1167 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1168 src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
1169 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1170 dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
1172 src_rect = *src_rect_in;
1173 dst_rect = *dst_rect_in;
1177 case WINED3D_TEXF_LINEAR:
1178 gl_filter = GL_LINEAR;
1182 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
1183 case WINED3D_TEXF_NONE:
1184 case WINED3D_TEXF_POINT:
1185 gl_filter = GL_NEAREST;
1189 /* Resolve the source surface first if needed. */
1190 if (src_location == SFLAG_INRB_MULTISAMPLE
1191 && (src_surface->resource.format->id != dst_surface->resource.format->id
1192 || abs(src_rect.bottom - src_rect.top) != abs(dst_rect.bottom - dst_rect.top)
1193 || abs(src_rect.right - src_rect.left) != abs(dst_rect.right - dst_rect.left)))
1194 src_location = SFLAG_INRB_RESOLVED;
1196 /* Make sure the locations are up-to-date. Loading the destination
1197 * surface isn't required if the entire surface is overwritten. (And is
1198 * in fact harmful if we're being called by surface_load_location() with
1199 * the purpose of loading the destination surface.) */
1200 surface_load_location(src_surface, src_location, NULL);
1201 if (!surface_is_full_rect(dst_surface, &dst_rect))
1202 surface_load_location(dst_surface, dst_location, NULL);
1204 if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
1205 else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
1206 else context = context_acquire(device, NULL);
1208 if (!context->valid)
1210 context_release(context);
1211 WARN("Invalid context, skipping blit.\n");
1215 gl_info = context->gl_info;
1217 if (src_location == SFLAG_INDRAWABLE)
1219 TRACE("Source surface %p is onscreen.\n", src_surface);
1220 buffer = surface_get_gl_buffer(src_surface);
1221 surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
1225 TRACE("Source surface %p is offscreen.\n", src_surface);
1226 buffer = GL_COLOR_ATTACHMENT0;
1230 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
1231 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
1232 checkGLcall("glReadBuffer()");
1233 context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
1236 if (dst_location == SFLAG_INDRAWABLE)
1238 TRACE("Destination surface %p is onscreen.\n", dst_surface);
1239 buffer = surface_get_gl_buffer(dst_surface);
1240 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
1244 TRACE("Destination surface %p is offscreen.\n", dst_surface);
1245 buffer = GL_COLOR_ATTACHMENT0;
1249 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
1250 context_set_draw_buffer(context, buffer);
1251 context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
1252 context_invalidate_state(context, STATE_FRAMEBUFFER);
1254 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1255 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
1256 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
1257 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
1258 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
1260 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
1261 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE));
1263 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
1264 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
1265 checkGLcall("glBlitFramebuffer()");
1269 if (wined3d_settings.strict_draw_ordering
1270 || (dst_location == SFLAG_INDRAWABLE
1271 && dst_surface->container.u.swapchain->front_buffer == dst_surface))
1272 gl_info->gl_ops.gl.p_glFlush();
1274 context_release(context);
1277 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
1278 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
1279 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
1281 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
1284 /* Source and/or destination need to be on the GL side */
1285 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
1290 case WINED3D_BLIT_OP_COLOR_BLIT:
1291 if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
1293 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
1297 case WINED3D_BLIT_OP_DEPTH_BLIT:
1298 if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1300 if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
1308 if (!(src_format->id == dst_format->id
1309 || (is_identity_fixup(src_format->color_fixup)
1310 && is_identity_fixup(dst_format->color_fixup))))
1316 /* This function checks if the primary render target uses the 8bit paletted format. */
1317 static BOOL primary_render_target_is_p8(const struct wined3d_device *device)
1319 if (device->fb.render_targets && device->fb.render_targets[0])
1321 const struct wined3d_surface *render_target = device->fb.render_targets[0];
1322 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
1323 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
1329 static BOOL surface_convert_color_to_float(const struct wined3d_surface *surface,
1330 DWORD color, struct wined3d_color *float_color)
1332 const struct wined3d_format *format = surface->resource.format;
1333 const struct wined3d_device *device = surface->resource.device;
1337 case WINED3DFMT_P8_UINT:
1338 if (surface->palette)
1340 float_color->r = surface->palette->palents[color].peRed / 255.0f;
1341 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
1342 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
1346 float_color->r = 0.0f;
1347 float_color->g = 0.0f;
1348 float_color->b = 0.0f;
1350 float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
1353 case WINED3DFMT_B5G6R5_UNORM:
1354 float_color->r = ((color >> 11) & 0x1f) / 31.0f;
1355 float_color->g = ((color >> 5) & 0x3f) / 63.0f;
1356 float_color->b = (color & 0x1f) / 31.0f;
1357 float_color->a = 1.0f;
1360 case WINED3DFMT_B8G8R8_UNORM:
1361 case WINED3DFMT_B8G8R8X8_UNORM:
1362 float_color->r = D3DCOLOR_R(color);
1363 float_color->g = D3DCOLOR_G(color);
1364 float_color->b = D3DCOLOR_B(color);
1365 float_color->a = 1.0f;
1368 case WINED3DFMT_B8G8R8A8_UNORM:
1369 float_color->r = D3DCOLOR_R(color);
1370 float_color->g = D3DCOLOR_G(color);
1371 float_color->b = D3DCOLOR_B(color);
1372 float_color->a = D3DCOLOR_A(color);
1376 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1383 static BOOL surface_convert_depth_to_float(const struct wined3d_surface *surface, DWORD depth, float *float_depth)
1385 const struct wined3d_format *format = surface->resource.format;
1389 case WINED3DFMT_S1_UINT_D15_UNORM:
1390 *float_depth = depth / (float)0x00007fff;
1393 case WINED3DFMT_D16_UNORM:
1394 *float_depth = depth / (float)0x0000ffff;
1397 case WINED3DFMT_D24_UNORM_S8_UINT:
1398 case WINED3DFMT_X8D24_UNORM:
1399 *float_depth = depth / (float)0x00ffffff;
1402 case WINED3DFMT_D32_UNORM:
1403 *float_depth = depth / (float)0xffffffff;
1407 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1414 /* Do not call while under the GL lock. */
1415 static HRESULT wined3d_surface_depth_fill(struct wined3d_surface *surface, const RECT *rect, float depth)
1417 const struct wined3d_resource *resource = &surface->resource;
1418 struct wined3d_device *device = resource->device;
1419 const struct blit_shader *blitter;
1421 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
1422 NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
1425 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1426 return WINED3DERR_INVALIDCALL;
1429 return blitter->depth_fill(device, surface, rect, depth);
1432 static HRESULT wined3d_surface_depth_blt(struct wined3d_surface *src_surface, const RECT *src_rect,
1433 struct wined3d_surface *dst_surface, const RECT *dst_rect)
1435 struct wined3d_device *device = src_surface->resource.device;
1437 if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
1438 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1439 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1440 return WINED3DERR_INVALIDCALL;
1442 wined3d_surface_depth_blt_fbo(device, src_surface, src_rect, dst_surface, dst_rect);
1444 surface_modify_ds_location(dst_surface, SFLAG_INTEXTURE,
1445 dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
1450 /* Do not call while under the GL lock. */
1451 HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
1452 struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
1453 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
1455 struct wined3d_swapchain *src_swapchain, *dst_swapchain;
1456 struct wined3d_device *device = dst_surface->resource.device;
1457 DWORD src_ds_flags, dst_ds_flags;
1458 RECT src_rect, dst_rect;
1459 BOOL scale, convert;
1461 static const DWORD simple_blit = WINEDDBLT_ASYNC
1462 | WINEDDBLT_COLORFILL
1464 | WINEDDBLT_DEPTHFILL
1465 | WINEDDBLT_DONOTWAIT;
1467 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1468 dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
1469 flags, fx, debug_d3dtexturefiltertype(filter));
1470 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
1474 TRACE("dwSize %#x.\n", fx->dwSize);
1475 TRACE("dwDDFX %#x.\n", fx->dwDDFX);
1476 TRACE("dwROP %#x.\n", fx->dwROP);
1477 TRACE("dwDDROP %#x.\n", fx->dwDDROP);
1478 TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle);
1479 TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode);
1480 TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow);
1481 TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh);
1482 TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest);
1483 TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth);
1484 TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest);
1485 TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth);
1486 TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc);
1487 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth);
1488 TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend);
1489 TRACE("dwReserved %#x.\n", fx->dwReserved);
1490 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth);
1491 TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest);
1492 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth);
1493 TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc);
1494 TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern);
1495 TRACE("ddckDestColorkey {%#x, %#x}.\n",
1496 fx->ddckDestColorkey.color_space_low_value,
1497 fx->ddckDestColorkey.color_space_high_value);
1498 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
1499 fx->ddckSrcColorkey.color_space_low_value,
1500 fx->ddckSrcColorkey.color_space_high_value);
1503 if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
1505 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1506 return WINEDDERR_SURFACEBUSY;
1509 surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
1511 if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom
1512 || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0
1513 || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0
1514 || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0
1515 || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0)
1517 WARN("The application gave us a bad destination rectangle.\n");
1518 return WINEDDERR_INVALIDRECT;
1523 surface_get_rect(src_surface, src_rect_in, &src_rect);
1525 if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom
1526 || src_rect.left > src_surface->resource.width || src_rect.left < 0
1527 || src_rect.top > src_surface->resource.height || src_rect.top < 0
1528 || src_rect.right > src_surface->resource.width || src_rect.right < 0
1529 || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0)
1531 WARN("Application gave us bad source rectangle for Blt.\n");
1532 return WINEDDERR_INVALIDRECT;
1537 memset(&src_rect, 0, sizeof(src_rect));
1540 if (!fx || !(fx->dwDDFX))
1541 flags &= ~WINEDDBLT_DDFX;
1543 if (flags & WINEDDBLT_WAIT)
1544 flags &= ~WINEDDBLT_WAIT;
1546 if (flags & WINEDDBLT_ASYNC)
1548 static unsigned int once;
1551 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1552 flags &= ~WINEDDBLT_ASYNC;
1555 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1556 if (flags & WINEDDBLT_DONOTWAIT)
1558 static unsigned int once;
1561 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1562 flags &= ~WINEDDBLT_DONOTWAIT;
1565 if (!device->d3d_initialized)
1567 WARN("D3D not initialized, using fallback.\n");
1571 /* We want to avoid invalidating the sysmem location for converted
1572 * surfaces, since otherwise we'd have to convert the data back when
1574 if (dst_surface->flags & SFLAG_CONVERTED)
1576 WARN("Converted surface, using CPU blit.\n");
1577 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1580 if (flags & ~simple_blit)
1582 WARN("Using fallback for complex blit (%#x).\n", flags);
1586 if (src_surface && src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1587 src_swapchain = src_surface->container.u.swapchain;
1589 src_swapchain = NULL;
1591 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
1592 dst_swapchain = dst_surface->container.u.swapchain;
1594 dst_swapchain = NULL;
1596 /* This isn't strictly needed. FBO blits for example could deal with
1597 * cross-swapchain blits by first downloading the source to a texture
1598 * before switching to the destination context. We just have this here to
1599 * not have to deal with the issue, since cross-swapchain blits should be
1601 if (src_swapchain && dst_swapchain && src_swapchain != dst_swapchain)
1603 FIXME("Using fallback for cross-swapchain blit.\n");
1608 && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
1609 || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top);
1610 convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
1612 dst_ds_flags = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1614 src_ds_flags = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
1618 if (src_ds_flags || dst_ds_flags)
1620 if (flags & WINEDDBLT_DEPTHFILL)
1624 TRACE("Depth fill.\n");
1626 if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
1627 return WINED3DERR_INVALIDCALL;
1629 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth)))
1634 if (src_ds_flags != dst_ds_flags)
1636 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1637 return WINED3DERR_INVALIDCALL;
1640 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, &src_rect, dst_surface, &dst_rect)))
1646 /* In principle this would apply to depth blits as well, but we don't
1647 * implement those in the CPU blitter at the moment. */
1648 if ((dst_surface->flags & SFLAG_INSYSMEM)
1649 && (!src_surface || (src_surface->flags & SFLAG_INSYSMEM)))
1652 TRACE("Not doing sysmem blit because of scaling.\n");
1654 TRACE("Not doing sysmem blit because of format conversion.\n");
1656 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1659 if (flags & WINEDDBLT_COLORFILL)
1661 struct wined3d_color color;
1663 TRACE("Color fill.\n");
1665 if (!surface_convert_color_to_float(dst_surface, fx->u5.dwFillColor, &color))
1668 if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
1673 TRACE("Color blit.\n");
1676 if ((src_surface->flags & SFLAG_INSYSMEM) && !(dst_surface->flags & SFLAG_INSYSMEM))
1679 TRACE("Not doing upload because of scaling.\n");
1681 TRACE("Not doing upload because of format conversion.\n");
1684 POINT dst_point = {dst_rect.left, dst_rect.top};
1686 if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect)))
1688 if (!surface_is_offscreen(dst_surface))
1689 surface_load_location(dst_surface, dst_surface->draw_binding, NULL);
1695 /* Use present for back -> front blits. The idea behind this is
1696 * that present is potentially faster than a blit, in particular
1697 * when FBO blits aren't available. Some ddraw applications like
1698 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
1699 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
1700 * applications can't blit directly to the frontbuffer. */
1701 if (dst_swapchain && dst_swapchain->back_buffers
1702 && dst_surface == dst_swapchain->front_buffer
1703 && src_surface == dst_swapchain->back_buffers[0])
1705 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
1707 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1709 /* Set the swap effect to COPY, we don't want the backbuffer
1710 * to become undefined. */
1711 dst_swapchain->desc.swap_effect = WINED3D_SWAP_EFFECT_COPY;
1712 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
1713 dst_swapchain->desc.swap_effect = swap_effect;
1718 if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1719 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1720 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1722 TRACE("Using FBO blit.\n");
1724 surface_blt_fbo(device, filter,
1725 src_surface, src_surface->draw_binding, &src_rect,
1726 dst_surface, dst_surface->draw_binding, &dst_rect);
1727 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
1731 if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
1732 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
1733 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
1735 TRACE("Using arbfp blit.\n");
1737 if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
1745 /* Special cases for render targets. */
1746 if ((dst_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1747 || (src_surface && (src_surface->resource.usage & WINED3DUSAGE_RENDERTARGET)))
1749 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface, &dst_rect,
1750 src_surface, &src_rect, flags, fx, filter)))
1756 /* For the rest call the X11 surface implementation. For render targets
1757 * this should be implemented OpenGL accelerated in BltOverride, other
1758 * blits are rather rare. */
1759 return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
1762 HRESULT CDECL wined3d_surface_get_render_target_data(struct wined3d_surface *surface,
1763 struct wined3d_surface *render_target)
1765 TRACE("surface %p, render_target %p.\n", surface, render_target);
1767 /* TODO: Check surface sizes, pools, etc. */
1769 if (render_target->resource.multisample_type)
1770 return WINED3DERR_INVALIDCALL;
1772 return wined3d_surface_blt(surface, NULL, render_target, NULL, 0, NULL, WINED3D_TEXF_POINT);
1775 /* Context activation is done by the caller. */
1776 static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
1778 if (surface->flags & SFLAG_DIBSECTION)
1780 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1784 if (!surface->resource.heapMemory)
1785 surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
1786 else if (!(surface->flags & SFLAG_CLIENT))
1787 ERR("Surface %p has heapMemory %p and flags %#x.\n",
1788 surface, surface->resource.heapMemory, surface->flags);
1790 surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
1791 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1795 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
1796 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1797 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
1798 surface->resource.size, surface->resource.allocatedMemory));
1799 checkGLcall("glGetBufferSubDataARB");
1800 GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
1801 checkGLcall("glDeleteBuffersARB");
1805 surface->flags &= ~SFLAG_PBO;
1808 static BOOL surface_init_sysmem(struct wined3d_surface *surface)
1810 if (!surface->resource.allocatedMemory)
1812 if (!surface->resource.heapMemory)
1814 if (!(surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1815 surface->resource.size + RESOURCE_ALIGNMENT)))
1817 ERR("Failed to allocate memory.\n");
1821 else if (!(surface->flags & SFLAG_CLIENT))
1823 ERR("Surface %p has heapMemory %p and flags %#x.\n",
1824 surface, surface->resource.heapMemory, surface->flags);
1827 surface->resource.allocatedMemory =
1828 (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1832 memset(surface->resource.allocatedMemory, 0, surface->resource.size);
1835 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1840 /* Do not call while under the GL lock. */
1841 static void surface_unload(struct wined3d_resource *resource)
1843 struct wined3d_surface *surface = surface_from_resource(resource);
1844 struct wined3d_renderbuffer_entry *entry, *entry2;
1845 struct wined3d_device *device = resource->device;
1846 const struct wined3d_gl_info *gl_info;
1847 struct wined3d_context *context;
1849 TRACE("surface %p.\n", surface);
1851 if (resource->pool == WINED3D_POOL_DEFAULT)
1853 /* Default pool resources are supposed to be destroyed before Reset is called.
1854 * Implicit resources stay however. So this means we have an implicit render target
1855 * or depth stencil. The content may be destroyed, but we still have to tear down
1856 * opengl resources, so we cannot leave early.
1858 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1859 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1860 * or the depth stencil into an FBO the texture or render buffer will be removed
1861 * and all flags get lost
1863 if (!(surface->flags & SFLAG_PBO))
1864 surface_init_sysmem(surface);
1865 /* We also get here when the ddraw swapchain is destroyed, for example
1866 * for a mode switch. In this case this surface won't necessarily be
1867 * an implicit surface. We have to mark it lost so that the
1868 * application can restore it after the mode switch. */
1869 surface->flags |= SFLAG_LOST;
1873 /* Load the surface into system memory */
1874 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1875 surface_modify_location(surface, surface->draw_binding, FALSE);
1877 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
1878 surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
1879 surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1881 context = context_acquire(device, NULL);
1882 gl_info = context->gl_info;
1884 /* Destroy PBOs, but load them into real sysmem before */
1885 if (surface->flags & SFLAG_PBO)
1886 surface_remove_pbo(surface, gl_info);
1888 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1889 * all application-created targets the application has to release the surface
1890 * before calling _Reset
1892 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
1895 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1897 list_remove(&entry->entry);
1898 HeapFree(GetProcessHeap(), 0, entry);
1900 list_init(&surface->renderbuffers);
1901 surface->current_renderbuffer = NULL;
1905 /* If we're in a texture, the texture name belongs to the texture.
1906 * Otherwise, destroy it. */
1907 if (surface->container.type != WINED3D_CONTAINER_TEXTURE)
1909 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name);
1910 surface->texture_name = 0;
1911 gl_info->gl_ops.gl.p_glDeleteTextures(1, &surface->texture_name_srgb);
1912 surface->texture_name_srgb = 0;
1914 if (surface->rb_multisample)
1916 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_multisample);
1917 surface->rb_multisample = 0;
1919 if (surface->rb_resolved)
1921 gl_info->fbo_ops.glDeleteRenderbuffers(1, &surface->rb_resolved);
1922 surface->rb_resolved = 0;
1927 context_release(context);
1929 resource_unload(resource);
1932 static const struct wined3d_resource_ops surface_resource_ops =
1937 static const struct wined3d_surface_ops surface_ops =
1939 surface_private_setup,
1940 surface_realize_palette,
1945 /*****************************************************************************
1946 * Initializes the GDI surface, aka creates the DIB section we render to
1947 * The DIB section creation is done by calling GetDC, which will create the
1948 * section and releasing the dc to allow the app to use it. The dib section
1949 * will stay until the surface is released
1951 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1952 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1953 * avoid confusion in the shared surface code.
1956 * WINED3D_OK on success
1957 * The return values of called methods on failure
1959 *****************************************************************************/
1960 static HRESULT gdi_surface_private_setup(struct wined3d_surface *surface)
1964 TRACE("surface %p.\n", surface);
1966 if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
1968 ERR("Overlays not yet supported by GDI surfaces.\n");
1969 return WINED3DERR_INVALIDCALL;
1972 /* Sysmem textures have memory already allocated - release it,
1973 * this avoids an unnecessary memcpy. */
1974 hr = surface_create_dib_section(surface);
1977 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
1978 surface->resource.heapMemory = NULL;
1979 surface->resource.allocatedMemory = surface->dib.bitmap_data;
1982 /* We don't mind the nonpow2 stuff in GDI. */
1983 surface->pow2Width = surface->resource.width;
1984 surface->pow2Height = surface->resource.height;
1989 static void gdi_surface_realize_palette(struct wined3d_surface *surface)
1991 struct wined3d_palette *palette = surface->palette;
1993 TRACE("surface %p.\n", surface);
1995 if (!palette) return;
1997 if (surface->flags & SFLAG_DIBSECTION)
2002 TRACE("Updating the DC's palette.\n");
2004 for (i = 0; i < 256; ++i)
2006 col[i].rgbRed = palette->palents[i].peRed;
2007 col[i].rgbGreen = palette->palents[i].peGreen;
2008 col[i].rgbBlue = palette->palents[i].peBlue;
2009 col[i].rgbReserved = 0;
2011 SetDIBColorTable(surface->hDC, 0, 256, col);
2014 /* Update the image because of the palette change. Some games like e.g.
2015 * Red Alert call SetEntries a lot to implement fading. */
2016 /* Tell the swapchain to update the screen. */
2017 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
2019 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2020 if (surface == swapchain->front_buffer)
2022 x11_copy_to_screen(swapchain, NULL);
2027 static void gdi_surface_map(struct wined3d_surface *surface, const RECT *rect, DWORD flags)
2029 TRACE("surface %p, rect %s, flags %#x.\n",
2030 surface, wine_dbgstr_rect(rect), flags);
2032 if (!(surface->flags & SFLAG_DIBSECTION))
2036 /* This happens on gdi surfaces if the application set a user pointer
2037 * and resets it. Recreate the DIB section. */
2038 if (FAILED(hr = surface_create_dib_section(surface)))
2040 ERR("Failed to create dib section, hr %#x.\n", hr);
2043 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
2044 surface->resource.heapMemory = NULL;
2045 surface->resource.allocatedMemory = surface->dib.bitmap_data;
2049 static void gdi_surface_unmap(struct wined3d_surface *surface)
2051 TRACE("surface %p.\n", surface);
2053 /* Tell the swapchain to update the screen. */
2054 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
2056 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2057 if (surface == swapchain->front_buffer)
2059 x11_copy_to_screen(swapchain, &surface->lockedRect);
2063 memset(&surface->lockedRect, 0, sizeof(RECT));
2066 static const struct wined3d_surface_ops gdi_surface_ops =
2068 gdi_surface_private_setup,
2069 gdi_surface_realize_palette,
2074 void surface_set_texture_name(struct wined3d_surface *surface, GLuint new_name, BOOL srgb)
2079 TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
2083 name = &surface->texture_name_srgb;
2084 flag = SFLAG_INSRGBTEX;
2088 name = &surface->texture_name;
2089 flag = SFLAG_INTEXTURE;
2092 if (!*name && new_name)
2094 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2095 * surface has no texture name yet. See if we can get rid of this. */
2096 if (surface->flags & flag)
2098 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
2099 surface_modify_location(surface, flag, FALSE);
2104 surface_force_reload(surface);
2107 void surface_set_texture_target(struct wined3d_surface *surface, GLenum target, GLint level)
2109 TRACE("surface %p, target %#x.\n", surface, target);
2111 if (surface->texture_target != target)
2113 if (target == GL_TEXTURE_RECTANGLE_ARB)
2115 surface->flags &= ~SFLAG_NORMCOORD;
2117 else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
2119 surface->flags |= SFLAG_NORMCOORD;
2122 surface->texture_target = target;
2123 surface->texture_level = level;
2124 surface_force_reload(surface);
2127 /* This call just downloads data, the caller is responsible for binding the
2128 * correct texture. */
2129 /* Context activation is done by the caller. */
2130 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2132 const struct wined3d_format *format = surface->resource.format;
2134 /* Only support read back of converted P8 surfaces. */
2135 if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
2137 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
2143 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2145 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2146 surface, surface->texture_level, format->glFormat, format->glType,
2147 surface->resource.allocatedMemory);
2149 if (surface->flags & SFLAG_PBO)
2151 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2152 checkGLcall("glBindBufferARB");
2153 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
2154 checkGLcall("glGetCompressedTexImageARB");
2155 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2156 checkGLcall("glBindBufferARB");
2160 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
2161 surface->texture_level, surface->resource.allocatedMemory));
2162 checkGLcall("glGetCompressedTexImageARB");
2170 GLenum gl_format = format->glFormat;
2171 GLenum gl_type = format->glType;
2175 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2176 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device))
2178 gl_format = GL_ALPHA;
2179 gl_type = GL_UNSIGNED_BYTE;
2182 if (surface->flags & SFLAG_NONPOW2)
2184 unsigned char alignment = surface->resource.device->surface_alignment;
2185 src_pitch = format->byte_count * surface->pow2Width;
2186 dst_pitch = wined3d_surface_get_pitch(surface);
2187 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
2188 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
2192 mem = surface->resource.allocatedMemory;
2195 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2196 surface, surface->texture_level, gl_format, gl_type, mem);
2198 if (surface->flags & SFLAG_PBO)
2200 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2201 checkGLcall("glBindBufferARB");
2203 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2204 gl_format, gl_type, NULL);
2205 checkGLcall("glGetTexImage");
2207 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2208 checkGLcall("glBindBufferARB");
2212 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2213 gl_format, gl_type, mem);
2214 checkGLcall("glGetTexImage");
2218 if (surface->flags & SFLAG_NONPOW2)
2220 const BYTE *src_data;
2224 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2225 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2226 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2228 * We're doing this...
2230 * instead of boxing the texture :
2231 * |<-texture width ->| -->pow2width| /\
2232 * |111111111111111111| | |
2233 * |222 Texture 222222| boxed empty | texture height
2234 * |3333 Data 33333333| | |
2235 * |444444444444444444| | \/
2236 * ----------------------------------- |
2237 * | boxed empty | boxed empty | pow2height
2239 * -----------------------------------
2242 * we're repacking the data to the expected texture width
2244 * |<-texture width ->| -->pow2width| /\
2245 * |111111111111111111222222222222222| |
2246 * |222333333333333333333444444444444| texture height
2250 * | empty | pow2height
2252 * -----------------------------------
2256 * |<-texture width ->| /\
2257 * |111111111111111111|
2258 * |222222222222222222|texture height
2259 * |333333333333333333|
2260 * |444444444444444444| \/
2261 * --------------------
2263 * this also means that any references to allocatedMemory should work with the data as if were a
2264 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2266 * internally the texture is still stored in a boxed format so any references to textureName will
2267 * get a boxed texture with width pow2width and not a texture of width resource.width.
2269 * Performance should not be an issue, because applications normally do not lock the surfaces when
2270 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2271 * and doesn't have to be re-read. */
2273 dst_data = surface->resource.allocatedMemory;
2274 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
2275 for (y = 1; y < surface->resource.height; ++y)
2277 /* skip the first row */
2278 src_data += src_pitch;
2279 dst_data += dst_pitch;
2280 memcpy(dst_data, src_data, dst_pitch);
2283 HeapFree(GetProcessHeap(), 0, mem);
2287 /* Surface has now been downloaded */
2288 surface->flags |= SFLAG_INSYSMEM;
2291 /* This call just uploads data, the caller is responsible for binding the
2292 * correct texture. */
2293 /* Context activation is done by the caller. */
2294 static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2295 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
2296 BOOL srgb, const struct wined3d_bo_address *data)
2298 UINT update_w = src_rect->right - src_rect->left;
2299 UINT update_h = src_rect->bottom - src_rect->top;
2301 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
2302 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
2303 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
2305 if (surface->resource.map_count)
2307 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
2308 surface->flags |= SFLAG_PIN_SYSMEM;
2311 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2313 update_h *= format->height_scale.numerator;
2314 update_h /= format->height_scale.denominator;
2319 if (data->buffer_object)
2321 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
2322 checkGLcall("glBindBufferARB");
2325 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2327 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1);
2328 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
2329 const BYTE *addr = data->addr;
2332 addr += (src_rect->top / format->block_height) * src_pitch;
2333 addr += (src_rect->left / format->block_width) * format->block_byte_count;
2336 internal = format->glGammaInternal;
2337 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2338 internal = format->rtInternal;
2340 internal = format->glInternal;
2342 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2343 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
2344 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
2346 if (row_length == src_pitch)
2348 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2349 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
2355 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2356 * can't use the unpack row length like below. */
2357 for (row = 0, y = dst_point->y; row < row_count; ++row)
2359 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2360 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
2361 y += format->block_height;
2365 checkGLcall("glCompressedTexSubImage2DARB");
2369 const BYTE *addr = data->addr;
2371 addr += src_rect->top * src_pitch;
2372 addr += src_rect->left * format->byte_count;
2374 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2375 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
2376 update_w, update_h, format->glFormat, format->glType, addr);
2378 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
2379 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
2380 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
2381 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2382 checkGLcall("glTexSubImage2D");
2385 if (data->buffer_object)
2387 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2388 checkGLcall("glBindBufferARB");
2393 if (wined3d_settings.strict_draw_ordering)
2394 gl_info->gl_ops.gl.p_glFlush();
2396 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2398 struct wined3d_device *device = surface->resource.device;
2401 for (i = 0; i < device->context_count; ++i)
2403 context_surface_update(device->contexts[i], surface);
2408 static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
2409 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
2411 BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2412 const struct wined3d_device *device = surface->resource.device;
2413 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2414 BOOL blit_supported = FALSE;
2416 /* Copy the default values from the surface. Below we might perform fixups */
2417 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2418 *format = *surface->resource.format;
2419 *conversion_type = WINED3D_CT_NONE;
2421 /* Ok, now look if we have to do any conversion */
2422 switch (surface->resource.format->id)
2424 case WINED3DFMT_P8_UINT:
2425 /* Below the call to blit_supported is disabled for Wine 1.2
2426 * because the function isn't operating correctly yet. At the
2427 * moment 8-bit blits are handled in software and if certain GL
2428 * extensions are around, surface conversion is performed at
2429 * upload time. The blit_supported call recognizes it as a
2430 * destination fixup. This type of upload 'fixup' and 8-bit to
2431 * 8-bit blits need to be handled by the blit_shader.
2432 * TODO: get rid of this #if 0. */
2434 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2435 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
2436 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
2438 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2440 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2441 * texturing. Further also use conversion in case of color keying.
2442 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2443 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2444 * conflicts with this.
2446 if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
2447 || colorkey_active || !use_texturing)
2449 format->glFormat = GL_RGBA;
2450 format->glInternal = GL_RGBA;
2451 format->glType = GL_UNSIGNED_BYTE;
2452 format->conv_byte_count = 4;
2453 if (colorkey_active)
2454 *conversion_type = WINED3D_CT_PALETTED_CK;
2456 *conversion_type = WINED3D_CT_PALETTED;
2460 case WINED3DFMT_B2G3R3_UNORM:
2461 /* **********************
2462 GL_UNSIGNED_BYTE_3_3_2
2463 ********************** */
2464 if (colorkey_active) {
2465 /* This texture format will never be used.. So do not care about color keying
2466 up until the point in time it will be needed :-) */
2467 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2471 case WINED3DFMT_B5G6R5_UNORM:
2472 if (colorkey_active)
2474 *conversion_type = WINED3D_CT_CK_565;
2475 format->glFormat = GL_RGBA;
2476 format->glInternal = GL_RGB5_A1;
2477 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2478 format->conv_byte_count = 2;
2482 case WINED3DFMT_B5G5R5X1_UNORM:
2483 if (colorkey_active)
2485 *conversion_type = WINED3D_CT_CK_5551;
2486 format->glFormat = GL_BGRA;
2487 format->glInternal = GL_RGB5_A1;
2488 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2489 format->conv_byte_count = 2;
2493 case WINED3DFMT_B8G8R8_UNORM:
2494 if (colorkey_active)
2496 *conversion_type = WINED3D_CT_CK_RGB24;
2497 format->glFormat = GL_RGBA;
2498 format->glInternal = GL_RGBA8;
2499 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2500 format->conv_byte_count = 4;
2504 case WINED3DFMT_B8G8R8X8_UNORM:
2505 if (colorkey_active)
2507 *conversion_type = WINED3D_CT_RGB32_888;
2508 format->glFormat = GL_RGBA;
2509 format->glInternal = GL_RGBA8;
2510 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2511 format->conv_byte_count = 4;
2515 case WINED3DFMT_B8G8R8A8_UNORM:
2516 if (colorkey_active)
2518 *conversion_type = WINED3D_CT_CK_ARGB32;
2519 format->conv_byte_count = 4;
2527 if (*conversion_type != WINED3D_CT_NONE)
2529 format->rtInternal = format->glInternal;
2530 format->glGammaInternal = format->glInternal;
2536 static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
2538 UINT width_mask, height_mask;
2540 if (!rect->left && !rect->top
2541 && rect->right == surface->resource.width
2542 && rect->bottom == surface->resource.height)
2545 /* This assumes power of two block sizes, but NPOT block sizes would be
2547 width_mask = surface->resource.format->block_width - 1;
2548 height_mask = surface->resource.format->block_height - 1;
2550 if (!(rect->left & width_mask) && !(rect->top & height_mask)
2551 && !(rect->right & width_mask) && !(rect->bottom & height_mask))
2557 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
2558 struct wined3d_surface *src_surface, const RECT *src_rect)
2560 const struct wined3d_format *src_format;
2561 const struct wined3d_format *dst_format;
2562 const struct wined3d_gl_info *gl_info;
2563 enum wined3d_conversion_type convert;
2564 struct wined3d_context *context;
2565 struct wined3d_bo_address data;
2566 struct wined3d_format format;
2567 UINT update_w, update_h;
2573 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2574 dst_surface, wine_dbgstr_point(dst_point),
2575 src_surface, wine_dbgstr_rect(src_rect));
2577 src_format = src_surface->resource.format;
2578 dst_format = dst_surface->resource.format;
2580 if (src_format->id != dst_format->id)
2582 WARN("Source and destination surfaces should have the same format.\n");
2583 return WINED3DERR_INVALIDCALL;
2592 else if (dst_point->x < 0 || dst_point->y < 0)
2594 WARN("Invalid destination point.\n");
2595 return WINED3DERR_INVALIDCALL;
2602 r.right = src_surface->resource.width;
2603 r.bottom = src_surface->resource.height;
2606 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
2607 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
2609 WARN("Invalid source rectangle.\n");
2610 return WINED3DERR_INVALIDCALL;
2613 dst_w = dst_surface->resource.width;
2614 dst_h = dst_surface->resource.height;
2616 update_w = src_rect->right - src_rect->left;
2617 update_h = src_rect->bottom - src_rect->top;
2619 if (update_w > dst_w || dst_point->x > dst_w - update_w
2620 || update_h > dst_h || dst_point->y > dst_h - update_h)
2622 WARN("Destination out of bounds.\n");
2623 return WINED3DERR_INVALIDCALL;
2626 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
2628 WARN("Source rectangle not block-aligned.\n");
2629 return WINED3DERR_INVALIDCALL;
2632 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
2633 if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
2635 WARN("Destination rectangle not block-aligned.\n");
2636 return WINED3DERR_INVALIDCALL;
2639 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2640 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
2641 if (convert != WINED3D_CT_NONE || format.convert)
2642 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
2644 context = context_acquire(dst_surface->resource.device, NULL);
2645 gl_info = context->gl_info;
2647 /* Only load the surface for partial updates. For newly allocated texture
2648 * the texture wouldn't be the current location, and we'd upload zeroes
2649 * just to overwrite them again. */
2650 if (update_w == dst_w && update_h == dst_h)
2651 surface_prepare_texture(dst_surface, context, FALSE);
2653 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
2654 surface_bind(dst_surface, context, FALSE);
2656 data.buffer_object = src_surface->pbo;
2657 data.addr = src_surface->resource.allocatedMemory;
2658 src_pitch = wined3d_surface_get_pitch(src_surface);
2660 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
2662 invalidate_active_texture(dst_surface->resource.device, context);
2664 context_release(context);
2666 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2670 /* This call just allocates the texture, the caller is responsible for binding
2671 * the correct texture. */
2672 /* Context activation is done by the caller. */
2673 static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2674 const struct wined3d_format *format, BOOL srgb)
2676 BOOL enable_client_storage = FALSE;
2677 GLsizei width = surface->pow2Width;
2678 GLsizei height = surface->pow2Height;
2679 const BYTE *mem = NULL;
2684 internal = format->glGammaInternal;
2686 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2688 internal = format->rtInternal;
2692 internal = format->glInternal;
2696 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2698 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2700 height *= format->height_scale.numerator;
2701 height /= format->height_scale.denominator;
2704 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",
2705 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
2706 internal, width, height, format->glFormat, format->glType);
2710 if (gl_info->supported[APPLE_CLIENT_STORAGE])
2712 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2713 || !surface->resource.allocatedMemory)
2715 /* In some cases we want to disable client storage.
2716 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2717 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2718 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2719 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2721 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2722 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2723 surface->flags &= ~SFLAG_CLIENT;
2724 enable_client_storage = TRUE;
2728 surface->flags |= SFLAG_CLIENT;
2730 /* Point OpenGL to our allocated texture memory. Do not use
2731 * resource.allocatedMemory here because it might point into a
2732 * PBO. Instead use heapMemory, but get the alignment right. */
2733 mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2734 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2738 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
2740 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
2741 internal, width, height, 0, surface->resource.size, mem));
2742 checkGLcall("glCompressedTexImage2DARB");
2746 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
2747 internal, width, height, 0, format->glFormat, format->glType, mem);
2748 checkGLcall("glTexImage2D");
2751 if (enable_client_storage)
2753 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2754 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2759 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2760 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2761 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2762 /* GL locking is done by the caller */
2763 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
2765 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
2766 struct wined3d_renderbuffer_entry *entry;
2767 GLuint renderbuffer = 0;
2768 unsigned int src_width, src_height;
2769 unsigned int width, height;
2771 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
2773 width = rt->pow2Width;
2774 height = rt->pow2Height;
2778 width = surface->pow2Width;
2779 height = surface->pow2Height;
2782 src_width = surface->pow2Width;
2783 src_height = surface->pow2Height;
2785 /* A depth stencil smaller than the render target is not valid */
2786 if (width > src_width || height > src_height) return;
2788 /* Remove any renderbuffer set if the sizes match */
2789 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
2790 || (width == src_width && height == src_height))
2792 surface->current_renderbuffer = NULL;
2796 /* Look if we've already got a renderbuffer of the correct dimensions */
2797 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2799 if (entry->width == width && entry->height == height)
2801 renderbuffer = entry->id;
2802 surface->current_renderbuffer = entry;
2809 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
2810 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
2811 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
2812 surface->resource.format->glInternal, width, height);
2814 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
2815 entry->width = width;
2816 entry->height = height;
2817 entry->id = renderbuffer;
2818 list_add_head(&surface->renderbuffers, &entry->entry);
2820 surface->current_renderbuffer = entry;
2823 checkGLcall("set_compatible_renderbuffer");
2826 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
2828 const struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2830 TRACE("surface %p.\n", surface);
2832 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
2834 ERR("Surface %p is not on a swapchain.\n", surface);
2838 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
2840 if (swapchain->render_to_fbo)
2842 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2843 return GL_COLOR_ATTACHMENT0;
2845 TRACE("Returning GL_BACK\n");
2848 else if (surface == swapchain->front_buffer)
2850 TRACE("Returning GL_FRONT\n");
2854 FIXME("Higher back buffer, returning GL_BACK\n");
2858 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2859 void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
2861 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
2863 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
2864 /* No partial locking for textures yet. */
2865 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2867 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2870 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
2871 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
2872 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
2873 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
2877 surface->dirtyRect.left = 0;
2878 surface->dirtyRect.top = 0;
2879 surface->dirtyRect.right = surface->resource.width;
2880 surface->dirtyRect.bottom = surface->resource.height;
2883 /* if the container is a texture then mark it dirty. */
2884 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
2886 TRACE("Passing to container.\n");
2887 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
2891 HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
2893 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2896 TRACE("surface %p, srgb %#x.\n", surface, srgb);
2898 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
2900 ERR("Not supported on scratch surfaces.\n");
2901 return WINED3DERR_INVALIDCALL;
2904 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2906 /* Reload if either the texture and sysmem have different ideas about the
2907 * color key, or the actual key values changed. */
2908 if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
2909 && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
2910 || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
2912 TRACE("Reloading because of color keying\n");
2913 /* To perform the color key conversion we need a sysmem copy of
2914 * the surface. Make sure we have it. */
2916 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2917 /* Make sure the texture is reloaded because of the color key change,
2918 * this kills performance though :( */
2919 /* TODO: This is not necessarily needed with hw palettized texture support. */
2920 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2921 /* Switching color keying on / off may change the internal format. */
2923 surface_force_reload(surface);
2925 else if (!(surface->flags & flag))
2927 TRACE("Reloading because surface is dirty.\n");
2931 TRACE("surface is already in texture\n");
2935 /* No partial locking for textures yet. */
2936 surface_load_location(surface, flag, NULL);
2937 surface_evict_sysmem(surface);
2942 /* See also float_16_to_32() in wined3d_private.h */
2943 static inline unsigned short float_32_to_16(const float *in)
2946 float tmp = fabsf(*in);
2947 unsigned int mantissa;
2950 /* Deal with special numbers */
2956 return (*in < 0.0f ? 0xfc00 : 0x7c00);
2958 if (tmp < powf(2, 10))
2964 } while (tmp < powf(2, 10));
2966 else if (tmp >= powf(2, 11))
2972 } while (tmp >= powf(2, 11));
2975 mantissa = (unsigned int)tmp;
2976 if (tmp - mantissa >= 0.5f)
2977 ++mantissa; /* Round to nearest, away from zero. */
2979 exp += 10; /* Normalize the mantissa. */
2980 exp += 15; /* Exponent is encoded with excess 15. */
2982 if (exp > 30) /* too big */
2984 ret = 0x7c00; /* INF */
2988 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2991 mantissa = mantissa >> 1;
2994 ret = mantissa & 0x3ff;
2998 ret = (exp << 10) | (mantissa & 0x3ff);
3001 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
3005 ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
3009 TRACE("Surface %p, container %p of type %#x.\n",
3010 surface, surface->container.u.base, surface->container.type);
3012 switch (surface->container.type)
3014 case WINED3D_CONTAINER_TEXTURE:
3015 return wined3d_texture_incref(surface->container.u.texture);
3017 case WINED3D_CONTAINER_SWAPCHAIN:
3018 return wined3d_swapchain_incref(surface->container.u.swapchain);
3021 ERR("Unhandled container type %#x.\n", surface->container.type);
3022 case WINED3D_CONTAINER_NONE:
3026 refcount = InterlockedIncrement(&surface->resource.ref);
3027 TRACE("%p increasing refcount to %u.\n", surface, refcount);
3032 /* Do not call while under the GL lock. */
3033 ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
3037 TRACE("Surface %p, container %p of type %#x.\n",
3038 surface, surface->container.u.base, surface->container.type);
3040 switch (surface->container.type)
3042 case WINED3D_CONTAINER_TEXTURE:
3043 return wined3d_texture_decref(surface->container.u.texture);
3045 case WINED3D_CONTAINER_SWAPCHAIN:
3046 return wined3d_swapchain_decref(surface->container.u.swapchain);
3049 ERR("Unhandled container type %#x.\n", surface->container.type);
3050 case WINED3D_CONTAINER_NONE:
3054 refcount = InterlockedDecrement(&surface->resource.ref);
3055 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3059 surface_cleanup(surface);
3060 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3062 TRACE("Destroyed surface %p.\n", surface);
3063 HeapFree(GetProcessHeap(), 0, surface);
3069 DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
3071 return resource_set_priority(&surface->resource, priority);
3074 DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
3076 return resource_get_priority(&surface->resource);
3079 void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
3081 TRACE("surface %p.\n", surface);
3083 if (!surface->resource.device->d3d_initialized)
3085 ERR("D3D not initialized.\n");
3089 surface_internal_preload(surface, SRGB_ANY);
3092 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
3094 TRACE("surface %p.\n", surface);
3096 return surface->resource.parent;
3099 struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
3101 TRACE("surface %p.\n", surface);
3103 return &surface->resource;
3106 HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
3108 TRACE("surface %p, flags %#x.\n", surface, flags);
3112 case WINEDDGBS_CANBLT:
3113 case WINEDDGBS_ISBLTDONE:
3117 return WINED3DERR_INVALIDCALL;
3121 HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
3123 TRACE("surface %p, flags %#x.\n", surface, flags);
3125 /* XXX: DDERR_INVALIDSURFACETYPE */
3129 case WINEDDGFS_CANFLIP:
3130 case WINEDDGFS_ISFLIPDONE:
3134 return WINED3DERR_INVALIDCALL;
3138 HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
3140 TRACE("surface %p.\n", surface);
3142 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
3143 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3146 HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
3148 TRACE("surface %p.\n", surface);
3150 surface->flags &= ~SFLAG_LOST;
3154 void CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
3156 TRACE("surface %p, palette %p.\n", surface, palette);
3158 if (surface->palette == palette)
3160 TRACE("Nop palette change.\n");
3164 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
3165 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3167 surface->palette = palette;
3171 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3172 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
3174 surface->surface_ops->surface_realize_palette(surface);
3178 HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3179 DWORD flags, const struct wined3d_color_key *color_key)
3181 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3183 if (flags & WINEDDCKEY_COLORSPACE)
3185 FIXME(" colorkey value not supported (%08x) !\n", flags);
3186 return WINED3DERR_INVALIDCALL;
3189 /* Dirtify the surface, but only if a key was changed. */
3192 switch (flags & ~WINEDDCKEY_COLORSPACE)
3194 case WINEDDCKEY_DESTBLT:
3195 surface->dst_blt_color_key = *color_key;
3196 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3199 case WINEDDCKEY_DESTOVERLAY:
3200 surface->dst_overlay_color_key = *color_key;
3201 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3204 case WINEDDCKEY_SRCOVERLAY:
3205 surface->src_overlay_color_key = *color_key;
3206 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3209 case WINEDDCKEY_SRCBLT:
3210 surface->src_blt_color_key = *color_key;
3211 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3217 switch (flags & ~WINEDDCKEY_COLORSPACE)
3219 case WINEDDCKEY_DESTBLT:
3220 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3223 case WINEDDCKEY_DESTOVERLAY:
3224 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3227 case WINEDDCKEY_SRCOVERLAY:
3228 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3231 case WINEDDCKEY_SRCBLT:
3232 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3240 struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3242 TRACE("surface %p.\n", surface);
3244 return surface->palette;
3247 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3249 const struct wined3d_format *format = surface->resource.format;
3252 TRACE("surface %p.\n", surface);
3254 if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3256 /* Since compressed formats are block based, pitch means the amount of
3257 * bytes to the next row of block rather than the next row of pixels. */
3258 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3259 pitch = row_block_count * format->block_byte_count;
3263 unsigned char alignment = surface->resource.device->surface_alignment;
3264 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
3265 pitch = (pitch + alignment - 1) & ~(alignment - 1);
3268 TRACE("Returning %u.\n", pitch);
3273 HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem)
3275 TRACE("surface %p, mem %p.\n", surface, mem);
3277 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3279 WARN("Surface is mapped or the DC is in use.\n");
3280 return WINED3DERR_INVALIDCALL;
3283 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3284 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3286 ERR("Not supported on render targets.\n");
3287 return WINED3DERR_INVALIDCALL;
3290 if (mem && mem != surface->resource.allocatedMemory)
3292 void *release = NULL;
3294 /* Do I have to copy the old surface content? */
3295 if (surface->flags & SFLAG_DIBSECTION)
3297 DeleteDC(surface->hDC);
3298 DeleteObject(surface->dib.DIBsection);
3299 surface->dib.bitmap_data = NULL;
3300 surface->resource.allocatedMemory = NULL;
3301 surface->hDC = NULL;
3302 surface->flags &= ~SFLAG_DIBSECTION;
3304 else if (!(surface->flags & SFLAG_USERPTR))
3306 release = surface->resource.heapMemory;
3307 surface->resource.heapMemory = NULL;
3309 surface->resource.allocatedMemory = mem;
3310 surface->flags |= SFLAG_USERPTR;
3312 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3313 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3315 /* For client textures OpenGL has to be notified. */
3316 if (surface->flags & SFLAG_CLIENT)
3317 surface_release_client_storage(surface);
3319 /* Now free the old memory if any. */
3320 HeapFree(GetProcessHeap(), 0, release);
3322 else if (surface->flags & SFLAG_USERPTR)
3324 /* HeapMemory should be NULL already. */
3325 if (surface->resource.heapMemory)
3326 ERR("User pointer surface has heap memory allocated.\n");
3330 surface->resource.allocatedMemory = NULL;
3331 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3333 if (surface->flags & SFLAG_CLIENT)
3334 surface_release_client_storage(surface);
3336 surface_prepare_system_memory(surface);
3339 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3345 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3349 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3351 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3353 WARN("Not an overlay surface.\n");
3354 return WINEDDERR_NOTAOVERLAYSURFACE;
3357 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3358 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3359 surface->overlay_destrect.left = x;
3360 surface->overlay_destrect.top = y;
3361 surface->overlay_destrect.right = x + w;
3362 surface->overlay_destrect.bottom = y + h;
3364 surface_draw_overlay(surface);
3369 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3371 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3373 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3375 TRACE("Not an overlay surface.\n");
3376 return WINEDDERR_NOTAOVERLAYSURFACE;
3379 if (!surface->overlay_dest)
3381 TRACE("Overlay not visible.\n");
3384 return WINEDDERR_OVERLAYNOTVISIBLE;
3387 *x = surface->overlay_destrect.left;
3388 *y = surface->overlay_destrect.top;
3390 TRACE("Returning position %d, %d.\n", *x, *y);
3395 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3396 DWORD flags, struct wined3d_surface *ref)
3398 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3400 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3402 TRACE("Not an overlay surface.\n");
3403 return WINEDDERR_NOTAOVERLAYSURFACE;
3409 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3410 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3412 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3413 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3415 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3417 WARN("Not an overlay surface.\n");
3418 return WINEDDERR_NOTAOVERLAYSURFACE;
3420 else if (!dst_surface)
3422 WARN("Dest surface is NULL.\n");
3423 return WINED3DERR_INVALIDCALL;
3428 surface->overlay_srcrect = *src_rect;
3432 surface->overlay_srcrect.left = 0;
3433 surface->overlay_srcrect.top = 0;
3434 surface->overlay_srcrect.right = surface->resource.width;
3435 surface->overlay_srcrect.bottom = surface->resource.height;
3440 surface->overlay_destrect = *dst_rect;
3444 surface->overlay_destrect.left = 0;
3445 surface->overlay_destrect.top = 0;
3446 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3447 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3450 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3452 surface->overlay_dest = NULL;
3453 list_remove(&surface->overlay_entry);
3456 if (flags & WINEDDOVER_SHOW)
3458 if (surface->overlay_dest != dst_surface)
3460 surface->overlay_dest = dst_surface;
3461 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3464 else if (flags & WINEDDOVER_HIDE)
3466 /* tests show that the rectangles are erased on hide */
3467 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3468 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3469 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3470 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3471 surface->overlay_dest = NULL;
3474 surface_draw_overlay(surface);
3479 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3480 UINT width, UINT height, enum wined3d_format_id format_id,
3481 enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3483 struct wined3d_device *device = surface->resource.device;
3484 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3485 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3486 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3488 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3489 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3492 return WINED3DERR_INVALIDCALL;
3494 if (device->d3d_initialized)
3495 surface->resource.resource_ops->resource_unload(&surface->resource);
3497 if (surface->flags & SFLAG_DIBSECTION)
3499 DeleteDC(surface->hDC);
3500 DeleteObject(surface->dib.DIBsection);
3501 surface->dib.bitmap_data = NULL;
3502 surface->flags &= ~SFLAG_DIBSECTION;
3505 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3506 surface->resource.allocatedMemory = NULL;
3507 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3508 surface->resource.heapMemory = NULL;
3510 surface->resource.width = width;
3511 surface->resource.height = height;
3512 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3513 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3515 surface->pow2Width = width;
3516 surface->pow2Height = height;
3520 surface->pow2Width = surface->pow2Height = 1;
3521 while (surface->pow2Width < width)
3522 surface->pow2Width <<= 1;
3523 while (surface->pow2Height < height)
3524 surface->pow2Height <<= 1;
3527 if (surface->pow2Width != width || surface->pow2Height != height)
3528 surface->flags |= SFLAG_NONPOW2;
3530 surface->flags &= ~SFLAG_NONPOW2;
3532 surface->resource.format = format;
3533 surface->resource.multisample_type = multisample_type;
3534 surface->resource.multisample_quality = multisample_quality;
3535 surface->resource.size = resource_size;
3537 if (!surface_init_sysmem(surface))
3538 return E_OUTOFMEMORY;
3543 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3544 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3546 unsigned short *dst_s;
3550 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3552 for (y = 0; y < h; ++y)
3554 src_f = (const float *)(src + y * pitch_in);
3555 dst_s = (unsigned short *) (dst + y * pitch_out);
3556 for (x = 0; x < w; ++x)
3558 dst_s[x] = float_32_to_16(src_f + x);
3563 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3564 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3566 static const unsigned char convert_5to8[] =
3568 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3569 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3570 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3571 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3573 static const unsigned char convert_6to8[] =
3575 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3576 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3577 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3578 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3579 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3580 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3581 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3582 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3586 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3588 for (y = 0; y < h; ++y)
3590 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3591 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3592 for (x = 0; x < w; ++x)
3594 WORD pixel = src_line[x];
3595 dst_line[x] = 0xff000000
3596 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3597 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3598 | convert_5to8[(pixel & 0x001f)];
3603 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3604 * in both cases we're just setting the X / Alpha channel to 0xff. */
3605 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3606 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3610 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3612 for (y = 0; y < h; ++y)
3614 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3615 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3617 for (x = 0; x < w; ++x)
3619 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3624 static inline BYTE cliptobyte(int x)
3626 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3629 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3630 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3632 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3635 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3637 for (y = 0; y < h; ++y)
3639 const BYTE *src_line = src + y * pitch_in;
3640 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3641 for (x = 0; x < w; ++x)
3643 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3644 * C = Y - 16; D = U - 128; E = V - 128;
3645 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3646 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3647 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3648 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3649 * U and V are shared between the pixels. */
3650 if (!(x & 1)) /* For every even pixel, read new U and V. */
3652 d = (int) src_line[1] - 128;
3653 e = (int) src_line[3] - 128;
3655 g2 = - 100 * d - 208 * e + 128;
3658 c2 = 298 * ((int) src_line[0] - 16);
3659 dst_line[x] = 0xff000000
3660 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3661 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3662 | cliptobyte((c2 + b2) >> 8); /* blue */
3663 /* Scale RGB values to 0..255 range,
3664 * then clip them if still not in range (may be negative),
3665 * then shift them within DWORD if necessary. */
3671 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3672 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3675 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3677 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3679 for (y = 0; y < h; ++y)
3681 const BYTE *src_line = src + y * pitch_in;
3682 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3683 for (x = 0; x < w; ++x)
3685 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3686 * C = Y - 16; D = U - 128; E = V - 128;
3687 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3688 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3689 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3690 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3691 * U and V are shared between the pixels. */
3692 if (!(x & 1)) /* For every even pixel, read new U and V. */
3694 d = (int) src_line[1] - 128;
3695 e = (int) src_line[3] - 128;
3697 g2 = - 100 * d - 208 * e + 128;
3700 c2 = 298 * ((int) src_line[0] - 16);
3701 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3702 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3703 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3704 /* Scale RGB values to 0..255 range,
3705 * then clip them if still not in range (may be negative),
3706 * then shift them within DWORD if necessary. */
3712 struct d3dfmt_converter_desc
3714 enum wined3d_format_id from, to;
3715 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3718 static const struct d3dfmt_converter_desc converters[] =
3720 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3721 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3722 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3723 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3724 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3725 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3728 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
3729 enum wined3d_format_id to)
3733 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
3735 if (converters[i].from == from && converters[i].to == to)
3736 return &converters[i];
3742 /*****************************************************************************
3743 * surface_convert_format
3745 * Creates a duplicate of a surface in a different format. Is used by Blt to
3746 * blit between surfaces with different formats.
3749 * source: Source surface
3750 * fmt: Requested destination format
3752 *****************************************************************************/
3753 static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
3755 struct wined3d_map_desc src_map, dst_map;
3756 const struct d3dfmt_converter_desc *conv;
3757 struct wined3d_surface *ret = NULL;
3760 conv = find_converter(source->resource.format->id, to_fmt);
3763 FIXME("Cannot find a conversion function from format %s to %s.\n",
3764 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
3768 /* FIXME: Multisampled conversion? */
3769 if (FAILED(hr = wined3d_surface_create(source->resource.device, source->resource.width, source->resource.height,
3770 to_fmt, 0, WINED3D_POOL_SCRATCH, WINED3D_MULTISAMPLE_NONE, 0, source->surface_type,
3771 WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, NULL, &wined3d_null_parent_ops, &ret)))
3773 ERR("Failed to create a destination surface for conversion.\n");
3777 memset(&src_map, 0, sizeof(src_map));
3778 memset(&dst_map, 0, sizeof(dst_map));
3780 if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
3782 ERR("Failed to lock the source surface.\n");
3783 wined3d_surface_decref(ret);
3786 if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
3788 ERR("Failed to lock the destination surface.\n");
3789 wined3d_surface_unmap(source);
3790 wined3d_surface_decref(ret);
3794 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
3795 source->resource.width, source->resource.height);
3797 wined3d_surface_unmap(ret);
3798 wined3d_surface_unmap(source);
3803 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
3804 unsigned int bpp, UINT pitch, DWORD color)
3811 #define COLORFILL_ROW(type) \
3813 type *d = (type *)buf; \
3814 for (x = 0; x < width; ++x) \
3815 d[x] = (type)color; \
3821 COLORFILL_ROW(BYTE);
3825 COLORFILL_ROW(WORD);
3831 for (x = 0; x < width; ++x, d += 3)
3833 d[0] = (color ) & 0xff;
3834 d[1] = (color >> 8) & 0xff;
3835 d[2] = (color >> 16) & 0xff;
3840 COLORFILL_ROW(DWORD);
3844 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
3845 return WINED3DERR_NOTAVAILABLE;
3848 #undef COLORFILL_ROW
3850 /* Now copy first row. */
3852 for (y = 1; y < height; ++y)
3855 memcpy(buf, first, width * bpp);
3861 struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
3863 return surface_from_resource(resource);
3866 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
3868 TRACE("surface %p.\n", surface);
3870 if (!surface->resource.map_count)
3872 WARN("Trying to unmap unmapped surface.\n");
3873 return WINEDDERR_NOTLOCKED;
3875 --surface->resource.map_count;
3877 surface->surface_ops->surface_unmap(surface);
3882 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
3883 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
3885 const struct wined3d_format *format = surface->resource.format;
3887 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
3888 surface, map_desc, wine_dbgstr_rect(rect), flags);
3890 if (surface->resource.map_count)
3892 WARN("Surface is already mapped.\n");
3893 return WINED3DERR_INVALIDCALL;
3896 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
3897 && !surface_check_block_align(surface, rect))
3899 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
3900 wine_dbgstr_rect(rect), format->block_width, format->block_height);
3902 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
3903 return WINED3DERR_INVALIDCALL;
3906 ++surface->resource.map_count;
3908 if (!(surface->flags & SFLAG_LOCKABLE))
3909 WARN("Trying to lock unlockable surface.\n");
3911 /* Performance optimization: Count how often a surface is mapped, if it is
3912 * mapped regularly do not throw away the system memory copy. This avoids
3913 * the need to download the surface from OpenGL all the time. The surface
3914 * is still downloaded if the OpenGL texture is changed. */
3915 if (!(surface->flags & SFLAG_DYNLOCK))
3917 if (++surface->lockCount > MAXLOCKCOUNT)
3919 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3920 surface->flags |= SFLAG_DYNLOCK;
3924 surface->surface_ops->surface_map(surface, rect, flags);
3926 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
3927 map_desc->row_pitch = surface->resource.width * format->byte_count;
3929 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
3930 map_desc->slice_pitch = 0;
3934 map_desc->data = surface->resource.allocatedMemory;
3935 surface->lockedRect.left = 0;
3936 surface->lockedRect.top = 0;
3937 surface->lockedRect.right = surface->resource.width;
3938 surface->lockedRect.bottom = surface->resource.height;
3942 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
3944 /* Compressed textures are block based, so calculate the offset of
3945 * the block that contains the top-left pixel of the locked rectangle. */
3946 map_desc->data = surface->resource.allocatedMemory
3947 + ((rect->top / format->block_height) * map_desc->row_pitch)
3948 + ((rect->left / format->block_width) * format->block_byte_count);
3952 map_desc->data = surface->resource.allocatedMemory
3953 + (map_desc->row_pitch * rect->top)
3954 + (rect->left * format->byte_count);
3956 surface->lockedRect.left = rect->left;
3957 surface->lockedRect.top = rect->top;
3958 surface->lockedRect.right = rect->right;
3959 surface->lockedRect.bottom = rect->bottom;
3962 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3963 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
3968 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
3970 struct wined3d_map_desc map;
3973 TRACE("surface %p, dc %p.\n", surface, dc);
3975 if (surface->flags & SFLAG_USERPTR)
3977 ERR("Not supported on surfaces with application-provided memory.\n");
3978 return WINEDDERR_NODC;
3981 /* Give more detailed info for ddraw. */
3982 if (surface->flags & SFLAG_DCINUSE)
3983 return WINEDDERR_DCALREADYCREATED;
3985 /* Can't GetDC if the surface is locked. */
3986 if (surface->resource.map_count)
3987 return WINED3DERR_INVALIDCALL;
3989 /* Create a DIB section if there isn't a dc yet. */
3992 if (surface->flags & SFLAG_CLIENT)
3994 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3995 surface_release_client_storage(surface);
3997 hr = surface_create_dib_section(surface);
3999 return WINED3DERR_INVALIDCALL;
4001 /* Use the DIB section from now on if we are not using a PBO. */
4002 if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
4004 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
4005 surface->resource.heapMemory = NULL;
4006 surface->resource.allocatedMemory = surface->dib.bitmap_data;
4010 /* Map the surface. */
4011 hr = wined3d_surface_map(surface, &map, NULL, 0);
4014 ERR("Map failed, hr %#x.\n", hr);
4018 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4019 * activates the allocatedMemory. */
4020 if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4021 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4023 if (surface->resource.format->id == WINED3DFMT_P8_UINT
4024 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4026 /* GetDC on palettized formats is unsupported in D3D9, and the method
4027 * is missing in D3D8, so this should only be used for DX <=7
4028 * surfaces (with non-device palettes). */
4029 const PALETTEENTRY *pal = NULL;
4031 if (surface->palette)
4033 pal = surface->palette->palents;
4037 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4038 struct wined3d_surface *dds_primary = swapchain->front_buffer;
4040 if (dds_primary && dds_primary->palette)
4041 pal = dds_primary->palette->palents;
4049 for (i = 0; i < 256; ++i)
4051 col[i].rgbRed = pal[i].peRed;
4052 col[i].rgbGreen = pal[i].peGreen;
4053 col[i].rgbBlue = pal[i].peBlue;
4054 col[i].rgbReserved = 0;
4056 SetDIBColorTable(surface->hDC, 0, 256, col);
4060 surface->flags |= SFLAG_DCINUSE;
4063 TRACE("Returning dc %p.\n", *dc);
4068 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4070 TRACE("surface %p, dc %p.\n", surface, dc);
4072 if (!(surface->flags & SFLAG_DCINUSE))
4073 return WINEDDERR_NODC;
4075 if (surface->hDC != dc)
4077 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4079 return WINEDDERR_NODC;
4082 /* Copy the contents of the DIB over to the PBO. */
4083 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4084 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4086 /* We locked first, so unlock now. */
4087 wined3d_surface_unmap(surface);
4089 surface->flags &= ~SFLAG_DCINUSE;
4094 HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4096 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4102 FIXME("Ignoring flags %#x.\n", flags);
4104 WARN("Ignoring flags %#x.\n", flags);
4107 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
4109 ERR("Not supported on swapchain surfaces.\n");
4110 return WINEDDERR_NOTFLIPPABLE;
4113 /* Flipping is only supported on render targets and overlays. */
4114 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
4116 WARN("Tried to flip a non-render target, non-overlay surface.\n");
4117 return WINEDDERR_NOTFLIPPABLE;
4120 flip_surface(surface, override);
4122 /* Update overlays if they're visible. */
4123 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4124 return surface_draw_overlay(surface);
4129 /* Do not call while under the GL lock. */
4130 void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4132 struct wined3d_device *device = surface->resource.device;
4134 TRACE("iface %p, srgb %#x.\n", surface, srgb);
4136 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4138 struct wined3d_texture *texture = surface->container.u.texture;
4140 TRACE("Passing to container (%p).\n", texture);
4141 texture->texture_ops->texture_preload(texture, srgb);
4145 struct wined3d_context *context;
4147 TRACE("(%p) : About to load surface\n", surface);
4149 /* TODO: Use already acquired context when possible. */
4150 context = context_acquire(device, NULL);
4152 surface_load(surface, srgb == SRGB_SRGB);
4154 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4156 /* Tell opengl to try and keep this texture in video ram (well mostly) */
4160 context->gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &surface->texture_name, &tmp);
4164 context_release(context);
4168 /* Read the framebuffer back into the surface */
4169 static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4171 struct wined3d_device *device = surface->resource.device;
4172 const struct wined3d_gl_info *gl_info;
4173 struct wined3d_context *context;
4177 BYTE *row, *top, *bottom;
4181 BOOL srcIsUpsideDown;
4186 context = context_acquire(device, surface);
4187 context_apply_blit_state(context, device);
4188 gl_info = context->gl_info;
4192 /* Select the correct read buffer, and give some debug output.
4193 * There is no need to keep track of the current read buffer or reset it, every part of the code
4194 * that reads sets the read buffer as desired.
4196 if (surface_is_offscreen(surface))
4198 /* Mapping the primary render target which is not on a swapchain.
4199 * Read from the back buffer. */
4200 TRACE("Mapping offscreen render target.\n");
4201 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4202 srcIsUpsideDown = TRUE;
4206 /* Onscreen surfaces are always part of a swapchain */
4207 GLenum buffer = surface_get_gl_buffer(surface);
4208 TRACE("Mapping %#x buffer.\n", buffer);
4209 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
4210 checkGLcall("glReadBuffer");
4211 srcIsUpsideDown = FALSE;
4214 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4217 local_rect.left = 0;
4219 local_rect.right = surface->resource.width;
4220 local_rect.bottom = surface->resource.height;
4226 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4228 switch (surface->resource.format->id)
4230 case WINED3DFMT_P8_UINT:
4232 if (primary_render_target_is_p8(device))
4234 /* In case of P8 render targets the index is stored in the alpha component */
4236 type = GL_UNSIGNED_BYTE;
4238 bpp = surface->resource.format->byte_count;
4242 /* GL can't return palettized data, so read ARGB pixels into a
4243 * separate block of memory and convert them into palettized format
4244 * in software. Slow, but if the app means to use palettized render
4245 * targets and locks it...
4247 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4248 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4249 * for the color channels when palettizing the colors.
4252 type = GL_UNSIGNED_BYTE;
4254 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4257 ERR("Out of memory\n");
4261 bpp = surface->resource.format->byte_count * 3;
4268 fmt = surface->resource.format->glFormat;
4269 type = surface->resource.format->glType;
4270 bpp = surface->resource.format->byte_count;
4273 if (surface->flags & SFLAG_PBO)
4275 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4276 checkGLcall("glBindBufferARB");
4279 ERR("mem not null for pbo -- unexpected\n");
4284 /* Save old pixel store pack state */
4285 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4286 checkGLcall("glGetIntegerv");
4287 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4288 checkGLcall("glGetIntegerv");
4289 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4290 checkGLcall("glGetIntegerv");
4292 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4293 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4294 checkGLcall("glPixelStorei");
4295 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4296 checkGLcall("glPixelStorei");
4297 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4298 checkGLcall("glPixelStorei");
4300 gl_info->gl_ops.gl.p_glReadPixels(local_rect.left,
4301 !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4302 local_rect.right - local_rect.left,
4303 local_rect.bottom - local_rect.top,
4305 checkGLcall("glReadPixels");
4307 /* Reset previous pixel store pack state */
4308 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4309 checkGLcall("glPixelStorei");
4310 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4311 checkGLcall("glPixelStorei");
4312 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4313 checkGLcall("glPixelStorei");
4315 if (surface->flags & SFLAG_PBO)
4317 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4318 checkGLcall("glBindBufferARB");
4320 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4321 * to get a pointer to it and perform the flipping in software. This is a lot
4322 * faster than calling glReadPixels for each line. In case we want more speed
4323 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4324 if (!srcIsUpsideDown)
4326 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4327 checkGLcall("glBindBufferARB");
4329 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4330 checkGLcall("glMapBufferARB");
4334 /* TODO: Merge this with the palettization loop below for P8 targets */
4335 if(!srcIsUpsideDown) {
4337 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4338 Flip the lines in software */
4339 len = (local_rect.right - local_rect.left) * bpp;
4340 off = local_rect.left * bpp;
4342 row = HeapAlloc(GetProcessHeap(), 0, len);
4344 ERR("Out of memory\n");
4345 if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4346 HeapFree(GetProcessHeap(), 0, mem);
4351 top = mem + pitch * local_rect.top;
4352 bottom = mem + pitch * (local_rect.bottom - 1);
4353 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4354 memcpy(row, top + off, len);
4355 memcpy(top + off, bottom + off, len);
4356 memcpy(bottom + off, row, len);
4360 HeapFree(GetProcessHeap(), 0, row);
4362 /* Unmap the temp PBO buffer */
4363 if (surface->flags & SFLAG_PBO)
4365 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4366 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4371 context_release(context);
4373 /* For P8 textures we need to perform an inverse palette lookup. This is
4374 * done by searching for a palette index which matches the RGB value.
4375 * Note this isn't guaranteed to work when there are multiple entries for
4376 * the same color but we have no choice. In case of P8 render targets,
4377 * the index is stored in the alpha component so no conversion is needed. */
4378 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4380 const PALETTEENTRY *pal = NULL;
4381 DWORD width = pitch / 3;
4384 if (surface->palette)
4386 pal = surface->palette->palents;
4390 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4391 HeapFree(GetProcessHeap(), 0, mem);
4395 for(y = local_rect.top; y < local_rect.bottom; y++) {
4396 for(x = local_rect.left; x < local_rect.right; x++) {
4397 /* start lines pixels */
4398 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4399 const BYTE *green = blue + 1;
4400 const BYTE *red = green + 1;
4402 for(c = 0; c < 256; c++) {
4403 if(*red == pal[c].peRed &&
4404 *green == pal[c].peGreen &&
4405 *blue == pal[c].peBlue)
4407 *((BYTE *) dest + y * width + x) = c;
4413 HeapFree(GetProcessHeap(), 0, mem);
4417 /* Read the framebuffer contents into a texture. Note that this function
4418 * doesn't do any kind of flipping. Using this on an onscreen surface will
4419 * result in a flipped D3D texture. */
4420 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4422 struct wined3d_device *device = surface->resource.device;
4423 const struct wined3d_gl_info *gl_info;
4424 struct wined3d_context *context;
4426 context = context_acquire(device, surface);
4427 gl_info = context->gl_info;
4428 device_invalidate_state(device, STATE_FRAMEBUFFER);
4430 surface_prepare_texture(surface, context, srgb);
4431 surface_bind_and_dirtify(surface, context, srgb);
4433 TRACE("Reading back offscreen render target %p.\n", surface);
4437 if (surface_is_offscreen(surface))
4438 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4440 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
4441 checkGLcall("glReadBuffer");
4443 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4444 0, 0, 0, 0, surface->resource.width, surface->resource.height);
4445 checkGLcall("glCopyTexSubImage2D");
4449 context_release(context);
4452 /* Context activation is done by the caller. */
4453 static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4454 struct wined3d_context *context, BOOL srgb)
4456 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4457 enum wined3d_conversion_type convert;
4458 struct wined3d_format format;
4460 if (surface->flags & alloc_flag) return;
4462 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4463 if (convert != WINED3D_CT_NONE || format.convert)
4464 surface->flags |= SFLAG_CONVERTED;
4465 else surface->flags &= ~SFLAG_CONVERTED;
4467 surface_bind_and_dirtify(surface, context, srgb);
4468 surface_allocate_surface(surface, context->gl_info, &format, srgb);
4469 surface->flags |= alloc_flag;
4472 /* Context activation is done by the caller. */
4473 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4475 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4477 struct wined3d_texture *texture = surface->container.u.texture;
4478 UINT sub_count = texture->level_count * texture->layer_count;
4481 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4483 for (i = 0; i < sub_count; ++i)
4485 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4486 surface_prepare_texture_internal(s, context, srgb);
4492 surface_prepare_texture_internal(surface, context, srgb);
4495 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4499 if (surface->rb_multisample)
4502 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4503 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4504 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4505 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4506 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4510 if (surface->rb_resolved)
4513 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4514 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4515 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4516 surface->pow2Width, surface->pow2Height);
4517 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4521 static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4522 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4524 struct wined3d_device *device = surface->resource.device;
4525 UINT pitch = wined3d_surface_get_pitch(surface);
4526 const struct wined3d_gl_info *gl_info;
4527 struct wined3d_context *context;
4531 surface_get_rect(surface, rect, &local_rect);
4533 mem += local_rect.top * pitch + local_rect.left * bpp;
4534 w = local_rect.right - local_rect.left;
4535 h = local_rect.bottom - local_rect.top;
4537 /* Activate the correct context for the render target */
4538 context = context_acquire(device, surface);
4539 context_apply_blit_state(context, device);
4540 gl_info = context->gl_info;
4544 if (!surface_is_offscreen(surface))
4546 GLenum buffer = surface_get_gl_buffer(surface);
4547 TRACE("Unlocking %#x buffer.\n", buffer);
4548 context_set_draw_buffer(context, buffer);
4550 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4551 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, -1.0f);
4555 /* Primary offscreen render target */
4556 TRACE("Offscreen render target.\n");
4557 context_set_draw_buffer(context, device->offscreenBuffer);
4559 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, 1.0f);
4562 gl_info->gl_ops.gl.p_glRasterPos3i(local_rect.left, local_rect.top, 1);
4563 checkGLcall("glRasterPos3i");
4565 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4566 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4568 if (surface->flags & SFLAG_PBO)
4570 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4571 checkGLcall("glBindBufferARB");
4574 gl_info->gl_ops.gl.p_glDrawPixels(w, h, fmt, type, mem);
4575 checkGLcall("glDrawPixels");
4577 if (surface->flags & SFLAG_PBO)
4579 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4580 checkGLcall("glBindBufferARB");
4583 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4584 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4588 if (wined3d_settings.strict_draw_ordering
4589 || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4590 && surface->container.u.swapchain->front_buffer == surface))
4591 gl_info->gl_ops.gl.p_glFlush();
4593 context_release(context);
4596 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4598 /* FIXME: Is this really how color keys are supposed to work? I think it
4599 * makes more sense to compare the individual channels. */
4600 return color >= color_key->color_space_low_value
4601 && color <= color_key->color_space_high_value;
4604 void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4606 const struct wined3d_device *device = surface->resource.device;
4607 const struct wined3d_palette *pal = surface->palette;
4608 BOOL index_in_alpha = FALSE;
4611 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4612 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4613 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4614 * duplicate entries. Store the color key in the unused alpha component to speed the
4615 * download up and to make conversion unneeded. */
4616 index_in_alpha = primary_render_target_is_p8(device);
4620 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4623 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4624 * there's no palette at this time. */
4625 for (i = 0; i < 256; i++) table[i][3] = i;
4630 TRACE("Using surface palette %p\n", pal);
4631 /* Get the surface's palette */
4632 for (i = 0; i < 256; ++i)
4634 table[i][0] = pal->palents[i].peRed;
4635 table[i][1] = pal->palents[i].peGreen;
4636 table[i][2] = pal->palents[i].peBlue;
4638 /* When index_in_alpha is set the palette index is stored in the
4639 * alpha component. In case of a readback we can then read
4640 * GL_ALPHA. Color keying is handled in BltOverride using a
4641 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4642 * color key itself is passed to glAlphaFunc in other cases the
4643 * alpha component of pixels that should be masked away is set to 0. */
4646 else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4648 else if (pal->flags & WINEDDPCAPS_ALPHA)
4649 table[i][3] = pal->palents[i].peFlags;
4656 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4657 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4662 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4663 src, dst, pitch, width, height, outpitch, conversion_type, surface);
4665 switch (conversion_type)
4667 case WINED3D_CT_NONE:
4669 memcpy(dst, src, pitch * height);
4673 case WINED3D_CT_PALETTED:
4674 case WINED3D_CT_PALETTED_CK:
4679 d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4681 for (y = 0; y < height; y++)
4683 source = src + pitch * y;
4684 dest = dst + outpitch * y;
4685 /* This is an 1 bpp format, using the width here is fine */
4686 for (x = 0; x < width; x++) {
4687 BYTE color = *source++;
4688 *dest++ = table[color][0];
4689 *dest++ = table[color][1];
4690 *dest++ = table[color][2];
4691 *dest++ = table[color][3];
4697 case WINED3D_CT_CK_565:
4699 /* Converting the 565 format in 5551 packed to emulate color-keying.
4701 Note : in all these conversion, it would be best to average the averaging
4702 pixels to get the color of the pixel that will be color-keyed to
4703 prevent 'color bleeding'. This will be done later on if ever it is
4706 Note2: Nvidia documents say that their driver does not support alpha + color keying
4707 on the same surface and disables color keying in such a case
4713 TRACE("Color keyed 565\n");
4715 for (y = 0; y < height; y++) {
4716 Source = (const WORD *)(src + y * pitch);
4717 Dest = (WORD *) (dst + y * outpitch);
4718 for (x = 0; x < width; x++ ) {
4719 WORD color = *Source++;
4720 *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
4721 if (!color_in_range(&surface->src_blt_color_key, color))
4729 case WINED3D_CT_CK_5551:
4731 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4735 TRACE("Color keyed 5551\n");
4736 for (y = 0; y < height; y++) {
4737 Source = (const WORD *)(src + y * pitch);
4738 Dest = (WORD *) (dst + y * outpitch);
4739 for (x = 0; x < width; x++ ) {
4740 WORD color = *Source++;
4742 if (!color_in_range(&surface->src_blt_color_key, color))
4745 *Dest &= ~(1 << 15);
4752 case WINED3D_CT_CK_RGB24:
4754 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4756 for (y = 0; y < height; y++)
4758 source = src + pitch * y;
4759 dest = dst + outpitch * y;
4760 for (x = 0; x < width; x++) {
4761 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4762 DWORD dstcolor = color << 8;
4763 if (!color_in_range(&surface->src_blt_color_key, color))
4765 *(DWORD*)dest = dstcolor;
4773 case WINED3D_CT_RGB32_888:
4775 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4777 for (y = 0; y < height; y++)
4779 source = src + pitch * y;
4780 dest = dst + outpitch * y;
4781 for (x = 0; x < width; x++) {
4782 DWORD color = 0xffffff & *(const DWORD*)source;
4783 DWORD dstcolor = color << 8;
4784 if (!color_in_range(&surface->src_blt_color_key, color))
4786 *(DWORD*)dest = dstcolor;
4794 case WINED3D_CT_CK_ARGB32:
4797 for (y = 0; y < height; ++y)
4799 source = src + pitch * y;
4800 dest = dst + outpitch * y;
4801 for (x = 0; x < width; ++x)
4803 DWORD color = *(const DWORD *)source;
4804 if (color_in_range(&surface->src_blt_color_key, color))
4805 color &= ~0xff000000;
4806 *(DWORD*)dest = color;
4815 ERR("Unsupported conversion type %#x.\n", conversion_type);
4820 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
4822 /* Flip the surface contents */
4827 front->hDC = back->hDC;
4831 /* Flip the DIBsection */
4833 HBITMAP tmp = front->dib.DIBsection;
4834 front->dib.DIBsection = back->dib.DIBsection;
4835 back->dib.DIBsection = tmp;
4838 /* Flip the surface data */
4842 tmp = front->dib.bitmap_data;
4843 front->dib.bitmap_data = back->dib.bitmap_data;
4844 back->dib.bitmap_data = tmp;
4846 tmp = front->resource.allocatedMemory;
4847 front->resource.allocatedMemory = back->resource.allocatedMemory;
4848 back->resource.allocatedMemory = tmp;
4850 tmp = front->resource.heapMemory;
4851 front->resource.heapMemory = back->resource.heapMemory;
4852 back->resource.heapMemory = tmp;
4857 GLuint tmp_pbo = front->pbo;
4858 front->pbo = back->pbo;
4859 back->pbo = tmp_pbo;
4862 /* Flip the opengl texture */
4866 tmp = back->texture_name;
4867 back->texture_name = front->texture_name;
4868 front->texture_name = tmp;
4870 tmp = back->texture_name_srgb;
4871 back->texture_name_srgb = front->texture_name_srgb;
4872 front->texture_name_srgb = tmp;
4874 tmp = back->rb_multisample;
4875 back->rb_multisample = front->rb_multisample;
4876 front->rb_multisample = tmp;
4878 tmp = back->rb_resolved;
4879 back->rb_resolved = front->rb_resolved;
4880 front->rb_resolved = tmp;
4882 resource_unload(&back->resource);
4883 resource_unload(&front->resource);
4887 DWORD tmp_flags = back->flags;
4888 back->flags = front->flags;
4889 front->flags = tmp_flags;
4893 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4894 * pixel copy calls. */
4895 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
4896 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
4898 struct wined3d_device *device = dst_surface->resource.device;
4899 const struct wined3d_gl_info *gl_info;
4902 struct wined3d_context *context;
4903 BOOL upsidedown = FALSE;
4904 RECT dst_rect = *dst_rect_in;
4907 if (dst_surface->container.type == WINED3D_CONTAINER_TEXTURE)
4908 dst_target = dst_surface->container.u.texture->target;
4910 dst_target = dst_surface->texture_target;
4912 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4913 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4915 if(dst_rect.top > dst_rect.bottom) {
4916 UINT tmp = dst_rect.bottom;
4917 dst_rect.bottom = dst_rect.top;
4922 context = context_acquire(device, src_surface);
4923 gl_info = context->gl_info;
4924 context_apply_blit_state(context, device);
4925 surface_internal_preload(dst_surface, SRGB_RGB);
4928 /* Bind the target texture */
4929 context_bind_texture(context, dst_target, dst_surface->texture_name);
4930 if (surface_is_offscreen(src_surface))
4932 TRACE("Reading from an offscreen target\n");
4933 upsidedown = !upsidedown;
4934 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4938 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
4940 checkGLcall("glReadBuffer");
4942 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
4943 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
4945 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4947 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4949 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4950 ERR("Texture filtering not supported in direct blit.\n");
4952 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4953 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4955 ERR("Texture filtering not supported in direct blit\n");
4959 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4960 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4962 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
4963 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4964 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
4965 src_rect->left, src_surface->resource.height - src_rect->bottom,
4966 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4970 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
4971 /* I have to process this row by row to swap the image,
4972 * otherwise it would be upside down, so stretching in y direction
4973 * doesn't cost extra time
4975 * However, stretching in x direction can be avoided if not necessary
4977 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
4978 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4980 /* Well, that stuff works, but it's very slow.
4981 * find a better way instead
4985 for (col = dst_rect.left; col < dst_rect.right; ++col)
4987 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4988 dst_rect.left + col /* x offset */, row /* y offset */,
4989 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
4994 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4995 dst_rect.left /* x offset */, row /* y offset */,
4996 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
5000 checkGLcall("glCopyTexSubImage2D");
5003 context_release(context);
5005 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5006 * path is never entered
5008 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5011 /* Uses the hardware to stretch and flip the image */
5012 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5013 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5015 struct wined3d_device *device = dst_surface->resource.device;
5016 struct wined3d_swapchain *src_swapchain = NULL;
5017 GLuint src, backup = 0;
5018 float left, right, top, bottom; /* Texture coordinates */
5019 UINT fbwidth = src_surface->resource.width;
5020 UINT fbheight = src_surface->resource.height;
5021 const struct wined3d_gl_info *gl_info;
5022 struct wined3d_context *context;
5023 GLenum drawBuffer = GL_BACK;
5024 GLenum texture_target;
5025 BOOL noBackBufferBackup;
5027 BOOL upsidedown = FALSE;
5028 RECT dst_rect = *dst_rect_in;
5030 TRACE("Using hwstretch blit\n");
5031 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5032 context = context_acquire(device, src_surface);
5033 gl_info = context->gl_info;
5034 context_apply_blit_state(context, device);
5035 surface_internal_preload(dst_surface, SRGB_RGB);
5037 src_offscreen = surface_is_offscreen(src_surface);
5038 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5039 if (!noBackBufferBackup && !src_surface->texture_name)
5041 /* Get it a description */
5042 surface_internal_preload(src_surface, SRGB_RGB);
5046 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5047 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5049 if (context->aux_buffers >= 2)
5051 /* Got more than one aux buffer? Use the 2nd aux buffer */
5052 drawBuffer = GL_AUX1;
5054 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5056 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5057 drawBuffer = GL_AUX0;
5060 if (noBackBufferBackup)
5062 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
5063 checkGLcall("glGenTextures");
5064 context_bind_texture(context, GL_TEXTURE_2D, backup);
5065 texture_target = GL_TEXTURE_2D;
5069 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5070 * we are reading from the back buffer, the backup can be used as source texture
5072 texture_target = src_surface->texture_target;
5073 context_bind_texture(context, texture_target, src_surface->texture_name);
5074 gl_info->gl_ops.gl.p_glEnable(texture_target);
5075 checkGLcall("glEnable(texture_target)");
5077 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5078 src_surface->flags &= ~SFLAG_INTEXTURE;
5081 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5082 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5084 if(dst_rect.top > dst_rect.bottom) {
5085 UINT tmp = dst_rect.bottom;
5086 dst_rect.bottom = dst_rect.top;
5093 TRACE("Reading from an offscreen target\n");
5094 upsidedown = !upsidedown;
5095 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5099 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5102 /* TODO: Only back up the part that will be overwritten */
5103 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
5105 checkGLcall("glCopyTexSubImage2D");
5107 /* No issue with overriding these - the sampler is dirty due to blit usage */
5108 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5109 wined3d_gl_mag_filter(magLookup, filter));
5110 checkGLcall("glTexParameteri");
5111 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5112 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5113 checkGLcall("glTexParameteri");
5115 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5116 src_swapchain = src_surface->container.u.swapchain;
5117 if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
5119 src = backup ? backup : src_surface->texture_name;
5123 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
5124 checkGLcall("glReadBuffer(GL_FRONT)");
5126 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
5127 checkGLcall("glGenTextures(1, &src)");
5128 context_bind_texture(context, GL_TEXTURE_2D, src);
5130 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5131 * out for power of 2 sizes
5133 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5134 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5135 checkGLcall("glTexImage2D");
5136 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
5138 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5139 checkGLcall("glTexParameteri");
5140 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5141 checkGLcall("glTexParameteri");
5143 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
5144 checkGLcall("glReadBuffer(GL_BACK)");
5146 if (texture_target != GL_TEXTURE_2D)
5148 gl_info->gl_ops.gl.p_glDisable(texture_target);
5149 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5150 texture_target = GL_TEXTURE_2D;
5153 checkGLcall("glEnd and previous");
5155 left = src_rect->left;
5156 right = src_rect->right;
5160 top = src_surface->resource.height - src_rect->top;
5161 bottom = src_surface->resource.height - src_rect->bottom;
5165 top = src_surface->resource.height - src_rect->bottom;
5166 bottom = src_surface->resource.height - src_rect->top;
5169 if (src_surface->flags & SFLAG_NORMCOORD)
5171 left /= src_surface->pow2Width;
5172 right /= src_surface->pow2Width;
5173 top /= src_surface->pow2Height;
5174 bottom /= src_surface->pow2Height;
5177 /* draw the source texture stretched and upside down. The correct surface is bound already */
5178 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5179 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5181 context_set_draw_buffer(context, drawBuffer);
5182 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
5184 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5186 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
5187 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5190 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
5191 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
5194 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
5195 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5198 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
5199 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
5200 gl_info->gl_ops.gl.p_glEnd();
5201 checkGLcall("glEnd and previous");
5203 if (texture_target != dst_surface->texture_target)
5205 gl_info->gl_ops.gl.p_glDisable(texture_target);
5206 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
5207 texture_target = dst_surface->texture_target;
5210 /* Now read the stretched and upside down image into the destination texture */
5211 context_bind_texture(context, texture_target, dst_surface->texture_name);
5212 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
5214 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5215 0, 0, /* We blitted the image to the origin */
5216 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5217 checkGLcall("glCopyTexSubImage2D");
5219 if (drawBuffer == GL_BACK)
5221 /* Write the back buffer backup back. */
5224 if (texture_target != GL_TEXTURE_2D)
5226 gl_info->gl_ops.gl.p_glDisable(texture_target);
5227 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5228 texture_target = GL_TEXTURE_2D;
5230 context_bind_texture(context, GL_TEXTURE_2D, backup);
5234 if (texture_target != src_surface->texture_target)
5236 gl_info->gl_ops.gl.p_glDisable(texture_target);
5237 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
5238 texture_target = src_surface->texture_target;
5240 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5243 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5245 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
5246 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
5249 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5250 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5253 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5254 (float)fbheight / (float)src_surface->pow2Height);
5255 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
5258 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5259 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
5260 gl_info->gl_ops.gl.p_glEnd();
5262 gl_info->gl_ops.gl.p_glDisable(texture_target);
5263 checkGLcall("glDisable(texture_target)");
5266 if (src != src_surface->texture_name && src != backup)
5268 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
5269 checkGLcall("glDeleteTextures(1, &src)");
5273 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
5274 checkGLcall("glDeleteTextures(1, &backup)");
5279 if (wined3d_settings.strict_draw_ordering)
5280 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5282 context_release(context);
5284 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5285 * path is never entered
5287 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5290 /* Front buffer coordinates are always full screen coordinates, but our GL
5291 * drawable is limited to the window's client area. The sysmem and texture
5292 * copies do have the full screen size. Note that GL has a bottom-left
5293 * origin, while D3D has a top-left origin. */
5294 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5296 UINT drawable_height;
5298 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5299 && surface == surface->container.u.swapchain->front_buffer)
5301 POINT offset = {0, 0};
5304 ScreenToClient(window, &offset);
5305 OffsetRect(rect, offset.x, offset.y);
5307 GetClientRect(window, &windowsize);
5308 drawable_height = windowsize.bottom - windowsize.top;
5312 drawable_height = surface->resource.height;
5315 rect->top = drawable_height - rect->top;
5316 rect->bottom = drawable_height - rect->bottom;
5319 static void surface_blt_to_drawable(const struct wined3d_device *device,
5320 enum wined3d_texture_filter_type filter, BOOL color_key,
5321 struct wined3d_surface *src_surface, const RECT *src_rect_in,
5322 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5324 const struct wined3d_gl_info *gl_info;
5325 struct wined3d_context *context;
5326 RECT src_rect, dst_rect;
5328 src_rect = *src_rect_in;
5329 dst_rect = *dst_rect_in;
5331 /* Make sure the surface is up-to-date. This should probably use
5332 * surface_load_location() and worry about the destination surface too,
5333 * unless we're overwriting it completely. */
5334 surface_internal_preload(src_surface, SRGB_RGB);
5336 /* Activate the destination context, set it up for blitting */
5337 context = context_acquire(device, dst_surface);
5338 gl_info = context->gl_info;
5339 context_apply_blit_state(context, device);
5341 if (!surface_is_offscreen(dst_surface))
5342 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5344 device->blitter->set_shader(device->blit_priv, context, src_surface);
5350 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
5351 checkGLcall("glEnable(GL_ALPHA_TEST)");
5353 /* When the primary render target uses P8, the alpha component
5354 * contains the palette index. Which means that the colorkey is one of
5355 * the palette entries. In other cases pixels that should be masked
5356 * away have alpha set to 0. */
5357 if (primary_render_target_is_p8(device))
5358 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
5359 (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5361 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
5362 checkGLcall("glAlphaFunc");
5366 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5367 checkGLcall("glDisable(GL_ALPHA_TEST)");
5370 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5374 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5375 checkGLcall("glDisable(GL_ALPHA_TEST)");
5380 /* Leave the opengl state valid for blitting */
5381 device->blitter->unset_shader(context->gl_info);
5383 if (wined3d_settings.strict_draw_ordering
5384 || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5385 && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5386 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5388 context_release(context);
5391 /* Do not call while under the GL lock. */
5392 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5394 struct wined3d_device *device = s->resource.device;
5395 const struct blit_shader *blitter;
5397 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5398 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5401 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5402 return WINED3DERR_INVALIDCALL;
5405 return blitter->color_fill(device, s, rect, color);
5408 /* Do not call while under the GL lock. */
5409 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5410 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5411 enum wined3d_texture_filter_type filter)
5413 struct wined3d_device *device = dst_surface->resource.device;
5414 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5415 struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5417 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5418 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5419 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5421 /* Get the swapchain. One of the surfaces has to be a primary surface */
5422 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5424 WARN("Destination is in sysmem, rejecting gl blt\n");
5425 return WINED3DERR_INVALIDCALL;
5428 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5429 dstSwapchain = dst_surface->container.u.swapchain;
5433 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5435 WARN("Src is in sysmem, rejecting gl blt\n");
5436 return WINED3DERR_INVALIDCALL;
5439 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5440 srcSwapchain = src_surface->container.u.swapchain;
5443 /* Early sort out of cases where no render target is used */
5444 if (!dstSwapchain && !srcSwapchain
5445 && src_surface != device->fb.render_targets[0]
5446 && dst_surface != device->fb.render_targets[0])
5448 TRACE("No surface is render target, not using hardware blit.\n");
5449 return WINED3DERR_INVALIDCALL;
5452 /* No destination color keying supported */
5453 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5455 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5456 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5457 return WINED3DERR_INVALIDCALL;
5460 if (dstSwapchain && dstSwapchain == srcSwapchain)
5462 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5463 return WINED3DERR_INVALIDCALL;
5466 if (dstSwapchain && srcSwapchain)
5468 FIXME("Implement hardware blit between two different swapchains\n");
5469 return WINED3DERR_INVALIDCALL;
5474 /* Handled with regular texture -> swapchain blit */
5475 if (src_surface == device->fb.render_targets[0])
5476 TRACE("Blit from active render target to a swapchain\n");
5478 else if (srcSwapchain && dst_surface == device->fb.render_targets[0])
5480 FIXME("Implement blit from a swapchain to the active render target\n");
5481 return WINED3DERR_INVALIDCALL;
5484 if ((srcSwapchain || src_surface == device->fb.render_targets[0]) && !dstSwapchain)
5486 /* Blit from render target to texture */
5489 /* P8 read back is not implemented */
5490 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5491 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5493 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5494 return WINED3DERR_INVALIDCALL;
5497 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5499 TRACE("Color keying not supported by frame buffer to texture blit\n");
5500 return WINED3DERR_INVALIDCALL;
5501 /* Destination color key is checked above */
5504 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5509 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5510 * flip the image nor scale it.
5512 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5513 * -> If the app wants a image width an unscaled width, copy it line per line
5514 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5515 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5516 * back buffer. This is slower than reading line per line, thus not used for flipping
5517 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5518 * pixel by pixel. */
5519 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5520 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5522 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5523 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5527 TRACE("Using hardware stretching to flip / stretch the texture.\n");
5528 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5531 if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5533 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5534 dst_surface->resource.allocatedMemory = NULL;
5535 dst_surface->resource.heapMemory = NULL;
5539 dst_surface->flags &= ~SFLAG_INSYSMEM;
5544 else if (src_surface)
5546 /* Blit from offscreen surface to render target */
5547 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5548 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5550 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5552 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5553 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5554 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5556 FIXME("Unsupported blit operation falling back to software\n");
5557 return WINED3DERR_INVALIDCALL;
5560 /* Color keying: Check if we have to do a color keyed blt,
5561 * and if not check if a color key is activated.
5563 * Just modify the color keying parameters in the surface and restore them afterwards
5564 * The surface keeps track of the color key last used to load the opengl surface.
5565 * PreLoad will catch the change to the flags and color key and reload if necessary.
5567 if (flags & WINEDDBLT_KEYSRC)
5569 /* Use color key from surface */
5571 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5573 /* Use color key from DDBltFx */
5574 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5575 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5579 /* Do not use color key */
5580 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5583 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5584 src_surface, src_rect, dst_surface, dst_rect);
5586 /* Restore the color key parameters */
5587 src_surface->CKeyFlags = oldCKeyFlags;
5588 src_surface->src_blt_color_key = old_blt_key;
5590 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5595 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5596 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5597 return WINED3DERR_INVALIDCALL;
5600 /* GL locking is done by the caller */
5601 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5602 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5604 struct wined3d_device *device = surface->resource.device;
5605 const struct wined3d_gl_info *gl_info = context->gl_info;
5606 GLint compare_mode = GL_NONE;
5607 struct blt_info info;
5608 GLint old_binding = 0;
5611 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5613 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
5614 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
5615 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5616 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
5617 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
5618 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
5619 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
5620 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5621 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5622 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
5623 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
5625 SetRect(&rect, 0, h, w, 0);
5626 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5627 context_active_texture(context, context->gl_info, 0);
5628 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
5629 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
5630 if (gl_info->supported[ARB_SHADOW])
5632 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5633 if (compare_mode != GL_NONE)
5634 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5637 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5638 gl_info, info.tex_type, &surface->ds_current_size);
5640 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
5641 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
5642 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
5643 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
5644 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
5645 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
5646 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
5647 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
5648 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
5649 gl_info->gl_ops.gl.p_glEnd();
5651 if (compare_mode != GL_NONE)
5652 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5653 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
5655 gl_info->gl_ops.gl.p_glPopAttrib();
5657 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5660 void surface_modify_ds_location(struct wined3d_surface *surface,
5661 DWORD location, UINT w, UINT h)
5663 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5665 if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5666 FIXME("Invalid location (%#x) specified.\n", location);
5668 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5669 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5671 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5673 TRACE("Passing to container.\n");
5674 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5678 surface->ds_current_size.cx = w;
5679 surface->ds_current_size.cy = h;
5680 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5681 surface->flags |= location;
5684 /* Context activation is done by the caller. */
5685 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5687 const struct wined3d_gl_info *gl_info = context->gl_info;
5688 struct wined3d_device *device = surface->resource.device;
5691 TRACE("surface %p, new location %#x.\n", surface, location);
5693 /* TODO: Make this work for modes other than FBO */
5694 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5696 if (!(surface->flags & location))
5698 w = surface->ds_current_size.cx;
5699 h = surface->ds_current_size.cy;
5700 surface->ds_current_size.cx = 0;
5701 surface->ds_current_size.cy = 0;
5705 w = surface->resource.width;
5706 h = surface->resource.height;
5709 if (surface->ds_current_size.cx == surface->resource.width
5710 && surface->ds_current_size.cy == surface->resource.height)
5712 TRACE("Location (%#x) is already up to date.\n", location);
5716 if (surface->current_renderbuffer)
5718 FIXME("Not supported with fixed up depth stencil.\n");
5722 if (surface->flags & SFLAG_DISCARDED)
5724 TRACE("Surface was discarded, no need copy data.\n");
5727 case SFLAG_INTEXTURE:
5728 surface_prepare_texture(surface, context, FALSE);
5730 case SFLAG_INRB_MULTISAMPLE:
5731 surface_prepare_rb(surface, gl_info, TRUE);
5733 case SFLAG_INDRAWABLE:
5737 FIXME("Unhandled location %#x\n", location);
5739 surface->flags &= ~SFLAG_DISCARDED;
5740 surface->flags |= location;
5741 surface->ds_current_size.cx = surface->resource.width;
5742 surface->ds_current_size.cy = surface->resource.height;
5746 if (!(surface->flags & SFLAG_LOCATIONS))
5748 FIXME("No up to date depth stencil location.\n");
5749 surface->flags |= location;
5750 surface->ds_current_size.cx = surface->resource.width;
5751 surface->ds_current_size.cy = surface->resource.height;
5755 if (location == SFLAG_INTEXTURE)
5757 GLint old_binding = 0;
5760 /* The render target is allowed to be smaller than the depth/stencil
5761 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5762 * than the offscreen surface. Don't overwrite the offscreen surface
5763 * with undefined data. */
5764 w = min(w, context->swapchain->desc.backbuffer_width);
5765 h = min(h, context->swapchain->desc.backbuffer_height);
5767 TRACE("Copying onscreen depth buffer to depth texture.\n");
5771 if (!device->depth_blt_texture)
5772 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
5774 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5775 * directly on the FBO texture. That's because we need to flip. */
5776 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5777 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5778 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
5780 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5781 bind_target = GL_TEXTURE_RECTANGLE_ARB;
5785 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5786 bind_target = GL_TEXTURE_2D;
5788 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
5789 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5790 * internal format, because the internal format might include stencil
5791 * data. In principle we should copy stencil data as well, but unless
5792 * the driver supports stencil export it's hard to do, and doesn't
5793 * seem to be needed in practice. If the hardware doesn't support
5794 * writing stencil data, the glCopyTexImage2D() call might trigger
5795 * software fallbacks. */
5796 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
5797 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5798 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5799 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5800 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5801 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
5802 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5803 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
5805 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5806 NULL, surface, SFLAG_INTEXTURE);
5807 context_set_draw_buffer(context, GL_NONE);
5808 gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
5810 /* Do the actual blit */
5811 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
5812 checkGLcall("depth_blt");
5814 context_invalidate_state(context, STATE_FRAMEBUFFER);
5818 if (wined3d_settings.strict_draw_ordering)
5819 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5821 else if (location == SFLAG_INDRAWABLE)
5823 TRACE("Copying depth texture to onscreen depth buffer.\n");
5827 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5828 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5829 surface_depth_blt(surface, context, surface->texture_name,
5830 0, surface->pow2Height - h, w, h, surface->texture_target);
5831 checkGLcall("depth_blt");
5833 context_invalidate_state(context, STATE_FRAMEBUFFER);
5837 if (wined3d_settings.strict_draw_ordering)
5838 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5842 ERR("Invalid location (%#x) specified.\n", location);
5845 surface->flags |= location;
5846 surface->ds_current_size.cx = surface->resource.width;
5847 surface->ds_current_size.cy = surface->resource.height;
5850 void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
5852 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
5853 struct wined3d_surface *overlay;
5855 TRACE("surface %p, location %s, persistent %#x.\n",
5856 surface, debug_surflocation(location), persistent);
5858 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
5859 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
5860 && (location & SFLAG_INDRAWABLE))
5861 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5863 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
5864 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
5865 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
5869 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5870 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
5872 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5874 TRACE("Passing to container.\n");
5875 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5878 surface->flags &= ~SFLAG_LOCATIONS;
5879 surface->flags |= location;
5881 /* Redraw emulated overlays, if any */
5882 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
5884 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
5886 surface_draw_overlay(overlay);
5892 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
5894 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5896 TRACE("Passing to container\n");
5897 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5900 surface->flags &= ~location;
5903 if (!(surface->flags & SFLAG_LOCATIONS))
5905 ERR("Surface %p does not have any up to date location.\n", surface);
5909 static DWORD resource_access_from_location(DWORD location)
5913 case SFLAG_INSYSMEM:
5914 return WINED3D_RESOURCE_ACCESS_CPU;
5916 case SFLAG_INDRAWABLE:
5917 case SFLAG_INSRGBTEX:
5918 case SFLAG_INTEXTURE:
5919 case SFLAG_INRB_MULTISAMPLE:
5920 case SFLAG_INRB_RESOLVED:
5921 return WINED3D_RESOURCE_ACCESS_GPU;
5924 FIXME("Unhandled location %#x.\n", location);
5929 static void surface_load_sysmem(struct wined3d_surface *surface,
5930 const struct wined3d_gl_info *gl_info, const RECT *rect)
5932 surface_prepare_system_memory(surface);
5934 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
5935 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5937 /* Download the surface to system memory. */
5938 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
5940 struct wined3d_device *device = surface->resource.device;
5941 struct wined3d_context *context;
5943 /* TODO: Use already acquired context when possible. */
5944 context = context_acquire(device, NULL);
5946 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
5947 surface_download_data(surface, gl_info);
5949 context_release(context);
5954 if (surface->flags & SFLAG_INDRAWABLE)
5956 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
5957 wined3d_surface_get_pitch(surface));
5961 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
5962 surface, surface->flags & SFLAG_LOCATIONS);
5965 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
5966 const struct wined3d_gl_info *gl_info, const RECT *rect)
5968 struct wined3d_device *device = surface->resource.device;
5969 enum wined3d_conversion_type convert;
5970 struct wined3d_format format;
5974 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
5976 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5977 return WINED3DERR_INVALIDCALL;
5980 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
5981 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5983 if (surface->flags & SFLAG_INTEXTURE)
5987 surface_get_rect(surface, rect, &r);
5988 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
5993 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
5995 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5996 * path through sysmem. */
5997 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6000 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
6002 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6003 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
6005 if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
6007 struct wined3d_context *context;
6009 TRACE("Removing the pbo attached to surface %p.\n", surface);
6011 /* TODO: Use already acquired context when possible. */
6012 context = context_acquire(device, NULL);
6014 surface_remove_pbo(surface, gl_info);
6016 context_release(context);
6019 if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
6021 UINT height = surface->resource.height;
6022 UINT width = surface->resource.width;
6023 UINT src_pitch, dst_pitch;
6025 byte_count = format.conv_byte_count;
6026 src_pitch = wined3d_surface_get_pitch(surface);
6028 /* Stick to the alignment for the converted surface too, makes it
6029 * easier to load the surface. */
6030 dst_pitch = width * byte_count;
6031 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6033 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6035 ERR("Out of memory (%u).\n", dst_pitch * height);
6036 return E_OUTOFMEMORY;
6039 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6040 src_pitch, width, height, dst_pitch, convert, surface);
6042 surface->flags |= SFLAG_CONVERTED;
6046 surface->flags &= ~SFLAG_CONVERTED;
6047 mem = surface->resource.allocatedMemory;
6048 byte_count = format.byte_count;
6051 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6053 /* Don't delete PBO memory. */
6054 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6055 HeapFree(GetProcessHeap(), 0, mem);
6060 static HRESULT surface_load_texture(struct wined3d_surface *surface,
6061 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6063 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6064 struct wined3d_device *device = surface->resource.device;
6065 enum wined3d_conversion_type convert;
6066 struct wined3d_context *context;
6067 UINT width, src_pitch, dst_pitch;
6068 struct wined3d_bo_address data;
6069 struct wined3d_format format;
6070 POINT dst_point = {0, 0};
6073 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6074 && surface_is_offscreen(surface)
6075 && (surface->flags & SFLAG_INDRAWABLE))
6077 surface_load_fb_texture(surface, srgb);
6082 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6083 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6084 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6085 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6086 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6089 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6090 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6092 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6093 &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6098 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6099 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6100 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6101 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6102 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6104 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6105 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6106 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6108 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6109 &rect, surface, dst_location, &rect);
6114 /* Upload from system memory */
6116 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6117 TRUE /* We will use textures */, &format, &convert);
6121 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6123 /* Performance warning... */
6124 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6125 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6130 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6132 /* Performance warning... */
6133 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6134 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6138 if (!(surface->flags & SFLAG_INSYSMEM))
6140 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6141 /* Lets hope we get it from somewhere... */
6142 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6145 /* TODO: Use already acquired context when possible. */
6146 context = context_acquire(device, NULL);
6148 surface_prepare_texture(surface, context, srgb);
6149 surface_bind_and_dirtify(surface, context, srgb);
6151 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6153 surface->flags |= SFLAG_GLCKEY;
6154 surface->gl_color_key = surface->src_blt_color_key;
6156 else surface->flags &= ~SFLAG_GLCKEY;
6158 width = surface->resource.width;
6159 src_pitch = wined3d_surface_get_pitch(surface);
6161 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6162 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6164 if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6166 TRACE("Removing the pbo attached to surface %p.\n", surface);
6167 surface_remove_pbo(surface, gl_info);
6172 /* This code is entered for texture formats which need a fixup. */
6173 UINT height = surface->resource.height;
6175 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6176 dst_pitch = width * format.conv_byte_count;
6177 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6179 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6181 ERR("Out of memory (%u).\n", dst_pitch * height);
6182 context_release(context);
6183 return E_OUTOFMEMORY;
6185 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6186 format.byte_count = format.conv_byte_count;
6187 src_pitch = dst_pitch;
6189 else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6191 /* This code is only entered for color keying fixups */
6192 UINT height = surface->resource.height;
6194 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6195 dst_pitch = width * format.conv_byte_count;
6196 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6198 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6200 ERR("Out of memory (%u).\n", dst_pitch * height);
6201 context_release(context);
6202 return E_OUTOFMEMORY;
6204 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6205 width, height, dst_pitch, convert, surface);
6206 format.byte_count = format.conv_byte_count;
6207 src_pitch = dst_pitch;
6211 mem = surface->resource.allocatedMemory;
6214 data.buffer_object = surface->pbo;
6216 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6218 context_release(context);
6220 /* Don't delete PBO memory. */
6221 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6222 HeapFree(GetProcessHeap(), 0, mem);
6227 static void surface_multisample_resolve(struct wined3d_surface *surface)
6229 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6231 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6232 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6234 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6235 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6238 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6240 struct wined3d_device *device = surface->resource.device;
6241 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6244 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6246 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6248 if (location == SFLAG_INTEXTURE)
6250 struct wined3d_context *context = context_acquire(device, NULL);
6251 surface_load_ds_location(surface, context, location);
6252 context_release(context);
6257 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location));
6258 return WINED3DERR_INVALIDCALL;
6262 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6263 location = SFLAG_INTEXTURE;
6265 if (surface->flags & location)
6267 TRACE("Location already up to date.\n");
6269 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6270 && surface_need_pbo(surface, gl_info))
6271 surface_load_pbo(surface, gl_info);
6276 if (WARN_ON(d3d_surface))
6278 DWORD required_access = resource_access_from_location(location);
6279 if ((surface->resource.access_flags & required_access) != required_access)
6280 WARN("Operation requires %#x access, but surface only has %#x.\n",
6281 required_access, surface->resource.access_flags);
6284 if (!(surface->flags & SFLAG_LOCATIONS))
6286 ERR("Surface %p does not have any up to date location.\n", surface);
6287 surface->flags |= SFLAG_LOST;
6288 return WINED3DERR_DEVICELOST;
6293 case SFLAG_INSYSMEM:
6294 surface_load_sysmem(surface, gl_info, rect);
6297 case SFLAG_INDRAWABLE:
6298 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6302 case SFLAG_INRB_RESOLVED:
6303 surface_multisample_resolve(surface);
6306 case SFLAG_INTEXTURE:
6307 case SFLAG_INSRGBTEX:
6308 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6313 ERR("Don't know how to handle location %#x.\n", location);
6319 surface->flags |= location;
6321 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6322 surface_evict_sysmem(surface);
6325 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6326 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6328 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6334 BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6336 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6338 /* Not on a swapchain - must be offscreen */
6339 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6341 /* The front buffer is always onscreen */
6342 if (surface == swapchain->front_buffer) return FALSE;
6344 /* If the swapchain is rendered to an FBO, the backbuffer is
6345 * offscreen, otherwise onscreen */
6346 return swapchain->render_to_fbo;
6349 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6350 /* Context activation is done by the caller. */
6351 static void ffp_blit_free(struct wined3d_device *device) { }
6353 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6354 /* Context activation is done by the caller. */
6355 static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6358 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) != 0;
6361 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6362 target = surface->container.u.texture->target;
6364 target = surface->texture_target;
6366 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6368 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6370 GL_EXTCALL(glColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6374 /* Context activation is done by the caller. */
6375 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6377 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6378 const struct wined3d_gl_info *gl_info = context->gl_info;
6381 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6382 target = surface->container.u.texture->target;
6384 target = surface->texture_target;
6386 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6387 * else the surface is converted in software at upload time in LoadLocation.
6389 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6390 && gl_info->supported[EXT_PALETTED_TEXTURE])
6391 ffp_blit_p8_upload_palette(surface, gl_info);
6394 gl_info->gl_ops.gl.p_glEnable(target);
6395 checkGLcall("glEnable(target)");
6400 /* Context activation is done by the caller. */
6401 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6404 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
6405 checkGLcall("glDisable(GL_TEXTURE_2D)");
6406 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6408 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6409 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6411 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6413 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
6414 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6419 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6420 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6421 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6423 enum complex_fixup src_fixup;
6427 case WINED3D_BLIT_OP_COLOR_BLIT:
6428 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6431 src_fixup = get_complex_fixup(src_format->color_fixup);
6432 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6434 TRACE("Checking support for fixup:\n");
6435 dump_color_fixup_desc(src_format->color_fixup);
6438 if (!is_identity_fixup(dst_format->color_fixup))
6440 TRACE("Destination fixups are not supported\n");
6444 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6446 TRACE("P8 fixup supported\n");
6450 /* We only support identity conversions. */
6451 if (is_identity_fixup(src_format->color_fixup))
6457 TRACE("[FAILED]\n");
6460 case WINED3D_BLIT_OP_COLOR_FILL:
6461 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6464 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6466 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6469 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6471 TRACE("Color fill not supported\n");
6475 /* FIXME: We should reject color fills on formats with fixups,
6476 * but this would break P8 color fills for example. */
6480 case WINED3D_BLIT_OP_DEPTH_FILL:
6484 TRACE("Unsupported blit_op=%d\n", blit_op);
6489 /* Do not call while under the GL lock. */
6490 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6491 const RECT *dst_rect, const struct wined3d_color *color)
6493 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6494 struct wined3d_fb_state fb = {&dst_surface, NULL};
6496 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6501 /* Do not call while under the GL lock. */
6502 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6503 struct wined3d_surface *surface, const RECT *rect, float depth)
6505 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6506 struct wined3d_fb_state fb = {NULL, surface};
6508 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6513 const struct blit_shader ffp_blit = {
6519 ffp_blit_color_fill,
6520 ffp_blit_depth_fill,
6523 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6528 /* Context activation is done by the caller. */
6529 static void cpu_blit_free(struct wined3d_device *device)
6533 /* Context activation is done by the caller. */
6534 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6539 /* Context activation is done by the caller. */
6540 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6544 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6545 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6546 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6548 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6556 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6557 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6558 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6560 UINT row_block_count;
6561 const BYTE *src_row;
6568 row_block_count = (update_w + format->block_width - 1) / format->block_width;
6572 for (y = 0; y < update_h; y += format->block_height)
6574 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6575 src_row += src_pitch;
6576 dst_row += dst_pitch;
6582 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6584 src_row += (((update_h / format->block_height) - 1) * src_pitch);
6588 case WINED3DFMT_DXT1:
6589 for (y = 0; y < update_h; y += format->block_height)
6594 BYTE control_row[4];
6597 const struct block *s = (const struct block *)src_row;
6598 struct block *d = (struct block *)dst_row;
6600 for (x = 0; x < row_block_count; ++x)
6602 d[x].color[0] = s[x].color[0];
6603 d[x].color[1] = s[x].color[1];
6604 d[x].control_row[0] = s[x].control_row[3];
6605 d[x].control_row[1] = s[x].control_row[2];
6606 d[x].control_row[2] = s[x].control_row[1];
6607 d[x].control_row[3] = s[x].control_row[0];
6609 src_row -= src_pitch;
6610 dst_row += dst_pitch;
6614 case WINED3DFMT_DXT3:
6615 for (y = 0; y < update_h; y += format->block_height)
6621 BYTE control_row[4];
6624 const struct block *s = (const struct block *)src_row;
6625 struct block *d = (struct block *)dst_row;
6627 for (x = 0; x < row_block_count; ++x)
6629 d[x].alpha_row[0] = s[x].alpha_row[3];
6630 d[x].alpha_row[1] = s[x].alpha_row[2];
6631 d[x].alpha_row[2] = s[x].alpha_row[1];
6632 d[x].alpha_row[3] = s[x].alpha_row[0];
6633 d[x].color[0] = s[x].color[0];
6634 d[x].color[1] = s[x].color[1];
6635 d[x].control_row[0] = s[x].control_row[3];
6636 d[x].control_row[1] = s[x].control_row[2];
6637 d[x].control_row[2] = s[x].control_row[1];
6638 d[x].control_row[3] = s[x].control_row[0];
6640 src_row -= src_pitch;
6641 dst_row += dst_pitch;
6646 FIXME("Compressed flip not implemented for format %s.\n",
6647 debug_d3dformat(format->id));
6652 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
6653 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
6658 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
6659 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
6660 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
6662 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
6663 const struct wined3d_format *src_format, *dst_format;
6664 struct wined3d_surface *orig_src = src_surface;
6665 struct wined3d_map_desc dst_map, src_map;
6666 const BYTE *sbase = NULL;
6667 HRESULT hr = WINED3D_OK;
6672 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6673 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
6674 flags, fx, debug_d3dtexturefiltertype(filter));
6676 if (src_surface == dst_surface)
6678 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
6680 src_format = dst_surface->resource.format;
6681 dst_format = src_format;
6685 dst_format = dst_surface->resource.format;
6688 if (dst_surface->resource.format->id != src_surface->resource.format->id)
6690 src_surface = surface_convert_format(src_surface, dst_format->id);
6693 /* The conv function writes a FIXME */
6694 WARN("Cannot convert source surface format to dest format.\n");
6698 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
6699 src_format = src_surface->resource.format;
6703 src_format = dst_format;
6706 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
6709 bpp = dst_surface->resource.format->byte_count;
6710 srcheight = src_rect->bottom - src_rect->top;
6711 srcwidth = src_rect->right - src_rect->left;
6712 dstheight = dst_rect->bottom - dst_rect->top;
6713 dstwidth = dst_rect->right - dst_rect->left;
6714 width = (dst_rect->right - dst_rect->left) * bpp;
6717 sbase = (BYTE *)src_map.data
6718 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
6719 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
6720 if (src_surface != dst_surface)
6721 dbuf = dst_map.data;
6723 dbuf = (BYTE *)dst_map.data
6724 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
6725 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
6727 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
6729 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
6731 if (src_surface == dst_surface)
6733 FIXME("Only plain blits supported on compressed surfaces.\n");
6738 if (srcheight != dstheight || srcwidth != dstwidth)
6740 WARN("Stretching not supported on compressed surfaces.\n");
6741 hr = WINED3DERR_INVALIDCALL;
6745 if (!surface_check_block_align(src_surface, src_rect))
6747 WARN("Source rectangle not block-aligned.\n");
6748 hr = WINED3DERR_INVALIDCALL;
6752 if (!surface_check_block_align(dst_surface, dst_rect))
6754 WARN("Destination rectangle not block-aligned.\n");
6755 hr = WINED3DERR_INVALIDCALL;
6759 hr = surface_cpu_blt_compressed(sbase, dbuf,
6760 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
6761 src_format, flags, fx);
6765 /* First, all the 'source-less' blits */
6766 if (flags & WINEDDBLT_COLORFILL)
6768 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
6769 flags &= ~WINEDDBLT_COLORFILL;
6772 if (flags & WINEDDBLT_DEPTHFILL)
6774 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6776 if (flags & WINEDDBLT_ROP)
6778 /* Catch some degenerate cases here. */
6782 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
6784 case 0xaa0029: /* No-op */
6787 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
6789 case SRCCOPY: /* Well, we do that below? */
6792 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
6795 flags &= ~WINEDDBLT_ROP;
6797 if (flags & WINEDDBLT_DDROPS)
6799 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
6801 /* Now the 'with source' blits. */
6804 int sx, xinc, sy, yinc;
6806 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
6809 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
6810 && (srcwidth != dstwidth || srcheight != dstheight))
6812 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6813 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
6816 xinc = (srcwidth << 16) / dstwidth;
6817 yinc = (srcheight << 16) / dstheight;
6821 /* No effects, we can cheat here. */
6822 if (dstwidth == srcwidth)
6824 if (dstheight == srcheight)
6826 /* No stretching in either direction. This needs to be as
6827 * fast as possible. */
6830 /* Check for overlapping surfaces. */
6831 if (src_surface != dst_surface || dst_rect->top < src_rect->top
6832 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
6834 /* No overlap, or dst above src, so copy from top downwards. */
6835 for (y = 0; y < dstheight; ++y)
6837 memcpy(dbuf, sbuf, width);
6838 sbuf += src_map.row_pitch;
6839 dbuf += dst_map.row_pitch;
6842 else if (dst_rect->top > src_rect->top)
6844 /* Copy from bottom upwards. */
6845 sbuf += src_map.row_pitch * dstheight;
6846 dbuf += dst_map.row_pitch * dstheight;
6847 for (y = 0; y < dstheight; ++y)
6849 sbuf -= src_map.row_pitch;
6850 dbuf -= dst_map.row_pitch;
6851 memcpy(dbuf, sbuf, width);
6856 /* Src and dst overlapping on the same line, use memmove. */
6857 for (y = 0; y < dstheight; ++y)
6859 memmove(dbuf, sbuf, width);
6860 sbuf += src_map.row_pitch;
6861 dbuf += dst_map.row_pitch;
6867 /* Stretching in y direction only. */
6868 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6870 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6871 memcpy(dbuf, sbuf, width);
6872 dbuf += dst_map.row_pitch;
6878 /* Stretching in X direction. */
6880 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6882 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6884 if ((sy >> 16) == (last_sy >> 16))
6886 /* This source row is the same as last source row -
6887 * Copy the already stretched row. */
6888 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
6892 #define STRETCH_ROW(type) \
6894 const type *s = (const type *)sbuf; \
6895 type *d = (type *)dbuf; \
6896 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6897 d[x] = s[sx >> 16]; \
6915 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
6919 s = sbuf + 3 * (sx >> 16);
6920 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
6921 d[0] = (pixel ) & 0xff;
6922 d[1] = (pixel >> 8) & 0xff;
6923 d[2] = (pixel >> 16) & 0xff;
6929 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
6930 hr = WINED3DERR_NOTAVAILABLE;
6935 dbuf += dst_map.row_pitch;
6942 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
6943 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
6944 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
6945 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
6947 /* The color keying flags are checked for correctness in ddraw */
6948 if (flags & WINEDDBLT_KEYSRC)
6950 keylow = src_surface->src_blt_color_key.color_space_low_value;
6951 keyhigh = src_surface->src_blt_color_key.color_space_high_value;
6953 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6955 keylow = fx->ddckSrcColorkey.color_space_low_value;
6956 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
6959 if (flags & WINEDDBLT_KEYDEST)
6961 /* Destination color keys are taken from the source surface! */
6962 destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
6963 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
6965 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
6967 destkeylow = fx->ddckDestColorkey.color_space_low_value;
6968 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
6978 get_color_masks(src_format, masks);
6983 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
6986 if (flags & WINEDDBLT_DDFX)
6988 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
6991 dTopRight = dbuf + ((dstwidth - 1) * bpp);
6992 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
6993 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
6995 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
6997 /* I don't think we need to do anything about this flag */
6998 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
7000 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
7003 dTopRight = dTopLeft;
7006 dBottomRight = dBottomLeft;
7008 dstxinc = dstxinc * -1;
7010 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
7013 dTopLeft = dBottomLeft;
7016 dTopRight = dBottomRight;
7018 dstyinc = dstyinc * -1;
7020 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
7022 /* I don't think we need to do anything about this flag */
7023 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
7025 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
7028 dBottomRight = dTopLeft;
7031 dBottomLeft = dTopRight;
7033 dstxinc = dstxinc * -1;
7034 dstyinc = dstyinc * -1;
7036 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
7039 dTopLeft = dBottomLeft;
7040 dBottomLeft = dBottomRight;
7041 dBottomRight = dTopRight;
7046 dstxinc = dstxinc * -1;
7048 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7051 dTopLeft = dTopRight;
7052 dTopRight = dBottomRight;
7053 dBottomRight = dBottomLeft;
7058 dstyinc = dstyinc * -1;
7060 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7062 /* I don't think we need to do anything about this flag */
7063 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7066 flags &= ~(WINEDDBLT_DDFX);
7069 #define COPY_COLORKEY_FX(type) \
7072 type *d = (type *)dbuf, *dx, tmp; \
7073 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7075 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7077 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7079 tmp = s[sx >> 16]; \
7080 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7081 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7085 dx = (type *)(((BYTE *)dx) + dstxinc); \
7087 d = (type *)(((BYTE *)d) + dstyinc); \
7094 COPY_COLORKEY_FX(BYTE);
7097 COPY_COLORKEY_FX(WORD);
7100 COPY_COLORKEY_FX(DWORD);
7105 BYTE *d = dbuf, *dx;
7106 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7108 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7110 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7112 DWORD pixel, dpixel = 0;
7113 s = sbuf + 3 * (sx>>16);
7114 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7115 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7116 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7117 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7119 dx[0] = (pixel ) & 0xff;
7120 dx[1] = (pixel >> 8) & 0xff;
7121 dx[2] = (pixel >> 16) & 0xff;
7130 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7131 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7132 hr = WINED3DERR_NOTAVAILABLE;
7134 #undef COPY_COLORKEY_FX
7140 if (flags && FIXME_ON(d3d_surface))
7142 FIXME("\tUnsupported flags: %#x.\n", flags);
7146 wined3d_surface_unmap(dst_surface);
7147 if (src_surface && src_surface != dst_surface)
7148 wined3d_surface_unmap(src_surface);
7149 /* Release the converted surface, if any. */
7150 if (src_surface && src_surface != orig_src)
7151 wined3d_surface_decref(src_surface);
7156 /* Do not call while under the GL lock. */
7157 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7158 const RECT *dst_rect, const struct wined3d_color *color)
7160 static const RECT src_rect;
7163 memset(&BltFx, 0, sizeof(BltFx));
7164 BltFx.dwSize = sizeof(BltFx);
7165 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7166 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7167 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7170 /* Do not call while under the GL lock. */
7171 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7172 struct wined3d_surface *surface, const RECT *rect, float depth)
7174 FIXME("Depth filling not implemented by cpu_blit.\n");
7175 return WINED3DERR_INVALIDCALL;
7178 const struct blit_shader cpu_blit = {
7184 cpu_blit_color_fill,
7185 cpu_blit_depth_fill,
7188 static HRESULT surface_init(struct wined3d_surface *surface, enum wined3d_surface_type surface_type,
7189 UINT alignment, UINT width, UINT height, enum wined3d_multisample_type multisample_type,
7190 UINT multisample_quality, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7191 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops)
7193 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7194 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7195 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7196 unsigned int resource_size;
7199 if (multisample_quality > 0)
7201 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7202 multisample_quality = 0;
7205 /* Quick lockable sanity check.
7206 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7207 * this function is too deep to need to care about things like this.
7208 * Levels need to be checked too, since they all affect what can be done. */
7211 case WINED3D_POOL_SCRATCH:
7214 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7215 "which are mutually exclusive, setting lockable to TRUE.\n");
7220 case WINED3D_POOL_SYSTEM_MEM:
7222 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7225 case WINED3D_POOL_MANAGED:
7226 if (usage & WINED3DUSAGE_DYNAMIC)
7227 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7230 case WINED3D_POOL_DEFAULT:
7231 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7232 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7236 FIXME("Unknown pool %#x.\n", pool);
7240 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7241 FIXME("Trying to create a render target that isn't in the default pool.\n");
7243 /* FIXME: Check that the format is supported by the device. */
7245 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7247 return WINED3DERR_INVALIDCALL;
7249 surface->surface_type = surface_type;
7251 switch (surface_type)
7253 case WINED3D_SURFACE_TYPE_OPENGL:
7254 surface->surface_ops = &surface_ops;
7257 case WINED3D_SURFACE_TYPE_GDI:
7258 surface->surface_ops = &gdi_surface_ops;
7262 ERR("Requested unknown surface implementation %#x.\n", surface_type);
7263 return WINED3DERR_INVALIDCALL;
7266 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7267 multisample_type, multisample_quality, usage, pool, width, height, 1,
7268 resource_size, parent, parent_ops, &surface_resource_ops);
7271 WARN("Failed to initialize resource, returning %#x.\n", hr);
7275 /* "Standalone" surface. */
7276 surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7278 list_init(&surface->overlays);
7281 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7282 if (flags & WINED3D_SURFACE_DISCARD)
7283 surface->flags |= SFLAG_DISCARD;
7284 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7285 surface->flags |= SFLAG_PIN_SYSMEM;
7286 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7287 surface->flags |= SFLAG_LOCKABLE;
7288 /* I'm not sure if this qualifies as a hack or as an optimization. It
7289 * seems reasonable to assume that lockable render targets will get
7290 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7291 * creation. However, the other reason we want to do this is that several
7292 * ddraw applications access surface memory while the surface isn't
7293 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7294 * future locks prevents these from crashing. */
7295 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7296 surface->flags |= SFLAG_DYNLOCK;
7298 /* Mark the texture as dirty so that it gets loaded first time around. */
7299 surface_add_dirty_rect(surface, NULL);
7300 list_init(&surface->renderbuffers);
7302 TRACE("surface %p, memory %p, size %u\n",
7303 surface, surface->resource.allocatedMemory, surface->resource.size);
7305 /* Call the private setup routine */
7306 hr = surface->surface_ops->surface_private_setup(surface);
7309 ERR("Private setup failed, returning %#x\n", hr);
7310 surface_cleanup(surface);
7314 /* Similar to lockable rendertargets above, creating the DIB section
7315 * during surface initialization prevents the sysmem pointer from changing
7316 * after a wined3d_surface_getdc() call. */
7317 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7318 && SUCCEEDED(surface_create_dib_section(surface)))
7320 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7321 surface->resource.heapMemory = NULL;
7322 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7328 HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
7329 enum wined3d_format_id format_id, DWORD usage, enum wined3d_pool pool,
7330 enum wined3d_multisample_type multisample_type, DWORD multisample_quality,
7331 enum wined3d_surface_type surface_type, DWORD flags, void *parent,
7332 const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface)
7334 struct wined3d_surface *object;
7337 TRACE("device %p, width %u, height %u, format %s\n",
7338 device, width, height, debug_d3dformat(format_id));
7339 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7340 surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
7341 TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type, flags, parent, parent_ops);
7343 if (surface_type == WINED3D_SURFACE_TYPE_OPENGL && !device->adapter)
7345 ERR("OpenGL surfaces are not available without OpenGL.\n");
7346 return WINED3DERR_NOTAVAILABLE;
7349 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
7352 ERR("Failed to allocate surface memory.\n");
7353 return WINED3DERR_OUTOFVIDEOMEMORY;
7356 if (FAILED(hr = surface_init(object, surface_type, device->surface_alignment, width, height,
7357 multisample_type, multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops)))
7359 WARN("Failed to initialize surface, returning %#x.\n", hr);
7360 HeapFree(GetProcessHeap(), 0, object);
7364 TRACE("Created surface %p.\n", object);