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)
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_force_reload(surface);
2126 /* This call just downloads data, the caller is responsible for binding the
2127 * correct texture. */
2128 /* Context activation is done by the caller. */
2129 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2131 const struct wined3d_format *format = surface->resource.format;
2133 /* Only support read back of converted P8 surfaces. */
2134 if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
2136 ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
2142 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2144 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2145 surface, surface->texture_level, format->glFormat, format->glType,
2146 surface->resource.allocatedMemory);
2148 if (surface->flags & SFLAG_PBO)
2150 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2151 checkGLcall("glBindBufferARB");
2152 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
2153 checkGLcall("glGetCompressedTexImageARB");
2154 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2155 checkGLcall("glBindBufferARB");
2159 GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
2160 surface->texture_level, surface->resource.allocatedMemory));
2161 checkGLcall("glGetCompressedTexImageARB");
2169 GLenum gl_format = format->glFormat;
2170 GLenum gl_type = format->glType;
2174 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2175 if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device))
2177 gl_format = GL_ALPHA;
2178 gl_type = GL_UNSIGNED_BYTE;
2181 if (surface->flags & SFLAG_NONPOW2)
2183 unsigned char alignment = surface->resource.device->surface_alignment;
2184 src_pitch = format->byte_count * surface->pow2Width;
2185 dst_pitch = wined3d_surface_get_pitch(surface);
2186 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
2187 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
2191 mem = surface->resource.allocatedMemory;
2194 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2195 surface, surface->texture_level, gl_format, gl_type, mem);
2197 if (surface->flags & SFLAG_PBO)
2199 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2200 checkGLcall("glBindBufferARB");
2202 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2203 gl_format, gl_type, NULL);
2204 checkGLcall("glGetTexImage");
2206 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2207 checkGLcall("glBindBufferARB");
2211 gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2212 gl_format, gl_type, mem);
2213 checkGLcall("glGetTexImage");
2217 if (surface->flags & SFLAG_NONPOW2)
2219 const BYTE *src_data;
2223 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2224 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2225 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2227 * We're doing this...
2229 * instead of boxing the texture :
2230 * |<-texture width ->| -->pow2width| /\
2231 * |111111111111111111| | |
2232 * |222 Texture 222222| boxed empty | texture height
2233 * |3333 Data 33333333| | |
2234 * |444444444444444444| | \/
2235 * ----------------------------------- |
2236 * | boxed empty | boxed empty | pow2height
2238 * -----------------------------------
2241 * we're repacking the data to the expected texture width
2243 * |<-texture width ->| -->pow2width| /\
2244 * |111111111111111111222222222222222| |
2245 * |222333333333333333333444444444444| texture height
2249 * | empty | pow2height
2251 * -----------------------------------
2255 * |<-texture width ->| /\
2256 * |111111111111111111|
2257 * |222222222222222222|texture height
2258 * |333333333333333333|
2259 * |444444444444444444| \/
2260 * --------------------
2262 * this also means that any references to allocatedMemory should work with the data as if were a
2263 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2265 * internally the texture is still stored in a boxed format so any references to textureName will
2266 * get a boxed texture with width pow2width and not a texture of width resource.width.
2268 * Performance should not be an issue, because applications normally do not lock the surfaces when
2269 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2270 * and doesn't have to be re-read. */
2272 dst_data = surface->resource.allocatedMemory;
2273 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
2274 for (y = 1; y < surface->resource.height; ++y)
2276 /* skip the first row */
2277 src_data += src_pitch;
2278 dst_data += dst_pitch;
2279 memcpy(dst_data, src_data, dst_pitch);
2282 HeapFree(GetProcessHeap(), 0, mem);
2286 /* Surface has now been downloaded */
2287 surface->flags |= SFLAG_INSYSMEM;
2290 /* This call just uploads data, the caller is responsible for binding the
2291 * correct texture. */
2292 /* Context activation is done by the caller. */
2293 static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2294 const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
2295 BOOL srgb, const struct wined3d_bo_address *data)
2297 UINT update_w = src_rect->right - src_rect->left;
2298 UINT update_h = src_rect->bottom - src_rect->top;
2300 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
2301 surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
2302 wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
2304 if (surface->resource.map_count)
2306 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
2307 surface->flags |= SFLAG_PIN_SYSMEM;
2310 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2312 update_h *= format->height_scale.numerator;
2313 update_h /= format->height_scale.denominator;
2318 if (data->buffer_object)
2320 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
2321 checkGLcall("glBindBufferARB");
2324 if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2326 UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1);
2327 UINT row_count = (update_h + format->block_height - 1) / format->block_height;
2328 const BYTE *addr = data->addr;
2331 addr += (src_rect->top / format->block_height) * src_pitch;
2332 addr += (src_rect->left / format->block_width) * format->block_byte_count;
2335 internal = format->glGammaInternal;
2336 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2337 internal = format->rtInternal;
2339 internal = format->glInternal;
2341 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2342 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
2343 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
2345 if (row_length == src_pitch)
2347 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2348 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
2354 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2355 * can't use the unpack row length like below. */
2356 for (row = 0, y = dst_point->y; row < row_count; ++row)
2358 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2359 dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
2360 y += format->block_height;
2364 checkGLcall("glCompressedTexSubImage2DARB");
2368 const BYTE *addr = data->addr;
2370 addr += src_rect->top * src_pitch;
2371 addr += src_rect->left * format->byte_count;
2373 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2374 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
2375 update_w, update_h, format->glFormat, format->glType, addr);
2377 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
2378 gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
2379 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
2380 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2381 checkGLcall("glTexSubImage2D");
2384 if (data->buffer_object)
2386 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2387 checkGLcall("glBindBufferARB");
2392 if (wined3d_settings.strict_draw_ordering)
2393 gl_info->gl_ops.gl.p_glFlush();
2395 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2397 struct wined3d_device *device = surface->resource.device;
2400 for (i = 0; i < device->context_count; ++i)
2402 context_surface_update(device->contexts[i], surface);
2407 static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
2408 struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
2410 BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2411 const struct wined3d_device *device = surface->resource.device;
2412 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2413 BOOL blit_supported = FALSE;
2415 /* Copy the default values from the surface. Below we might perform fixups */
2416 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2417 *format = *surface->resource.format;
2418 *conversion_type = WINED3D_CT_NONE;
2420 /* Ok, now look if we have to do any conversion */
2421 switch (surface->resource.format->id)
2423 case WINED3DFMT_P8_UINT:
2424 /* Below the call to blit_supported is disabled for Wine 1.2
2425 * because the function isn't operating correctly yet. At the
2426 * moment 8-bit blits are handled in software and if certain GL
2427 * extensions are around, surface conversion is performed at
2428 * upload time. The blit_supported call recognizes it as a
2429 * destination fixup. This type of upload 'fixup' and 8-bit to
2430 * 8-bit blits need to be handled by the blit_shader.
2431 * TODO: get rid of this #if 0. */
2433 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2434 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
2435 &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
2437 blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2439 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2440 * texturing. Further also use conversion in case of color keying.
2441 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2442 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2443 * conflicts with this.
2445 if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
2446 || colorkey_active || !use_texturing)
2448 format->glFormat = GL_RGBA;
2449 format->glInternal = GL_RGBA;
2450 format->glType = GL_UNSIGNED_BYTE;
2451 format->conv_byte_count = 4;
2452 if (colorkey_active)
2453 *conversion_type = WINED3D_CT_PALETTED_CK;
2455 *conversion_type = WINED3D_CT_PALETTED;
2459 case WINED3DFMT_B2G3R3_UNORM:
2460 /* **********************
2461 GL_UNSIGNED_BYTE_3_3_2
2462 ********************** */
2463 if (colorkey_active) {
2464 /* This texture format will never be used.. So do not care about color keying
2465 up until the point in time it will be needed :-) */
2466 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2470 case WINED3DFMT_B5G6R5_UNORM:
2471 if (colorkey_active)
2473 *conversion_type = WINED3D_CT_CK_565;
2474 format->glFormat = GL_RGBA;
2475 format->glInternal = GL_RGB5_A1;
2476 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2477 format->conv_byte_count = 2;
2481 case WINED3DFMT_B5G5R5X1_UNORM:
2482 if (colorkey_active)
2484 *conversion_type = WINED3D_CT_CK_5551;
2485 format->glFormat = GL_BGRA;
2486 format->glInternal = GL_RGB5_A1;
2487 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2488 format->conv_byte_count = 2;
2492 case WINED3DFMT_B8G8R8_UNORM:
2493 if (colorkey_active)
2495 *conversion_type = WINED3D_CT_CK_RGB24;
2496 format->glFormat = GL_RGBA;
2497 format->glInternal = GL_RGBA8;
2498 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2499 format->conv_byte_count = 4;
2503 case WINED3DFMT_B8G8R8X8_UNORM:
2504 if (colorkey_active)
2506 *conversion_type = WINED3D_CT_RGB32_888;
2507 format->glFormat = GL_RGBA;
2508 format->glInternal = GL_RGBA8;
2509 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2510 format->conv_byte_count = 4;
2514 case WINED3DFMT_B8G8R8A8_UNORM:
2515 if (colorkey_active)
2517 *conversion_type = WINED3D_CT_CK_ARGB32;
2518 format->conv_byte_count = 4;
2526 if (*conversion_type != WINED3D_CT_NONE)
2528 format->rtInternal = format->glInternal;
2529 format->glGammaInternal = format->glInternal;
2535 static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
2537 UINT width_mask, height_mask;
2539 if (!rect->left && !rect->top
2540 && rect->right == surface->resource.width
2541 && rect->bottom == surface->resource.height)
2544 /* This assumes power of two block sizes, but NPOT block sizes would be
2546 width_mask = surface->resource.format->block_width - 1;
2547 height_mask = surface->resource.format->block_height - 1;
2549 if (!(rect->left & width_mask) && !(rect->top & height_mask)
2550 && !(rect->right & width_mask) && !(rect->bottom & height_mask))
2556 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
2557 struct wined3d_surface *src_surface, const RECT *src_rect)
2559 const struct wined3d_format *src_format;
2560 const struct wined3d_format *dst_format;
2561 const struct wined3d_gl_info *gl_info;
2562 enum wined3d_conversion_type convert;
2563 struct wined3d_context *context;
2564 struct wined3d_bo_address data;
2565 struct wined3d_format format;
2566 UINT update_w, update_h;
2572 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2573 dst_surface, wine_dbgstr_point(dst_point),
2574 src_surface, wine_dbgstr_rect(src_rect));
2576 src_format = src_surface->resource.format;
2577 dst_format = dst_surface->resource.format;
2579 if (src_format->id != dst_format->id)
2581 WARN("Source and destination surfaces should have the same format.\n");
2582 return WINED3DERR_INVALIDCALL;
2591 else if (dst_point->x < 0 || dst_point->y < 0)
2593 WARN("Invalid destination point.\n");
2594 return WINED3DERR_INVALIDCALL;
2601 r.right = src_surface->resource.width;
2602 r.bottom = src_surface->resource.height;
2605 else if (src_rect->left < 0 || src_rect->left >= src_rect->right
2606 || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
2608 WARN("Invalid source rectangle.\n");
2609 return WINED3DERR_INVALIDCALL;
2612 dst_w = dst_surface->resource.width;
2613 dst_h = dst_surface->resource.height;
2615 update_w = src_rect->right - src_rect->left;
2616 update_h = src_rect->bottom - src_rect->top;
2618 if (update_w > dst_w || dst_point->x > dst_w - update_w
2619 || update_h > dst_h || dst_point->y > dst_h - update_h)
2621 WARN("Destination out of bounds.\n");
2622 return WINED3DERR_INVALIDCALL;
2625 if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
2627 WARN("Source rectangle not block-aligned.\n");
2628 return WINED3DERR_INVALIDCALL;
2631 SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
2632 if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
2634 WARN("Destination rectangle not block-aligned.\n");
2635 return WINED3DERR_INVALIDCALL;
2638 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2639 d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
2640 if (convert != WINED3D_CT_NONE || format.convert)
2641 return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
2643 context = context_acquire(dst_surface->resource.device, NULL);
2644 gl_info = context->gl_info;
2646 /* Only load the surface for partial updates. For newly allocated texture
2647 * the texture wouldn't be the current location, and we'd upload zeroes
2648 * just to overwrite them again. */
2649 if (update_w == dst_w && update_h == dst_h)
2650 surface_prepare_texture(dst_surface, context, FALSE);
2652 surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
2653 surface_bind(dst_surface, context, FALSE);
2655 data.buffer_object = src_surface->pbo;
2656 data.addr = src_surface->resource.allocatedMemory;
2657 src_pitch = wined3d_surface_get_pitch(src_surface);
2659 surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
2661 invalidate_active_texture(dst_surface->resource.device, context);
2663 context_release(context);
2665 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2669 /* This call just allocates the texture, the caller is responsible for binding
2670 * the correct texture. */
2671 /* Context activation is done by the caller. */
2672 static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2673 const struct wined3d_format *format, BOOL srgb)
2675 BOOL enable_client_storage = FALSE;
2676 GLsizei width = surface->pow2Width;
2677 GLsizei height = surface->pow2Height;
2678 const BYTE *mem = NULL;
2683 internal = format->glGammaInternal;
2685 else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2687 internal = format->rtInternal;
2691 internal = format->glInternal;
2695 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2697 if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2699 height *= format->height_scale.numerator;
2700 height /= format->height_scale.denominator;
2703 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",
2704 surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
2705 internal, width, height, format->glFormat, format->glType);
2709 if (gl_info->supported[APPLE_CLIENT_STORAGE])
2711 if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2712 || !surface->resource.allocatedMemory)
2714 /* In some cases we want to disable client storage.
2715 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2716 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2717 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2718 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2720 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2721 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2722 surface->flags &= ~SFLAG_CLIENT;
2723 enable_client_storage = TRUE;
2727 surface->flags |= SFLAG_CLIENT;
2729 /* Point OpenGL to our allocated texture memory. Do not use
2730 * resource.allocatedMemory here because it might point into a
2731 * PBO. Instead use heapMemory, but get the alignment right. */
2732 mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2733 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2737 if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
2739 GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
2740 internal, width, height, 0, surface->resource.size, mem));
2741 checkGLcall("glCompressedTexImage2DARB");
2745 gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
2746 internal, width, height, 0, format->glFormat, format->glType, mem);
2747 checkGLcall("glTexImage2D");
2750 if (enable_client_storage)
2752 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2753 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2758 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2759 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2760 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2761 /* GL locking is done by the caller */
2762 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
2764 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
2765 struct wined3d_renderbuffer_entry *entry;
2766 GLuint renderbuffer = 0;
2767 unsigned int src_width, src_height;
2768 unsigned int width, height;
2770 if (rt && rt->resource.format->id != WINED3DFMT_NULL)
2772 width = rt->pow2Width;
2773 height = rt->pow2Height;
2777 width = surface->pow2Width;
2778 height = surface->pow2Height;
2781 src_width = surface->pow2Width;
2782 src_height = surface->pow2Height;
2784 /* A depth stencil smaller than the render target is not valid */
2785 if (width > src_width || height > src_height) return;
2787 /* Remove any renderbuffer set if the sizes match */
2788 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
2789 || (width == src_width && height == src_height))
2791 surface->current_renderbuffer = NULL;
2795 /* Look if we've already got a renderbuffer of the correct dimensions */
2796 LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2798 if (entry->width == width && entry->height == height)
2800 renderbuffer = entry->id;
2801 surface->current_renderbuffer = entry;
2808 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
2809 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
2810 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
2811 surface->resource.format->glInternal, width, height);
2813 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
2814 entry->width = width;
2815 entry->height = height;
2816 entry->id = renderbuffer;
2817 list_add_head(&surface->renderbuffers, &entry->entry);
2819 surface->current_renderbuffer = entry;
2822 checkGLcall("set_compatible_renderbuffer");
2825 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
2827 const struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2829 TRACE("surface %p.\n", surface);
2831 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
2833 ERR("Surface %p is not on a swapchain.\n", surface);
2837 if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
2839 if (swapchain->render_to_fbo)
2841 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2842 return GL_COLOR_ATTACHMENT0;
2844 TRACE("Returning GL_BACK\n");
2847 else if (surface == swapchain->front_buffer)
2849 TRACE("Returning GL_FRONT\n");
2853 FIXME("Higher back buffer, returning GL_BACK\n");
2857 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2858 void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
2860 TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
2862 if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
2863 /* No partial locking for textures yet. */
2864 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2866 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2869 surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
2870 surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
2871 surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
2872 surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
2876 surface->dirtyRect.left = 0;
2877 surface->dirtyRect.top = 0;
2878 surface->dirtyRect.right = surface->resource.width;
2879 surface->dirtyRect.bottom = surface->resource.height;
2882 /* if the container is a texture then mark it dirty. */
2883 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
2885 TRACE("Passing to container.\n");
2886 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
2890 HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
2892 DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2895 TRACE("surface %p, srgb %#x.\n", surface, srgb);
2897 if (surface->resource.pool == WINED3D_POOL_SCRATCH)
2899 ERR("Not supported on scratch surfaces.\n");
2900 return WINED3DERR_INVALIDCALL;
2903 ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2905 /* Reload if either the texture and sysmem have different ideas about the
2906 * color key, or the actual key values changed. */
2907 if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
2908 && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
2909 || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
2911 TRACE("Reloading because of color keying\n");
2912 /* To perform the color key conversion we need a sysmem copy of
2913 * the surface. Make sure we have it. */
2915 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2916 /* Make sure the texture is reloaded because of the color key change,
2917 * this kills performance though :( */
2918 /* TODO: This is not necessarily needed with hw palettized texture support. */
2919 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2920 /* Switching color keying on / off may change the internal format. */
2922 surface_force_reload(surface);
2924 else if (!(surface->flags & flag))
2926 TRACE("Reloading because surface is dirty.\n");
2930 TRACE("surface is already in texture\n");
2934 /* No partial locking for textures yet. */
2935 surface_load_location(surface, flag, NULL);
2936 surface_evict_sysmem(surface);
2941 /* See also float_16_to_32() in wined3d_private.h */
2942 static inline unsigned short float_32_to_16(const float *in)
2945 float tmp = fabsf(*in);
2946 unsigned int mantissa;
2949 /* Deal with special numbers */
2955 return (*in < 0.0f ? 0xfc00 : 0x7c00);
2957 if (tmp < powf(2, 10))
2963 } while (tmp < powf(2, 10));
2965 else if (tmp >= powf(2, 11))
2971 } while (tmp >= powf(2, 11));
2974 mantissa = (unsigned int)tmp;
2975 if (tmp - mantissa >= 0.5f)
2976 ++mantissa; /* Round to nearest, away from zero. */
2978 exp += 10; /* Normalize the mantissa. */
2979 exp += 15; /* Exponent is encoded with excess 15. */
2981 if (exp > 30) /* too big */
2983 ret = 0x7c00; /* INF */
2987 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2990 mantissa = mantissa >> 1;
2993 ret = mantissa & 0x3ff;
2997 ret = (exp << 10) | (mantissa & 0x3ff);
3000 ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
3004 ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
3008 TRACE("Surface %p, container %p of type %#x.\n",
3009 surface, surface->container.u.base, surface->container.type);
3011 switch (surface->container.type)
3013 case WINED3D_CONTAINER_TEXTURE:
3014 return wined3d_texture_incref(surface->container.u.texture);
3016 case WINED3D_CONTAINER_SWAPCHAIN:
3017 return wined3d_swapchain_incref(surface->container.u.swapchain);
3020 ERR("Unhandled container type %#x.\n", surface->container.type);
3021 case WINED3D_CONTAINER_NONE:
3025 refcount = InterlockedIncrement(&surface->resource.ref);
3026 TRACE("%p increasing refcount to %u.\n", surface, refcount);
3031 /* Do not call while under the GL lock. */
3032 ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
3036 TRACE("Surface %p, container %p of type %#x.\n",
3037 surface, surface->container.u.base, surface->container.type);
3039 switch (surface->container.type)
3041 case WINED3D_CONTAINER_TEXTURE:
3042 return wined3d_texture_decref(surface->container.u.texture);
3044 case WINED3D_CONTAINER_SWAPCHAIN:
3045 return wined3d_swapchain_decref(surface->container.u.swapchain);
3048 ERR("Unhandled container type %#x.\n", surface->container.type);
3049 case WINED3D_CONTAINER_NONE:
3053 refcount = InterlockedDecrement(&surface->resource.ref);
3054 TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3058 surface_cleanup(surface);
3059 surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3061 TRACE("Destroyed surface %p.\n", surface);
3062 HeapFree(GetProcessHeap(), 0, surface);
3068 DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
3070 return resource_set_priority(&surface->resource, priority);
3073 DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
3075 return resource_get_priority(&surface->resource);
3078 void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
3080 TRACE("surface %p.\n", surface);
3082 if (!surface->resource.device->d3d_initialized)
3084 ERR("D3D not initialized.\n");
3088 surface_internal_preload(surface, SRGB_ANY);
3091 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
3093 TRACE("surface %p.\n", surface);
3095 return surface->resource.parent;
3098 struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
3100 TRACE("surface %p.\n", surface);
3102 return &surface->resource;
3105 HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
3107 TRACE("surface %p, flags %#x.\n", surface, flags);
3111 case WINEDDGBS_CANBLT:
3112 case WINEDDGBS_ISBLTDONE:
3116 return WINED3DERR_INVALIDCALL;
3120 HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
3122 TRACE("surface %p, flags %#x.\n", surface, flags);
3124 /* XXX: DDERR_INVALIDSURFACETYPE */
3128 case WINEDDGFS_CANFLIP:
3129 case WINEDDGFS_ISFLIPDONE:
3133 return WINED3DERR_INVALIDCALL;
3137 HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
3139 TRACE("surface %p.\n", surface);
3141 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
3142 return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3145 HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
3147 TRACE("surface %p.\n", surface);
3149 surface->flags &= ~SFLAG_LOST;
3153 void CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
3155 TRACE("surface %p, palette %p.\n", surface, palette);
3157 if (surface->palette == palette)
3159 TRACE("Nop palette change.\n");
3163 if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
3164 surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3166 surface->palette = palette;
3170 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3171 palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
3173 surface->surface_ops->surface_realize_palette(surface);
3177 HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3178 DWORD flags, const struct wined3d_color_key *color_key)
3180 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3182 if (flags & WINEDDCKEY_COLORSPACE)
3184 FIXME(" colorkey value not supported (%08x) !\n", flags);
3185 return WINED3DERR_INVALIDCALL;
3188 /* Dirtify the surface, but only if a key was changed. */
3191 switch (flags & ~WINEDDCKEY_COLORSPACE)
3193 case WINEDDCKEY_DESTBLT:
3194 surface->dst_blt_color_key = *color_key;
3195 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3198 case WINEDDCKEY_DESTOVERLAY:
3199 surface->dst_overlay_color_key = *color_key;
3200 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3203 case WINEDDCKEY_SRCOVERLAY:
3204 surface->src_overlay_color_key = *color_key;
3205 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3208 case WINEDDCKEY_SRCBLT:
3209 surface->src_blt_color_key = *color_key;
3210 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3216 switch (flags & ~WINEDDCKEY_COLORSPACE)
3218 case WINEDDCKEY_DESTBLT:
3219 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3222 case WINEDDCKEY_DESTOVERLAY:
3223 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3226 case WINEDDCKEY_SRCOVERLAY:
3227 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3230 case WINEDDCKEY_SRCBLT:
3231 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3239 struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3241 TRACE("surface %p.\n", surface);
3243 return surface->palette;
3246 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3248 const struct wined3d_format *format = surface->resource.format;
3251 TRACE("surface %p.\n", surface);
3253 if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3255 /* Since compressed formats are block based, pitch means the amount of
3256 * bytes to the next row of block rather than the next row of pixels. */
3257 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3258 pitch = row_block_count * format->block_byte_count;
3262 unsigned char alignment = surface->resource.device->surface_alignment;
3263 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
3264 pitch = (pitch + alignment - 1) & ~(alignment - 1);
3267 TRACE("Returning %u.\n", pitch);
3272 HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem)
3274 TRACE("surface %p, mem %p.\n", surface, mem);
3276 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3278 WARN("Surface is mapped or the DC is in use.\n");
3279 return WINED3DERR_INVALIDCALL;
3282 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3283 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3285 ERR("Not supported on render targets.\n");
3286 return WINED3DERR_INVALIDCALL;
3289 if (mem && mem != surface->resource.allocatedMemory)
3291 void *release = NULL;
3293 /* Do I have to copy the old surface content? */
3294 if (surface->flags & SFLAG_DIBSECTION)
3296 DeleteDC(surface->hDC);
3297 DeleteObject(surface->dib.DIBsection);
3298 surface->dib.bitmap_data = NULL;
3299 surface->resource.allocatedMemory = NULL;
3300 surface->hDC = NULL;
3301 surface->flags &= ~SFLAG_DIBSECTION;
3303 else if (!(surface->flags & SFLAG_USERPTR))
3305 release = surface->resource.heapMemory;
3306 surface->resource.heapMemory = NULL;
3308 surface->resource.allocatedMemory = mem;
3309 surface->flags |= SFLAG_USERPTR;
3311 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3312 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3314 /* For client textures OpenGL has to be notified. */
3315 if (surface->flags & SFLAG_CLIENT)
3316 surface_release_client_storage(surface);
3318 /* Now free the old memory if any. */
3319 HeapFree(GetProcessHeap(), 0, release);
3321 else if (surface->flags & SFLAG_USERPTR)
3323 /* HeapMemory should be NULL already. */
3324 if (surface->resource.heapMemory)
3325 ERR("User pointer surface has heap memory allocated.\n");
3329 surface->resource.allocatedMemory = NULL;
3330 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3332 if (surface->flags & SFLAG_CLIENT)
3333 surface_release_client_storage(surface);
3335 surface_prepare_system_memory(surface);
3338 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3344 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3348 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3350 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3352 WARN("Not an overlay surface.\n");
3353 return WINEDDERR_NOTAOVERLAYSURFACE;
3356 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3357 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3358 surface->overlay_destrect.left = x;
3359 surface->overlay_destrect.top = y;
3360 surface->overlay_destrect.right = x + w;
3361 surface->overlay_destrect.bottom = y + h;
3363 surface_draw_overlay(surface);
3368 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3370 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3372 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3374 TRACE("Not an overlay surface.\n");
3375 return WINEDDERR_NOTAOVERLAYSURFACE;
3378 if (!surface->overlay_dest)
3380 TRACE("Overlay not visible.\n");
3383 return WINEDDERR_OVERLAYNOTVISIBLE;
3386 *x = surface->overlay_destrect.left;
3387 *y = surface->overlay_destrect.top;
3389 TRACE("Returning position %d, %d.\n", *x, *y);
3394 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3395 DWORD flags, struct wined3d_surface *ref)
3397 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3399 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3401 TRACE("Not an overlay surface.\n");
3402 return WINEDDERR_NOTAOVERLAYSURFACE;
3408 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3409 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3411 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3412 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3414 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3416 WARN("Not an overlay surface.\n");
3417 return WINEDDERR_NOTAOVERLAYSURFACE;
3419 else if (!dst_surface)
3421 WARN("Dest surface is NULL.\n");
3422 return WINED3DERR_INVALIDCALL;
3427 surface->overlay_srcrect = *src_rect;
3431 surface->overlay_srcrect.left = 0;
3432 surface->overlay_srcrect.top = 0;
3433 surface->overlay_srcrect.right = surface->resource.width;
3434 surface->overlay_srcrect.bottom = surface->resource.height;
3439 surface->overlay_destrect = *dst_rect;
3443 surface->overlay_destrect.left = 0;
3444 surface->overlay_destrect.top = 0;
3445 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3446 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3449 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3451 surface->overlay_dest = NULL;
3452 list_remove(&surface->overlay_entry);
3455 if (flags & WINEDDOVER_SHOW)
3457 if (surface->overlay_dest != dst_surface)
3459 surface->overlay_dest = dst_surface;
3460 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3463 else if (flags & WINEDDOVER_HIDE)
3465 /* tests show that the rectangles are erased on hide */
3466 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3467 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3468 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3469 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3470 surface->overlay_dest = NULL;
3473 surface_draw_overlay(surface);
3478 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3479 UINT width, UINT height, enum wined3d_format_id format_id,
3480 enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3482 struct wined3d_device *device = surface->resource.device;
3483 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3484 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3485 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3487 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3488 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3491 return WINED3DERR_INVALIDCALL;
3493 if (device->d3d_initialized)
3494 surface->resource.resource_ops->resource_unload(&surface->resource);
3496 if (surface->flags & SFLAG_DIBSECTION)
3498 DeleteDC(surface->hDC);
3499 DeleteObject(surface->dib.DIBsection);
3500 surface->dib.bitmap_data = NULL;
3501 surface->flags &= ~SFLAG_DIBSECTION;
3504 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3505 surface->resource.allocatedMemory = NULL;
3506 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3507 surface->resource.heapMemory = NULL;
3509 surface->resource.width = width;
3510 surface->resource.height = height;
3511 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3512 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3514 surface->pow2Width = width;
3515 surface->pow2Height = height;
3519 surface->pow2Width = surface->pow2Height = 1;
3520 while (surface->pow2Width < width)
3521 surface->pow2Width <<= 1;
3522 while (surface->pow2Height < height)
3523 surface->pow2Height <<= 1;
3526 if (surface->pow2Width != width || surface->pow2Height != height)
3527 surface->flags |= SFLAG_NONPOW2;
3529 surface->flags &= ~SFLAG_NONPOW2;
3531 surface->resource.format = format;
3532 surface->resource.multisample_type = multisample_type;
3533 surface->resource.multisample_quality = multisample_quality;
3534 surface->resource.size = resource_size;
3536 if (!surface_init_sysmem(surface))
3537 return E_OUTOFMEMORY;
3542 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3543 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3545 unsigned short *dst_s;
3549 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3551 for (y = 0; y < h; ++y)
3553 src_f = (const float *)(src + y * pitch_in);
3554 dst_s = (unsigned short *) (dst + y * pitch_out);
3555 for (x = 0; x < w; ++x)
3557 dst_s[x] = float_32_to_16(src_f + x);
3562 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3563 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3565 static const unsigned char convert_5to8[] =
3567 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3568 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3569 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3570 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3572 static const unsigned char convert_6to8[] =
3574 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3575 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3576 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3577 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3578 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3579 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3580 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3581 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3585 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3587 for (y = 0; y < h; ++y)
3589 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3590 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3591 for (x = 0; x < w; ++x)
3593 WORD pixel = src_line[x];
3594 dst_line[x] = 0xff000000
3595 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3596 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3597 | convert_5to8[(pixel & 0x001f)];
3602 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3603 * in both cases we're just setting the X / Alpha channel to 0xff. */
3604 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3605 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3609 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3611 for (y = 0; y < h; ++y)
3613 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3614 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3616 for (x = 0; x < w; ++x)
3618 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3623 static inline BYTE cliptobyte(int x)
3625 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3628 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3629 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3631 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3634 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3636 for (y = 0; y < h; ++y)
3638 const BYTE *src_line = src + y * pitch_in;
3639 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3640 for (x = 0; x < w; ++x)
3642 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3643 * C = Y - 16; D = U - 128; E = V - 128;
3644 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3645 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3646 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3647 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3648 * U and V are shared between the pixels. */
3649 if (!(x & 1)) /* For every even pixel, read new U and V. */
3651 d = (int) src_line[1] - 128;
3652 e = (int) src_line[3] - 128;
3654 g2 = - 100 * d - 208 * e + 128;
3657 c2 = 298 * ((int) src_line[0] - 16);
3658 dst_line[x] = 0xff000000
3659 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3660 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3661 | cliptobyte((c2 + b2) >> 8); /* blue */
3662 /* Scale RGB values to 0..255 range,
3663 * then clip them if still not in range (may be negative),
3664 * then shift them within DWORD if necessary. */
3670 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3671 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3674 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3676 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3678 for (y = 0; y < h; ++y)
3680 const BYTE *src_line = src + y * pitch_in;
3681 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3682 for (x = 0; x < w; ++x)
3684 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3685 * C = Y - 16; D = U - 128; E = V - 128;
3686 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3687 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3688 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3689 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3690 * U and V are shared between the pixels. */
3691 if (!(x & 1)) /* For every even pixel, read new U and V. */
3693 d = (int) src_line[1] - 128;
3694 e = (int) src_line[3] - 128;
3696 g2 = - 100 * d - 208 * e + 128;
3699 c2 = 298 * ((int) src_line[0] - 16);
3700 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3701 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3702 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3703 /* Scale RGB values to 0..255 range,
3704 * then clip them if still not in range (may be negative),
3705 * then shift them within DWORD if necessary. */
3711 struct d3dfmt_converter_desc
3713 enum wined3d_format_id from, to;
3714 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3717 static const struct d3dfmt_converter_desc converters[] =
3719 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3720 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3721 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3722 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3723 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3724 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3727 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
3728 enum wined3d_format_id to)
3732 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
3734 if (converters[i].from == from && converters[i].to == to)
3735 return &converters[i];
3741 /*****************************************************************************
3742 * surface_convert_format
3744 * Creates a duplicate of a surface in a different format. Is used by Blt to
3745 * blit between surfaces with different formats.
3748 * source: Source surface
3749 * fmt: Requested destination format
3751 *****************************************************************************/
3752 static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
3754 struct wined3d_map_desc src_map, dst_map;
3755 const struct d3dfmt_converter_desc *conv;
3756 struct wined3d_surface *ret = NULL;
3759 conv = find_converter(source->resource.format->id, to_fmt);
3762 FIXME("Cannot find a conversion function from format %s to %s.\n",
3763 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
3767 wined3d_surface_create(source->resource.device, source->resource.width,
3768 source->resource.height, to_fmt, 0 /* level */, 0 /* usage */, WINED3D_POOL_SCRATCH,
3769 WINED3D_MULTISAMPLE_NONE /* TODO: Multisampled conversion */, 0 /* MultiSampleQuality */,
3770 source->surface_type, WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD,
3771 NULL /* parent */, &wined3d_null_parent_ops, &ret);
3774 ERR("Failed to create a destination surface for conversion.\n");
3778 memset(&src_map, 0, sizeof(src_map));
3779 memset(&dst_map, 0, sizeof(dst_map));
3781 if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
3783 ERR("Failed to lock the source surface.\n");
3784 wined3d_surface_decref(ret);
3787 if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
3789 ERR("Failed to lock the destination surface.\n");
3790 wined3d_surface_unmap(source);
3791 wined3d_surface_decref(ret);
3795 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
3796 source->resource.width, source->resource.height);
3798 wined3d_surface_unmap(ret);
3799 wined3d_surface_unmap(source);
3804 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
3805 unsigned int bpp, UINT pitch, DWORD color)
3812 #define COLORFILL_ROW(type) \
3814 type *d = (type *)buf; \
3815 for (x = 0; x < width; ++x) \
3816 d[x] = (type)color; \
3822 COLORFILL_ROW(BYTE);
3826 COLORFILL_ROW(WORD);
3832 for (x = 0; x < width; ++x, d += 3)
3834 d[0] = (color ) & 0xff;
3835 d[1] = (color >> 8) & 0xff;
3836 d[2] = (color >> 16) & 0xff;
3841 COLORFILL_ROW(DWORD);
3845 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
3846 return WINED3DERR_NOTAVAILABLE;
3849 #undef COLORFILL_ROW
3851 /* Now copy first row. */
3853 for (y = 1; y < height; ++y)
3856 memcpy(buf, first, width * bpp);
3862 struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
3864 return surface_from_resource(resource);
3867 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
3869 TRACE("surface %p.\n", surface);
3871 if (!surface->resource.map_count)
3873 WARN("Trying to unmap unmapped surface.\n");
3874 return WINEDDERR_NOTLOCKED;
3876 --surface->resource.map_count;
3878 surface->surface_ops->surface_unmap(surface);
3883 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
3884 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
3886 const struct wined3d_format *format = surface->resource.format;
3888 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
3889 surface, map_desc, wine_dbgstr_rect(rect), flags);
3891 if (surface->resource.map_count)
3893 WARN("Surface is already mapped.\n");
3894 return WINED3DERR_INVALIDCALL;
3897 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
3898 && !surface_check_block_align(surface, rect))
3900 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
3901 wine_dbgstr_rect(rect), format->block_width, format->block_height);
3903 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
3904 return WINED3DERR_INVALIDCALL;
3907 ++surface->resource.map_count;
3909 if (!(surface->flags & SFLAG_LOCKABLE))
3910 WARN("Trying to lock unlockable surface.\n");
3912 /* Performance optimization: Count how often a surface is mapped, if it is
3913 * mapped regularly do not throw away the system memory copy. This avoids
3914 * the need to download the surface from OpenGL all the time. The surface
3915 * is still downloaded if the OpenGL texture is changed. */
3916 if (!(surface->flags & SFLAG_DYNLOCK))
3918 if (++surface->lockCount > MAXLOCKCOUNT)
3920 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3921 surface->flags |= SFLAG_DYNLOCK;
3925 surface->surface_ops->surface_map(surface, rect, flags);
3927 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
3928 map_desc->row_pitch = surface->resource.width * format->byte_count;
3930 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
3931 map_desc->slice_pitch = 0;
3935 map_desc->data = surface->resource.allocatedMemory;
3936 surface->lockedRect.left = 0;
3937 surface->lockedRect.top = 0;
3938 surface->lockedRect.right = surface->resource.width;
3939 surface->lockedRect.bottom = surface->resource.height;
3943 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
3945 /* Compressed textures are block based, so calculate the offset of
3946 * the block that contains the top-left pixel of the locked rectangle. */
3947 map_desc->data = surface->resource.allocatedMemory
3948 + ((rect->top / format->block_height) * map_desc->row_pitch)
3949 + ((rect->left / format->block_width) * format->block_byte_count);
3953 map_desc->data = surface->resource.allocatedMemory
3954 + (map_desc->row_pitch * rect->top)
3955 + (rect->left * format->byte_count);
3957 surface->lockedRect.left = rect->left;
3958 surface->lockedRect.top = rect->top;
3959 surface->lockedRect.right = rect->right;
3960 surface->lockedRect.bottom = rect->bottom;
3963 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3964 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
3969 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
3971 struct wined3d_map_desc map;
3974 TRACE("surface %p, dc %p.\n", surface, dc);
3976 if (surface->flags & SFLAG_USERPTR)
3978 ERR("Not supported on surfaces with application-provided memory.\n");
3979 return WINEDDERR_NODC;
3982 /* Give more detailed info for ddraw. */
3983 if (surface->flags & SFLAG_DCINUSE)
3984 return WINEDDERR_DCALREADYCREATED;
3986 /* Can't GetDC if the surface is locked. */
3987 if (surface->resource.map_count)
3988 return WINED3DERR_INVALIDCALL;
3990 /* Create a DIB section if there isn't a dc yet. */
3993 if (surface->flags & SFLAG_CLIENT)
3995 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3996 surface_release_client_storage(surface);
3998 hr = surface_create_dib_section(surface);
4000 return WINED3DERR_INVALIDCALL;
4002 /* Use the DIB section from now on if we are not using a PBO. */
4003 if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
4005 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
4006 surface->resource.heapMemory = NULL;
4007 surface->resource.allocatedMemory = surface->dib.bitmap_data;
4011 /* Map the surface. */
4012 hr = wined3d_surface_map(surface, &map, NULL, 0);
4015 ERR("Map failed, hr %#x.\n", hr);
4019 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4020 * activates the allocatedMemory. */
4021 if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4022 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4024 if (surface->resource.format->id == WINED3DFMT_P8_UINT
4025 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4027 /* GetDC on palettized formats is unsupported in D3D9, and the method
4028 * is missing in D3D8, so this should only be used for DX <=7
4029 * surfaces (with non-device palettes). */
4030 const PALETTEENTRY *pal = NULL;
4032 if (surface->palette)
4034 pal = surface->palette->palents;
4038 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4039 struct wined3d_surface *dds_primary = swapchain->front_buffer;
4041 if (dds_primary && dds_primary->palette)
4042 pal = dds_primary->palette->palents;
4050 for (i = 0; i < 256; ++i)
4052 col[i].rgbRed = pal[i].peRed;
4053 col[i].rgbGreen = pal[i].peGreen;
4054 col[i].rgbBlue = pal[i].peBlue;
4055 col[i].rgbReserved = 0;
4057 SetDIBColorTable(surface->hDC, 0, 256, col);
4061 surface->flags |= SFLAG_DCINUSE;
4064 TRACE("Returning dc %p.\n", *dc);
4069 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4071 TRACE("surface %p, dc %p.\n", surface, dc);
4073 if (!(surface->flags & SFLAG_DCINUSE))
4074 return WINEDDERR_NODC;
4076 if (surface->hDC != dc)
4078 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4080 return WINEDDERR_NODC;
4083 /* Copy the contents of the DIB over to the PBO. */
4084 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4085 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4087 /* We locked first, so unlock now. */
4088 wined3d_surface_unmap(surface);
4090 surface->flags &= ~SFLAG_DCINUSE;
4095 HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4097 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4103 FIXME("Ignoring flags %#x.\n", flags);
4105 WARN("Ignoring flags %#x.\n", flags);
4108 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
4110 ERR("Not supported on swapchain surfaces.\n");
4111 return WINEDDERR_NOTFLIPPABLE;
4114 /* Flipping is only supported on render targets and overlays. */
4115 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
4117 WARN("Tried to flip a non-render target, non-overlay surface.\n");
4118 return WINEDDERR_NOTFLIPPABLE;
4121 flip_surface(surface, override);
4123 /* Update overlays if they're visible. */
4124 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4125 return surface_draw_overlay(surface);
4130 /* Do not call while under the GL lock. */
4131 void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4133 struct wined3d_device *device = surface->resource.device;
4135 TRACE("iface %p, srgb %#x.\n", surface, srgb);
4137 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4139 struct wined3d_texture *texture = surface->container.u.texture;
4141 TRACE("Passing to container (%p).\n", texture);
4142 texture->texture_ops->texture_preload(texture, srgb);
4146 struct wined3d_context *context;
4148 TRACE("(%p) : About to load surface\n", surface);
4150 /* TODO: Use already acquired context when possible. */
4151 context = context_acquire(device, NULL);
4153 surface_load(surface, srgb == SRGB_SRGB);
4155 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4157 /* Tell opengl to try and keep this texture in video ram (well mostly) */
4161 context->gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &surface->texture_name, &tmp);
4165 context_release(context);
4169 /* Read the framebuffer back into the surface */
4170 static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4172 struct wined3d_device *device = surface->resource.device;
4173 const struct wined3d_gl_info *gl_info;
4174 struct wined3d_context *context;
4178 BYTE *row, *top, *bottom;
4182 BOOL srcIsUpsideDown;
4187 context = context_acquire(device, surface);
4188 context_apply_blit_state(context, device);
4189 gl_info = context->gl_info;
4193 /* Select the correct read buffer, and give some debug output.
4194 * There is no need to keep track of the current read buffer or reset it, every part of the code
4195 * that reads sets the read buffer as desired.
4197 if (surface_is_offscreen(surface))
4199 /* Mapping the primary render target which is not on a swapchain.
4200 * Read from the back buffer. */
4201 TRACE("Mapping offscreen render target.\n");
4202 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4203 srcIsUpsideDown = TRUE;
4207 /* Onscreen surfaces are always part of a swapchain */
4208 GLenum buffer = surface_get_gl_buffer(surface);
4209 TRACE("Mapping %#x buffer.\n", buffer);
4210 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
4211 checkGLcall("glReadBuffer");
4212 srcIsUpsideDown = FALSE;
4215 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4218 local_rect.left = 0;
4220 local_rect.right = surface->resource.width;
4221 local_rect.bottom = surface->resource.height;
4227 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4229 switch (surface->resource.format->id)
4231 case WINED3DFMT_P8_UINT:
4233 if (primary_render_target_is_p8(device))
4235 /* In case of P8 render targets the index is stored in the alpha component */
4237 type = GL_UNSIGNED_BYTE;
4239 bpp = surface->resource.format->byte_count;
4243 /* GL can't return palettized data, so read ARGB pixels into a
4244 * separate block of memory and convert them into palettized format
4245 * in software. Slow, but if the app means to use palettized render
4246 * targets and locks it...
4248 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4249 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4250 * for the color channels when palettizing the colors.
4253 type = GL_UNSIGNED_BYTE;
4255 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4258 ERR("Out of memory\n");
4262 bpp = surface->resource.format->byte_count * 3;
4269 fmt = surface->resource.format->glFormat;
4270 type = surface->resource.format->glType;
4271 bpp = surface->resource.format->byte_count;
4274 if (surface->flags & SFLAG_PBO)
4276 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4277 checkGLcall("glBindBufferARB");
4280 ERR("mem not null for pbo -- unexpected\n");
4285 /* Save old pixel store pack state */
4286 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4287 checkGLcall("glGetIntegerv");
4288 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4289 checkGLcall("glGetIntegerv");
4290 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4291 checkGLcall("glGetIntegerv");
4293 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4294 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4295 checkGLcall("glPixelStorei");
4296 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4297 checkGLcall("glPixelStorei");
4298 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4299 checkGLcall("glPixelStorei");
4301 gl_info->gl_ops.gl.p_glReadPixels(local_rect.left,
4302 !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4303 local_rect.right - local_rect.left,
4304 local_rect.bottom - local_rect.top,
4306 checkGLcall("glReadPixels");
4308 /* Reset previous pixel store pack state */
4309 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4310 checkGLcall("glPixelStorei");
4311 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4312 checkGLcall("glPixelStorei");
4313 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4314 checkGLcall("glPixelStorei");
4316 if (surface->flags & SFLAG_PBO)
4318 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4319 checkGLcall("glBindBufferARB");
4321 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4322 * to get a pointer to it and perform the flipping in software. This is a lot
4323 * faster than calling glReadPixels for each line. In case we want more speed
4324 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4325 if (!srcIsUpsideDown)
4327 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4328 checkGLcall("glBindBufferARB");
4330 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4331 checkGLcall("glMapBufferARB");
4335 /* TODO: Merge this with the palettization loop below for P8 targets */
4336 if(!srcIsUpsideDown) {
4338 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4339 Flip the lines in software */
4340 len = (local_rect.right - local_rect.left) * bpp;
4341 off = local_rect.left * bpp;
4343 row = HeapAlloc(GetProcessHeap(), 0, len);
4345 ERR("Out of memory\n");
4346 if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4347 HeapFree(GetProcessHeap(), 0, mem);
4352 top = mem + pitch * local_rect.top;
4353 bottom = mem + pitch * (local_rect.bottom - 1);
4354 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4355 memcpy(row, top + off, len);
4356 memcpy(top + off, bottom + off, len);
4357 memcpy(bottom + off, row, len);
4361 HeapFree(GetProcessHeap(), 0, row);
4363 /* Unmap the temp PBO buffer */
4364 if (surface->flags & SFLAG_PBO)
4366 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4367 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4372 context_release(context);
4374 /* For P8 textures we need to perform an inverse palette lookup. This is
4375 * done by searching for a palette index which matches the RGB value.
4376 * Note this isn't guaranteed to work when there are multiple entries for
4377 * the same color but we have no choice. In case of P8 render targets,
4378 * the index is stored in the alpha component so no conversion is needed. */
4379 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4381 const PALETTEENTRY *pal = NULL;
4382 DWORD width = pitch / 3;
4385 if (surface->palette)
4387 pal = surface->palette->palents;
4391 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4392 HeapFree(GetProcessHeap(), 0, mem);
4396 for(y = local_rect.top; y < local_rect.bottom; y++) {
4397 for(x = local_rect.left; x < local_rect.right; x++) {
4398 /* start lines pixels */
4399 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4400 const BYTE *green = blue + 1;
4401 const BYTE *red = green + 1;
4403 for(c = 0; c < 256; c++) {
4404 if(*red == pal[c].peRed &&
4405 *green == pal[c].peGreen &&
4406 *blue == pal[c].peBlue)
4408 *((BYTE *) dest + y * width + x) = c;
4414 HeapFree(GetProcessHeap(), 0, mem);
4418 /* Read the framebuffer contents into a texture. Note that this function
4419 * doesn't do any kind of flipping. Using this on an onscreen surface will
4420 * result in a flipped D3D texture. */
4421 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4423 struct wined3d_device *device = surface->resource.device;
4424 const struct wined3d_gl_info *gl_info;
4425 struct wined3d_context *context;
4427 context = context_acquire(device, surface);
4428 gl_info = context->gl_info;
4429 device_invalidate_state(device, STATE_FRAMEBUFFER);
4431 surface_prepare_texture(surface, context, srgb);
4432 surface_bind_and_dirtify(surface, context, srgb);
4434 TRACE("Reading back offscreen render target %p.\n", surface);
4438 if (surface_is_offscreen(surface))
4439 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4441 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
4442 checkGLcall("glReadBuffer");
4444 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4445 0, 0, 0, 0, surface->resource.width, surface->resource.height);
4446 checkGLcall("glCopyTexSubImage2D");
4450 context_release(context);
4453 /* Context activation is done by the caller. */
4454 static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4455 struct wined3d_context *context, BOOL srgb)
4457 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4458 enum wined3d_conversion_type convert;
4459 struct wined3d_format format;
4461 if (surface->flags & alloc_flag) return;
4463 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4464 if (convert != WINED3D_CT_NONE || format.convert)
4465 surface->flags |= SFLAG_CONVERTED;
4466 else surface->flags &= ~SFLAG_CONVERTED;
4468 surface_bind_and_dirtify(surface, context, srgb);
4469 surface_allocate_surface(surface, context->gl_info, &format, srgb);
4470 surface->flags |= alloc_flag;
4473 /* Context activation is done by the caller. */
4474 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4476 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4478 struct wined3d_texture *texture = surface->container.u.texture;
4479 UINT sub_count = texture->level_count * texture->layer_count;
4482 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4484 for (i = 0; i < sub_count; ++i)
4486 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4487 surface_prepare_texture_internal(s, context, srgb);
4493 surface_prepare_texture_internal(surface, context, srgb);
4496 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4500 if (surface->rb_multisample)
4503 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4504 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4505 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4506 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4507 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4511 if (surface->rb_resolved)
4514 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4515 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4516 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4517 surface->pow2Width, surface->pow2Height);
4518 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4522 static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4523 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4525 struct wined3d_device *device = surface->resource.device;
4526 UINT pitch = wined3d_surface_get_pitch(surface);
4527 const struct wined3d_gl_info *gl_info;
4528 struct wined3d_context *context;
4532 surface_get_rect(surface, rect, &local_rect);
4534 mem += local_rect.top * pitch + local_rect.left * bpp;
4535 w = local_rect.right - local_rect.left;
4536 h = local_rect.bottom - local_rect.top;
4538 /* Activate the correct context for the render target */
4539 context = context_acquire(device, surface);
4540 context_apply_blit_state(context, device);
4541 gl_info = context->gl_info;
4545 if (!surface_is_offscreen(surface))
4547 GLenum buffer = surface_get_gl_buffer(surface);
4548 TRACE("Unlocking %#x buffer.\n", buffer);
4549 context_set_draw_buffer(context, buffer);
4551 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4552 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, -1.0f);
4556 /* Primary offscreen render target */
4557 TRACE("Offscreen render target.\n");
4558 context_set_draw_buffer(context, device->offscreenBuffer);
4560 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, 1.0f);
4563 gl_info->gl_ops.gl.p_glRasterPos3i(local_rect.left, local_rect.top, 1);
4564 checkGLcall("glRasterPos3i");
4566 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4567 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4569 if (surface->flags & SFLAG_PBO)
4571 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4572 checkGLcall("glBindBufferARB");
4575 gl_info->gl_ops.gl.p_glDrawPixels(w, h, fmt, type, mem);
4576 checkGLcall("glDrawPixels");
4578 if (surface->flags & SFLAG_PBO)
4580 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4581 checkGLcall("glBindBufferARB");
4584 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4585 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4589 if (wined3d_settings.strict_draw_ordering
4590 || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4591 && surface->container.u.swapchain->front_buffer == surface))
4592 gl_info->gl_ops.gl.p_glFlush();
4594 context_release(context);
4597 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4599 /* FIXME: Is this really how color keys are supposed to work? I think it
4600 * makes more sense to compare the individual channels. */
4601 return color >= color_key->color_space_low_value
4602 && color <= color_key->color_space_high_value;
4605 void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4607 const struct wined3d_device *device = surface->resource.device;
4608 const struct wined3d_palette *pal = surface->palette;
4609 BOOL index_in_alpha = FALSE;
4612 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4613 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4614 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4615 * duplicate entries. Store the color key in the unused alpha component to speed the
4616 * download up and to make conversion unneeded. */
4617 index_in_alpha = primary_render_target_is_p8(device);
4621 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4624 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4625 * there's no palette at this time. */
4626 for (i = 0; i < 256; i++) table[i][3] = i;
4631 TRACE("Using surface palette %p\n", pal);
4632 /* Get the surface's palette */
4633 for (i = 0; i < 256; ++i)
4635 table[i][0] = pal->palents[i].peRed;
4636 table[i][1] = pal->palents[i].peGreen;
4637 table[i][2] = pal->palents[i].peBlue;
4639 /* When index_in_alpha is set the palette index is stored in the
4640 * alpha component. In case of a readback we can then read
4641 * GL_ALPHA. Color keying is handled in BltOverride using a
4642 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4643 * color key itself is passed to glAlphaFunc in other cases the
4644 * alpha component of pixels that should be masked away is set to 0. */
4647 else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4649 else if (pal->flags & WINEDDPCAPS_ALPHA)
4650 table[i][3] = pal->palents[i].peFlags;
4657 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4658 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4663 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4664 src, dst, pitch, width, height, outpitch, conversion_type, surface);
4666 switch (conversion_type)
4668 case WINED3D_CT_NONE:
4670 memcpy(dst, src, pitch * height);
4674 case WINED3D_CT_PALETTED:
4675 case WINED3D_CT_PALETTED_CK:
4680 d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4682 for (y = 0; y < height; y++)
4684 source = src + pitch * y;
4685 dest = dst + outpitch * y;
4686 /* This is an 1 bpp format, using the width here is fine */
4687 for (x = 0; x < width; x++) {
4688 BYTE color = *source++;
4689 *dest++ = table[color][0];
4690 *dest++ = table[color][1];
4691 *dest++ = table[color][2];
4692 *dest++ = table[color][3];
4698 case WINED3D_CT_CK_565:
4700 /* Converting the 565 format in 5551 packed to emulate color-keying.
4702 Note : in all these conversion, it would be best to average the averaging
4703 pixels to get the color of the pixel that will be color-keyed to
4704 prevent 'color bleeding'. This will be done later on if ever it is
4707 Note2: Nvidia documents say that their driver does not support alpha + color keying
4708 on the same surface and disables color keying in such a case
4714 TRACE("Color keyed 565\n");
4716 for (y = 0; y < height; y++) {
4717 Source = (const WORD *)(src + y * pitch);
4718 Dest = (WORD *) (dst + y * outpitch);
4719 for (x = 0; x < width; x++ ) {
4720 WORD color = *Source++;
4721 *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
4722 if (!color_in_range(&surface->src_blt_color_key, color))
4730 case WINED3D_CT_CK_5551:
4732 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4736 TRACE("Color keyed 5551\n");
4737 for (y = 0; y < height; y++) {
4738 Source = (const WORD *)(src + y * pitch);
4739 Dest = (WORD *) (dst + y * outpitch);
4740 for (x = 0; x < width; x++ ) {
4741 WORD color = *Source++;
4743 if (!color_in_range(&surface->src_blt_color_key, color))
4746 *Dest &= ~(1 << 15);
4753 case WINED3D_CT_CK_RGB24:
4755 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4757 for (y = 0; y < height; y++)
4759 source = src + pitch * y;
4760 dest = dst + outpitch * y;
4761 for (x = 0; x < width; x++) {
4762 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4763 DWORD dstcolor = color << 8;
4764 if (!color_in_range(&surface->src_blt_color_key, color))
4766 *(DWORD*)dest = dstcolor;
4774 case WINED3D_CT_RGB32_888:
4776 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4778 for (y = 0; y < height; y++)
4780 source = src + pitch * y;
4781 dest = dst + outpitch * y;
4782 for (x = 0; x < width; x++) {
4783 DWORD color = 0xffffff & *(const DWORD*)source;
4784 DWORD dstcolor = color << 8;
4785 if (!color_in_range(&surface->src_blt_color_key, color))
4787 *(DWORD*)dest = dstcolor;
4795 case WINED3D_CT_CK_ARGB32:
4798 for (y = 0; y < height; ++y)
4800 source = src + pitch * y;
4801 dest = dst + outpitch * y;
4802 for (x = 0; x < width; ++x)
4804 DWORD color = *(const DWORD *)source;
4805 if (color_in_range(&surface->src_blt_color_key, color))
4806 color &= ~0xff000000;
4807 *(DWORD*)dest = color;
4816 ERR("Unsupported conversion type %#x.\n", conversion_type);
4821 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
4823 /* Flip the surface contents */
4828 front->hDC = back->hDC;
4832 /* Flip the DIBsection */
4834 HBITMAP tmp = front->dib.DIBsection;
4835 front->dib.DIBsection = back->dib.DIBsection;
4836 back->dib.DIBsection = tmp;
4839 /* Flip the surface data */
4843 tmp = front->dib.bitmap_data;
4844 front->dib.bitmap_data = back->dib.bitmap_data;
4845 back->dib.bitmap_data = tmp;
4847 tmp = front->resource.allocatedMemory;
4848 front->resource.allocatedMemory = back->resource.allocatedMemory;
4849 back->resource.allocatedMemory = tmp;
4851 tmp = front->resource.heapMemory;
4852 front->resource.heapMemory = back->resource.heapMemory;
4853 back->resource.heapMemory = tmp;
4858 GLuint tmp_pbo = front->pbo;
4859 front->pbo = back->pbo;
4860 back->pbo = tmp_pbo;
4863 /* Flip the opengl texture */
4867 tmp = back->texture_name;
4868 back->texture_name = front->texture_name;
4869 front->texture_name = tmp;
4871 tmp = back->texture_name_srgb;
4872 back->texture_name_srgb = front->texture_name_srgb;
4873 front->texture_name_srgb = tmp;
4875 tmp = back->rb_multisample;
4876 back->rb_multisample = front->rb_multisample;
4877 front->rb_multisample = tmp;
4879 tmp = back->rb_resolved;
4880 back->rb_resolved = front->rb_resolved;
4881 front->rb_resolved = tmp;
4883 resource_unload(&back->resource);
4884 resource_unload(&front->resource);
4888 DWORD tmp_flags = back->flags;
4889 back->flags = front->flags;
4890 front->flags = tmp_flags;
4894 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4895 * pixel copy calls. */
4896 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
4897 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
4899 struct wined3d_device *device = dst_surface->resource.device;
4900 const struct wined3d_gl_info *gl_info;
4903 struct wined3d_context *context;
4904 BOOL upsidedown = FALSE;
4905 RECT dst_rect = *dst_rect_in;
4908 if (dst_surface->container.type == WINED3D_CONTAINER_TEXTURE)
4909 dst_target = dst_surface->container.u.texture->target;
4911 dst_target = dst_surface->texture_target;
4913 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4914 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4916 if(dst_rect.top > dst_rect.bottom) {
4917 UINT tmp = dst_rect.bottom;
4918 dst_rect.bottom = dst_rect.top;
4923 context = context_acquire(device, src_surface);
4924 gl_info = context->gl_info;
4925 context_apply_blit_state(context, device);
4926 surface_internal_preload(dst_surface, SRGB_RGB);
4929 /* Bind the target texture */
4930 context_bind_texture(context, dst_target, dst_surface->texture_name);
4931 if (surface_is_offscreen(src_surface))
4933 TRACE("Reading from an offscreen target\n");
4934 upsidedown = !upsidedown;
4935 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4939 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
4941 checkGLcall("glReadBuffer");
4943 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
4944 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
4946 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4948 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4950 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4951 ERR("Texture filtering not supported in direct blit.\n");
4953 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4954 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4956 ERR("Texture filtering not supported in direct blit\n");
4960 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4961 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4963 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
4964 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4965 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
4966 src_rect->left, src_surface->resource.height - src_rect->bottom,
4967 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4971 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
4972 /* I have to process this row by row to swap the image,
4973 * otherwise it would be upside down, so stretching in y direction
4974 * doesn't cost extra time
4976 * However, stretching in x direction can be avoided if not necessary
4978 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
4979 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4981 /* Well, that stuff works, but it's very slow.
4982 * find a better way instead
4986 for (col = dst_rect.left; col < dst_rect.right; ++col)
4988 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4989 dst_rect.left + col /* x offset */, row /* y offset */,
4990 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
4995 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4996 dst_rect.left /* x offset */, row /* y offset */,
4997 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
5001 checkGLcall("glCopyTexSubImage2D");
5004 context_release(context);
5006 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5007 * path is never entered
5009 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5012 /* Uses the hardware to stretch and flip the image */
5013 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5014 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5016 struct wined3d_device *device = dst_surface->resource.device;
5017 struct wined3d_swapchain *src_swapchain = NULL;
5018 GLuint src, backup = 0;
5019 float left, right, top, bottom; /* Texture coordinates */
5020 UINT fbwidth = src_surface->resource.width;
5021 UINT fbheight = src_surface->resource.height;
5022 const struct wined3d_gl_info *gl_info;
5023 struct wined3d_context *context;
5024 GLenum drawBuffer = GL_BACK;
5025 GLenum texture_target;
5026 BOOL noBackBufferBackup;
5028 BOOL upsidedown = FALSE;
5029 RECT dst_rect = *dst_rect_in;
5031 TRACE("Using hwstretch blit\n");
5032 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5033 context = context_acquire(device, src_surface);
5034 gl_info = context->gl_info;
5035 context_apply_blit_state(context, device);
5036 surface_internal_preload(dst_surface, SRGB_RGB);
5038 src_offscreen = surface_is_offscreen(src_surface);
5039 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5040 if (!noBackBufferBackup && !src_surface->texture_name)
5042 /* Get it a description */
5043 surface_internal_preload(src_surface, SRGB_RGB);
5047 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5048 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5050 if (context->aux_buffers >= 2)
5052 /* Got more than one aux buffer? Use the 2nd aux buffer */
5053 drawBuffer = GL_AUX1;
5055 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5057 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5058 drawBuffer = GL_AUX0;
5061 if (noBackBufferBackup)
5063 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
5064 checkGLcall("glGenTextures");
5065 context_bind_texture(context, GL_TEXTURE_2D, backup);
5066 texture_target = GL_TEXTURE_2D;
5070 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5071 * we are reading from the back buffer, the backup can be used as source texture
5073 texture_target = src_surface->texture_target;
5074 context_bind_texture(context, texture_target, src_surface->texture_name);
5075 gl_info->gl_ops.gl.p_glEnable(texture_target);
5076 checkGLcall("glEnable(texture_target)");
5078 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5079 src_surface->flags &= ~SFLAG_INTEXTURE;
5082 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5083 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5085 if(dst_rect.top > dst_rect.bottom) {
5086 UINT tmp = dst_rect.bottom;
5087 dst_rect.bottom = dst_rect.top;
5094 TRACE("Reading from an offscreen target\n");
5095 upsidedown = !upsidedown;
5096 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5100 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5103 /* TODO: Only back up the part that will be overwritten */
5104 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
5106 checkGLcall("glCopyTexSubImage2D");
5108 /* No issue with overriding these - the sampler is dirty due to blit usage */
5109 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5110 wined3d_gl_mag_filter(magLookup, filter));
5111 checkGLcall("glTexParameteri");
5112 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5113 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5114 checkGLcall("glTexParameteri");
5116 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5117 src_swapchain = src_surface->container.u.swapchain;
5118 if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
5120 src = backup ? backup : src_surface->texture_name;
5124 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
5125 checkGLcall("glReadBuffer(GL_FRONT)");
5127 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
5128 checkGLcall("glGenTextures(1, &src)");
5129 context_bind_texture(context, GL_TEXTURE_2D, src);
5131 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5132 * out for power of 2 sizes
5134 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5135 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5136 checkGLcall("glTexImage2D");
5137 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
5139 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5140 checkGLcall("glTexParameteri");
5141 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5142 checkGLcall("glTexParameteri");
5144 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
5145 checkGLcall("glReadBuffer(GL_BACK)");
5147 if (texture_target != GL_TEXTURE_2D)
5149 gl_info->gl_ops.gl.p_glDisable(texture_target);
5150 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5151 texture_target = GL_TEXTURE_2D;
5154 checkGLcall("glEnd and previous");
5156 left = src_rect->left;
5157 right = src_rect->right;
5161 top = src_surface->resource.height - src_rect->top;
5162 bottom = src_surface->resource.height - src_rect->bottom;
5166 top = src_surface->resource.height - src_rect->bottom;
5167 bottom = src_surface->resource.height - src_rect->top;
5170 if (src_surface->flags & SFLAG_NORMCOORD)
5172 left /= src_surface->pow2Width;
5173 right /= src_surface->pow2Width;
5174 top /= src_surface->pow2Height;
5175 bottom /= src_surface->pow2Height;
5178 /* draw the source texture stretched and upside down. The correct surface is bound already */
5179 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5180 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5182 context_set_draw_buffer(context, drawBuffer);
5183 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
5185 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5187 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
5188 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5191 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
5192 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
5195 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
5196 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5199 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
5200 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
5201 gl_info->gl_ops.gl.p_glEnd();
5202 checkGLcall("glEnd and previous");
5204 if (texture_target != dst_surface->texture_target)
5206 gl_info->gl_ops.gl.p_glDisable(texture_target);
5207 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
5208 texture_target = dst_surface->texture_target;
5211 /* Now read the stretched and upside down image into the destination texture */
5212 context_bind_texture(context, texture_target, dst_surface->texture_name);
5213 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
5215 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5216 0, 0, /* We blitted the image to the origin */
5217 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5218 checkGLcall("glCopyTexSubImage2D");
5220 if (drawBuffer == GL_BACK)
5222 /* Write the back buffer backup back. */
5225 if (texture_target != GL_TEXTURE_2D)
5227 gl_info->gl_ops.gl.p_glDisable(texture_target);
5228 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5229 texture_target = GL_TEXTURE_2D;
5231 context_bind_texture(context, GL_TEXTURE_2D, backup);
5235 if (texture_target != src_surface->texture_target)
5237 gl_info->gl_ops.gl.p_glDisable(texture_target);
5238 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
5239 texture_target = src_surface->texture_target;
5241 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5244 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5246 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
5247 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
5250 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5251 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5254 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5255 (float)fbheight / (float)src_surface->pow2Height);
5256 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
5259 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5260 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
5261 gl_info->gl_ops.gl.p_glEnd();
5263 gl_info->gl_ops.gl.p_glDisable(texture_target);
5264 checkGLcall("glDisable(texture_target)");
5267 if (src != src_surface->texture_name && src != backup)
5269 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
5270 checkGLcall("glDeleteTextures(1, &src)");
5274 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
5275 checkGLcall("glDeleteTextures(1, &backup)");
5280 if (wined3d_settings.strict_draw_ordering)
5281 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5283 context_release(context);
5285 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5286 * path is never entered
5288 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5291 /* Front buffer coordinates are always full screen coordinates, but our GL
5292 * drawable is limited to the window's client area. The sysmem and texture
5293 * copies do have the full screen size. Note that GL has a bottom-left
5294 * origin, while D3D has a top-left origin. */
5295 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5297 UINT drawable_height;
5299 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5300 && surface == surface->container.u.swapchain->front_buffer)
5302 POINT offset = {0, 0};
5305 ScreenToClient(window, &offset);
5306 OffsetRect(rect, offset.x, offset.y);
5308 GetClientRect(window, &windowsize);
5309 drawable_height = windowsize.bottom - windowsize.top;
5313 drawable_height = surface->resource.height;
5316 rect->top = drawable_height - rect->top;
5317 rect->bottom = drawable_height - rect->bottom;
5320 static void surface_blt_to_drawable(const struct wined3d_device *device,
5321 enum wined3d_texture_filter_type filter, BOOL color_key,
5322 struct wined3d_surface *src_surface, const RECT *src_rect_in,
5323 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5325 const struct wined3d_gl_info *gl_info;
5326 struct wined3d_context *context;
5327 RECT src_rect, dst_rect;
5329 src_rect = *src_rect_in;
5330 dst_rect = *dst_rect_in;
5332 /* Make sure the surface is up-to-date. This should probably use
5333 * surface_load_location() and worry about the destination surface too,
5334 * unless we're overwriting it completely. */
5335 surface_internal_preload(src_surface, SRGB_RGB);
5337 /* Activate the destination context, set it up for blitting */
5338 context = context_acquire(device, dst_surface);
5339 gl_info = context->gl_info;
5340 context_apply_blit_state(context, device);
5342 if (!surface_is_offscreen(dst_surface))
5343 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5345 device->blitter->set_shader(device->blit_priv, context, src_surface);
5351 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
5352 checkGLcall("glEnable(GL_ALPHA_TEST)");
5354 /* When the primary render target uses P8, the alpha component
5355 * contains the palette index. Which means that the colorkey is one of
5356 * the palette entries. In other cases pixels that should be masked
5357 * away have alpha set to 0. */
5358 if (primary_render_target_is_p8(device))
5359 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
5360 (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5362 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
5363 checkGLcall("glAlphaFunc");
5367 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5368 checkGLcall("glDisable(GL_ALPHA_TEST)");
5371 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5375 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5376 checkGLcall("glDisable(GL_ALPHA_TEST)");
5381 /* Leave the opengl state valid for blitting */
5382 device->blitter->unset_shader(context->gl_info);
5384 if (wined3d_settings.strict_draw_ordering
5385 || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5386 && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5387 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5389 context_release(context);
5392 /* Do not call while under the GL lock. */
5393 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5395 struct wined3d_device *device = s->resource.device;
5396 const struct blit_shader *blitter;
5398 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5399 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5402 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5403 return WINED3DERR_INVALIDCALL;
5406 return blitter->color_fill(device, s, rect, color);
5409 /* Do not call while under the GL lock. */
5410 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5411 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5412 enum wined3d_texture_filter_type filter)
5414 struct wined3d_device *device = dst_surface->resource.device;
5415 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5416 struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5418 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5419 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5420 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5422 /* Get the swapchain. One of the surfaces has to be a primary surface */
5423 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5425 WARN("Destination is in sysmem, rejecting gl blt\n");
5426 return WINED3DERR_INVALIDCALL;
5429 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5430 dstSwapchain = dst_surface->container.u.swapchain;
5434 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5436 WARN("Src is in sysmem, rejecting gl blt\n");
5437 return WINED3DERR_INVALIDCALL;
5440 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5441 srcSwapchain = src_surface->container.u.swapchain;
5444 /* Early sort out of cases where no render target is used */
5445 if (!dstSwapchain && !srcSwapchain
5446 && src_surface != device->fb.render_targets[0]
5447 && dst_surface != device->fb.render_targets[0])
5449 TRACE("No surface is render target, not using hardware blit.\n");
5450 return WINED3DERR_INVALIDCALL;
5453 /* No destination color keying supported */
5454 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5456 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5457 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5458 return WINED3DERR_INVALIDCALL;
5461 if (dstSwapchain && dstSwapchain == srcSwapchain)
5463 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5464 return WINED3DERR_INVALIDCALL;
5467 if (dstSwapchain && srcSwapchain)
5469 FIXME("Implement hardware blit between two different swapchains\n");
5470 return WINED3DERR_INVALIDCALL;
5475 /* Handled with regular texture -> swapchain blit */
5476 if (src_surface == device->fb.render_targets[0])
5477 TRACE("Blit from active render target to a swapchain\n");
5479 else if (srcSwapchain && dst_surface == device->fb.render_targets[0])
5481 FIXME("Implement blit from a swapchain to the active render target\n");
5482 return WINED3DERR_INVALIDCALL;
5485 if ((srcSwapchain || src_surface == device->fb.render_targets[0]) && !dstSwapchain)
5487 /* Blit from render target to texture */
5490 /* P8 read back is not implemented */
5491 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5492 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5494 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5495 return WINED3DERR_INVALIDCALL;
5498 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5500 TRACE("Color keying not supported by frame buffer to texture blit\n");
5501 return WINED3DERR_INVALIDCALL;
5502 /* Destination color key is checked above */
5505 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5510 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5511 * flip the image nor scale it.
5513 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5514 * -> If the app wants a image width an unscaled width, copy it line per line
5515 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5516 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5517 * back buffer. This is slower than reading line per line, thus not used for flipping
5518 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5519 * pixel by pixel. */
5520 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5521 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5523 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5524 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5528 TRACE("Using hardware stretching to flip / stretch the texture.\n");
5529 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5532 if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5534 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5535 dst_surface->resource.allocatedMemory = NULL;
5536 dst_surface->resource.heapMemory = NULL;
5540 dst_surface->flags &= ~SFLAG_INSYSMEM;
5545 else if (src_surface)
5547 /* Blit from offscreen surface to render target */
5548 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5549 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5551 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5553 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5554 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5555 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5557 FIXME("Unsupported blit operation falling back to software\n");
5558 return WINED3DERR_INVALIDCALL;
5561 /* Color keying: Check if we have to do a color keyed blt,
5562 * and if not check if a color key is activated.
5564 * Just modify the color keying parameters in the surface and restore them afterwards
5565 * The surface keeps track of the color key last used to load the opengl surface.
5566 * PreLoad will catch the change to the flags and color key and reload if necessary.
5568 if (flags & WINEDDBLT_KEYSRC)
5570 /* Use color key from surface */
5572 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5574 /* Use color key from DDBltFx */
5575 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5576 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5580 /* Do not use color key */
5581 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5584 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5585 src_surface, src_rect, dst_surface, dst_rect);
5587 /* Restore the color key parameters */
5588 src_surface->CKeyFlags = oldCKeyFlags;
5589 src_surface->src_blt_color_key = old_blt_key;
5591 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5596 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5597 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5598 return WINED3DERR_INVALIDCALL;
5601 /* GL locking is done by the caller */
5602 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5603 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5605 struct wined3d_device *device = surface->resource.device;
5606 const struct wined3d_gl_info *gl_info = context->gl_info;
5607 GLint compare_mode = GL_NONE;
5608 struct blt_info info;
5609 GLint old_binding = 0;
5612 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5614 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
5615 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
5616 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5617 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
5618 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
5619 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
5620 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
5621 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5622 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5623 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
5624 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
5626 SetRect(&rect, 0, h, w, 0);
5627 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5628 context_active_texture(context, context->gl_info, 0);
5629 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
5630 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
5631 if (gl_info->supported[ARB_SHADOW])
5633 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5634 if (compare_mode != GL_NONE)
5635 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5638 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5639 gl_info, info.tex_type, &surface->ds_current_size);
5641 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
5642 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
5643 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
5644 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
5645 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
5646 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
5647 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
5648 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
5649 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
5650 gl_info->gl_ops.gl.p_glEnd();
5652 if (compare_mode != GL_NONE)
5653 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5654 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
5656 gl_info->gl_ops.gl.p_glPopAttrib();
5658 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5661 void surface_modify_ds_location(struct wined3d_surface *surface,
5662 DWORD location, UINT w, UINT h)
5664 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5666 if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5667 FIXME("Invalid location (%#x) specified.\n", location);
5669 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5670 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5672 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5674 TRACE("Passing to container.\n");
5675 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5679 surface->ds_current_size.cx = w;
5680 surface->ds_current_size.cy = h;
5681 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5682 surface->flags |= location;
5685 /* Context activation is done by the caller. */
5686 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5688 const struct wined3d_gl_info *gl_info = context->gl_info;
5689 struct wined3d_device *device = surface->resource.device;
5692 TRACE("surface %p, new location %#x.\n", surface, location);
5694 /* TODO: Make this work for modes other than FBO */
5695 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5697 if (!(surface->flags & location))
5699 w = surface->ds_current_size.cx;
5700 h = surface->ds_current_size.cy;
5701 surface->ds_current_size.cx = 0;
5702 surface->ds_current_size.cy = 0;
5706 w = surface->resource.width;
5707 h = surface->resource.height;
5710 if (surface->ds_current_size.cx == surface->resource.width
5711 && surface->ds_current_size.cy == surface->resource.height)
5713 TRACE("Location (%#x) is already up to date.\n", location);
5717 if (surface->current_renderbuffer)
5719 FIXME("Not supported with fixed up depth stencil.\n");
5723 if (surface->flags & SFLAG_DISCARDED)
5725 TRACE("Surface was discarded, no need copy data.\n");
5728 case SFLAG_INTEXTURE:
5729 surface_prepare_texture(surface, context, FALSE);
5731 case SFLAG_INRB_MULTISAMPLE:
5732 surface_prepare_rb(surface, gl_info, TRUE);
5734 case SFLAG_INDRAWABLE:
5738 FIXME("Unhandled location %#x\n", location);
5740 surface->flags &= ~SFLAG_DISCARDED;
5741 surface->flags |= location;
5742 surface->ds_current_size.cx = surface->resource.width;
5743 surface->ds_current_size.cy = surface->resource.height;
5747 if (!(surface->flags & SFLAG_LOCATIONS))
5749 FIXME("No up to date depth stencil location.\n");
5750 surface->flags |= location;
5751 surface->ds_current_size.cx = surface->resource.width;
5752 surface->ds_current_size.cy = surface->resource.height;
5756 if (location == SFLAG_INTEXTURE)
5758 GLint old_binding = 0;
5761 /* The render target is allowed to be smaller than the depth/stencil
5762 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5763 * than the offscreen surface. Don't overwrite the offscreen surface
5764 * with undefined data. */
5765 w = min(w, context->swapchain->desc.backbuffer_width);
5766 h = min(h, context->swapchain->desc.backbuffer_height);
5768 TRACE("Copying onscreen depth buffer to depth texture.\n");
5772 if (!device->depth_blt_texture)
5773 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
5775 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5776 * directly on the FBO texture. That's because we need to flip. */
5777 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5778 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5779 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
5781 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5782 bind_target = GL_TEXTURE_RECTANGLE_ARB;
5786 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5787 bind_target = GL_TEXTURE_2D;
5789 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
5790 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5791 * internal format, because the internal format might include stencil
5792 * data. In principle we should copy stencil data as well, but unless
5793 * the driver supports stencil export it's hard to do, and doesn't
5794 * seem to be needed in practice. If the hardware doesn't support
5795 * writing stencil data, the glCopyTexImage2D() call might trigger
5796 * software fallbacks. */
5797 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
5798 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5799 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5800 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5801 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5802 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
5803 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5804 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
5806 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5807 NULL, surface, SFLAG_INTEXTURE);
5808 context_set_draw_buffer(context, GL_NONE);
5809 gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
5811 /* Do the actual blit */
5812 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
5813 checkGLcall("depth_blt");
5815 context_invalidate_state(context, STATE_FRAMEBUFFER);
5819 if (wined3d_settings.strict_draw_ordering)
5820 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5822 else if (location == SFLAG_INDRAWABLE)
5824 TRACE("Copying depth texture to onscreen depth buffer.\n");
5828 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5829 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5830 surface_depth_blt(surface, context, surface->texture_name,
5831 0, surface->pow2Height - h, w, h, surface->texture_target);
5832 checkGLcall("depth_blt");
5834 context_invalidate_state(context, STATE_FRAMEBUFFER);
5838 if (wined3d_settings.strict_draw_ordering)
5839 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5843 ERR("Invalid location (%#x) specified.\n", location);
5846 surface->flags |= location;
5847 surface->ds_current_size.cx = surface->resource.width;
5848 surface->ds_current_size.cy = surface->resource.height;
5851 void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
5853 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
5854 struct wined3d_surface *overlay;
5856 TRACE("surface %p, location %s, persistent %#x.\n",
5857 surface, debug_surflocation(location), persistent);
5859 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
5860 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
5861 && (location & SFLAG_INDRAWABLE))
5862 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5864 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
5865 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
5866 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
5870 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5871 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
5873 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5875 TRACE("Passing to container.\n");
5876 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5879 surface->flags &= ~SFLAG_LOCATIONS;
5880 surface->flags |= location;
5882 /* Redraw emulated overlays, if any */
5883 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
5885 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
5887 surface_draw_overlay(overlay);
5893 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
5895 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5897 TRACE("Passing to container\n");
5898 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5901 surface->flags &= ~location;
5904 if (!(surface->flags & SFLAG_LOCATIONS))
5906 ERR("Surface %p does not have any up to date location.\n", surface);
5910 static DWORD resource_access_from_location(DWORD location)
5914 case SFLAG_INSYSMEM:
5915 return WINED3D_RESOURCE_ACCESS_CPU;
5917 case SFLAG_INDRAWABLE:
5918 case SFLAG_INSRGBTEX:
5919 case SFLAG_INTEXTURE:
5920 case SFLAG_INRB_MULTISAMPLE:
5921 case SFLAG_INRB_RESOLVED:
5922 return WINED3D_RESOURCE_ACCESS_GPU;
5925 FIXME("Unhandled location %#x.\n", location);
5930 static void surface_load_sysmem(struct wined3d_surface *surface,
5931 const struct wined3d_gl_info *gl_info, const RECT *rect)
5933 surface_prepare_system_memory(surface);
5935 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
5936 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5938 /* Download the surface to system memory. */
5939 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
5941 struct wined3d_device *device = surface->resource.device;
5942 struct wined3d_context *context;
5944 /* TODO: Use already acquired context when possible. */
5945 context = context_acquire(device, NULL);
5947 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
5948 surface_download_data(surface, gl_info);
5950 context_release(context);
5955 if (surface->flags & SFLAG_INDRAWABLE)
5957 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
5958 wined3d_surface_get_pitch(surface));
5962 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
5963 surface, surface->flags & SFLAG_LOCATIONS);
5966 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
5967 const struct wined3d_gl_info *gl_info, const RECT *rect)
5969 struct wined3d_device *device = surface->resource.device;
5970 enum wined3d_conversion_type convert;
5971 struct wined3d_format format;
5975 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
5977 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5978 return WINED3DERR_INVALIDCALL;
5981 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
5982 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5984 if (surface->flags & SFLAG_INTEXTURE)
5988 surface_get_rect(surface, rect, &r);
5989 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
5994 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
5996 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5997 * path through sysmem. */
5998 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6001 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
6003 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6004 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
6006 if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
6008 struct wined3d_context *context;
6010 TRACE("Removing the pbo attached to surface %p.\n", surface);
6012 /* TODO: Use already acquired context when possible. */
6013 context = context_acquire(device, NULL);
6015 surface_remove_pbo(surface, gl_info);
6017 context_release(context);
6020 if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
6022 UINT height = surface->resource.height;
6023 UINT width = surface->resource.width;
6024 UINT src_pitch, dst_pitch;
6026 byte_count = format.conv_byte_count;
6027 src_pitch = wined3d_surface_get_pitch(surface);
6029 /* Stick to the alignment for the converted surface too, makes it
6030 * easier to load the surface. */
6031 dst_pitch = width * byte_count;
6032 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6034 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6036 ERR("Out of memory (%u).\n", dst_pitch * height);
6037 return E_OUTOFMEMORY;
6040 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6041 src_pitch, width, height, dst_pitch, convert, surface);
6043 surface->flags |= SFLAG_CONVERTED;
6047 surface->flags &= ~SFLAG_CONVERTED;
6048 mem = surface->resource.allocatedMemory;
6049 byte_count = format.byte_count;
6052 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6054 /* Don't delete PBO memory. */
6055 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6056 HeapFree(GetProcessHeap(), 0, mem);
6061 static HRESULT surface_load_texture(struct wined3d_surface *surface,
6062 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6064 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6065 struct wined3d_device *device = surface->resource.device;
6066 enum wined3d_conversion_type convert;
6067 struct wined3d_context *context;
6068 UINT width, src_pitch, dst_pitch;
6069 struct wined3d_bo_address data;
6070 struct wined3d_format format;
6071 POINT dst_point = {0, 0};
6074 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6075 && surface_is_offscreen(surface)
6076 && (surface->flags & SFLAG_INDRAWABLE))
6078 surface_load_fb_texture(surface, srgb);
6083 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6084 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6085 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6086 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6087 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6090 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6091 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6093 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6094 &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6099 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6100 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6101 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6102 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6103 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6105 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6106 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6107 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6109 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6110 &rect, surface, dst_location, &rect);
6115 /* Upload from system memory */
6117 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6118 TRUE /* We will use textures */, &format, &convert);
6122 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6124 /* Performance warning... */
6125 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6126 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6131 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6133 /* Performance warning... */
6134 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6135 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6139 if (!(surface->flags & SFLAG_INSYSMEM))
6141 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6142 /* Lets hope we get it from somewhere... */
6143 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6146 /* TODO: Use already acquired context when possible. */
6147 context = context_acquire(device, NULL);
6149 surface_prepare_texture(surface, context, srgb);
6150 surface_bind_and_dirtify(surface, context, srgb);
6152 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6154 surface->flags |= SFLAG_GLCKEY;
6155 surface->gl_color_key = surface->src_blt_color_key;
6157 else surface->flags &= ~SFLAG_GLCKEY;
6159 width = surface->resource.width;
6160 src_pitch = wined3d_surface_get_pitch(surface);
6162 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6163 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6165 if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6167 TRACE("Removing the pbo attached to surface %p.\n", surface);
6168 surface_remove_pbo(surface, gl_info);
6173 /* This code is entered for texture formats which need a fixup. */
6174 UINT height = surface->resource.height;
6176 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6177 dst_pitch = width * format.conv_byte_count;
6178 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6180 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6182 ERR("Out of memory (%u).\n", dst_pitch * height);
6183 context_release(context);
6184 return E_OUTOFMEMORY;
6186 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6187 format.byte_count = format.conv_byte_count;
6188 src_pitch = dst_pitch;
6190 else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6192 /* This code is only entered for color keying fixups */
6193 UINT height = surface->resource.height;
6195 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6196 dst_pitch = width * format.conv_byte_count;
6197 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6199 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6201 ERR("Out of memory (%u).\n", dst_pitch * height);
6202 context_release(context);
6203 return E_OUTOFMEMORY;
6205 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6206 width, height, dst_pitch, convert, surface);
6207 format.byte_count = format.conv_byte_count;
6208 src_pitch = dst_pitch;
6212 mem = surface->resource.allocatedMemory;
6215 data.buffer_object = surface->pbo;
6217 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6219 context_release(context);
6221 /* Don't delete PBO memory. */
6222 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6223 HeapFree(GetProcessHeap(), 0, mem);
6228 static void surface_multisample_resolve(struct wined3d_surface *surface)
6230 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6232 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6233 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6235 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6236 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6239 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6241 struct wined3d_device *device = surface->resource.device;
6242 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6245 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6247 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6249 if (location == SFLAG_INTEXTURE)
6251 struct wined3d_context *context = context_acquire(device, NULL);
6252 surface_load_ds_location(surface, context, location);
6253 context_release(context);
6258 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location));
6259 return WINED3DERR_INVALIDCALL;
6263 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6264 location = SFLAG_INTEXTURE;
6266 if (surface->flags & location)
6268 TRACE("Location already up to date.\n");
6270 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6271 && surface_need_pbo(surface, gl_info))
6272 surface_load_pbo(surface, gl_info);
6277 if (WARN_ON(d3d_surface))
6279 DWORD required_access = resource_access_from_location(location);
6280 if ((surface->resource.access_flags & required_access) != required_access)
6281 WARN("Operation requires %#x access, but surface only has %#x.\n",
6282 required_access, surface->resource.access_flags);
6285 if (!(surface->flags & SFLAG_LOCATIONS))
6287 ERR("Surface %p does not have any up to date location.\n", surface);
6288 surface->flags |= SFLAG_LOST;
6289 return WINED3DERR_DEVICELOST;
6294 case SFLAG_INSYSMEM:
6295 surface_load_sysmem(surface, gl_info, rect);
6298 case SFLAG_INDRAWABLE:
6299 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6303 case SFLAG_INRB_RESOLVED:
6304 surface_multisample_resolve(surface);
6307 case SFLAG_INTEXTURE:
6308 case SFLAG_INSRGBTEX:
6309 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6314 ERR("Don't know how to handle location %#x.\n", location);
6320 surface->flags |= location;
6322 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6323 surface_evict_sysmem(surface);
6326 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6327 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6329 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6335 BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6337 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6339 /* Not on a swapchain - must be offscreen */
6340 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6342 /* The front buffer is always onscreen */
6343 if (surface == swapchain->front_buffer) return FALSE;
6345 /* If the swapchain is rendered to an FBO, the backbuffer is
6346 * offscreen, otherwise onscreen */
6347 return swapchain->render_to_fbo;
6350 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6351 /* Context activation is done by the caller. */
6352 static void ffp_blit_free(struct wined3d_device *device) { }
6354 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6355 /* Context activation is done by the caller. */
6356 static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6359 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) != 0;
6362 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6363 target = surface->container.u.texture->target;
6365 target = surface->texture_target;
6367 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6369 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6371 GL_EXTCALL(glColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6375 /* Context activation is done by the caller. */
6376 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6378 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6379 const struct wined3d_gl_info *gl_info = context->gl_info;
6382 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6383 target = surface->container.u.texture->target;
6385 target = surface->texture_target;
6387 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6388 * else the surface is converted in software at upload time in LoadLocation.
6390 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6391 && gl_info->supported[EXT_PALETTED_TEXTURE])
6392 ffp_blit_p8_upload_palette(surface, gl_info);
6395 gl_info->gl_ops.gl.p_glEnable(target);
6396 checkGLcall("glEnable(target)");
6401 /* Context activation is done by the caller. */
6402 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6405 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
6406 checkGLcall("glDisable(GL_TEXTURE_2D)");
6407 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6409 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6410 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6412 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6414 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
6415 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6420 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6421 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6422 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6424 enum complex_fixup src_fixup;
6428 case WINED3D_BLIT_OP_COLOR_BLIT:
6429 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6432 src_fixup = get_complex_fixup(src_format->color_fixup);
6433 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6435 TRACE("Checking support for fixup:\n");
6436 dump_color_fixup_desc(src_format->color_fixup);
6439 if (!is_identity_fixup(dst_format->color_fixup))
6441 TRACE("Destination fixups are not supported\n");
6445 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6447 TRACE("P8 fixup supported\n");
6451 /* We only support identity conversions. */
6452 if (is_identity_fixup(src_format->color_fixup))
6458 TRACE("[FAILED]\n");
6461 case WINED3D_BLIT_OP_COLOR_FILL:
6462 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6465 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6467 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6470 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6472 TRACE("Color fill not supported\n");
6476 /* FIXME: We should reject color fills on formats with fixups,
6477 * but this would break P8 color fills for example. */
6481 case WINED3D_BLIT_OP_DEPTH_FILL:
6485 TRACE("Unsupported blit_op=%d\n", blit_op);
6490 /* Do not call while under the GL lock. */
6491 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6492 const RECT *dst_rect, const struct wined3d_color *color)
6494 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6495 struct wined3d_fb_state fb = {&dst_surface, NULL};
6497 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6502 /* Do not call while under the GL lock. */
6503 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6504 struct wined3d_surface *surface, const RECT *rect, float depth)
6506 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6507 struct wined3d_fb_state fb = {NULL, surface};
6509 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6514 const struct blit_shader ffp_blit = {
6520 ffp_blit_color_fill,
6521 ffp_blit_depth_fill,
6524 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6529 /* Context activation is done by the caller. */
6530 static void cpu_blit_free(struct wined3d_device *device)
6534 /* Context activation is done by the caller. */
6535 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6540 /* Context activation is done by the caller. */
6541 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6545 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6546 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6547 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6549 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6557 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6558 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6559 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6561 UINT row_block_count;
6562 const BYTE *src_row;
6569 row_block_count = (update_w + format->block_width - 1) / format->block_width;
6573 for (y = 0; y < update_h; y += format->block_height)
6575 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6576 src_row += src_pitch;
6577 dst_row += dst_pitch;
6583 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6585 src_row += (((update_h / format->block_height) - 1) * src_pitch);
6589 case WINED3DFMT_DXT1:
6590 for (y = 0; y < update_h; y += format->block_height)
6595 BYTE control_row[4];
6598 const struct block *s = (const struct block *)src_row;
6599 struct block *d = (struct block *)dst_row;
6601 for (x = 0; x < row_block_count; ++x)
6603 d[x].color[0] = s[x].color[0];
6604 d[x].color[1] = s[x].color[1];
6605 d[x].control_row[0] = s[x].control_row[3];
6606 d[x].control_row[1] = s[x].control_row[2];
6607 d[x].control_row[2] = s[x].control_row[1];
6608 d[x].control_row[3] = s[x].control_row[0];
6610 src_row -= src_pitch;
6611 dst_row += dst_pitch;
6615 case WINED3DFMT_DXT3:
6616 for (y = 0; y < update_h; y += format->block_height)
6622 BYTE control_row[4];
6625 const struct block *s = (const struct block *)src_row;
6626 struct block *d = (struct block *)dst_row;
6628 for (x = 0; x < row_block_count; ++x)
6630 d[x].alpha_row[0] = s[x].alpha_row[3];
6631 d[x].alpha_row[1] = s[x].alpha_row[2];
6632 d[x].alpha_row[2] = s[x].alpha_row[1];
6633 d[x].alpha_row[3] = s[x].alpha_row[0];
6634 d[x].color[0] = s[x].color[0];
6635 d[x].color[1] = s[x].color[1];
6636 d[x].control_row[0] = s[x].control_row[3];
6637 d[x].control_row[1] = s[x].control_row[2];
6638 d[x].control_row[2] = s[x].control_row[1];
6639 d[x].control_row[3] = s[x].control_row[0];
6641 src_row -= src_pitch;
6642 dst_row += dst_pitch;
6647 FIXME("Compressed flip not implemented for format %s.\n",
6648 debug_d3dformat(format->id));
6653 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
6654 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
6659 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
6660 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
6661 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
6663 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
6664 const struct wined3d_format *src_format, *dst_format;
6665 struct wined3d_surface *orig_src = src_surface;
6666 struct wined3d_map_desc dst_map, src_map;
6667 const BYTE *sbase = NULL;
6668 HRESULT hr = WINED3D_OK;
6673 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6674 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
6675 flags, fx, debug_d3dtexturefiltertype(filter));
6677 if (src_surface == dst_surface)
6679 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
6681 src_format = dst_surface->resource.format;
6682 dst_format = src_format;
6686 dst_format = dst_surface->resource.format;
6689 if (dst_surface->resource.format->id != src_surface->resource.format->id)
6691 src_surface = surface_convert_format(src_surface, dst_format->id);
6694 /* The conv function writes a FIXME */
6695 WARN("Cannot convert source surface format to dest format.\n");
6699 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
6700 src_format = src_surface->resource.format;
6704 src_format = dst_format;
6707 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
6710 bpp = dst_surface->resource.format->byte_count;
6711 srcheight = src_rect->bottom - src_rect->top;
6712 srcwidth = src_rect->right - src_rect->left;
6713 dstheight = dst_rect->bottom - dst_rect->top;
6714 dstwidth = dst_rect->right - dst_rect->left;
6715 width = (dst_rect->right - dst_rect->left) * bpp;
6718 sbase = (BYTE *)src_map.data
6719 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
6720 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
6721 if (src_surface != dst_surface)
6722 dbuf = dst_map.data;
6724 dbuf = (BYTE *)dst_map.data
6725 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
6726 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
6728 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
6730 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
6732 if (src_surface == dst_surface)
6734 FIXME("Only plain blits supported on compressed surfaces.\n");
6739 if (srcheight != dstheight || srcwidth != dstwidth)
6741 WARN("Stretching not supported on compressed surfaces.\n");
6742 hr = WINED3DERR_INVALIDCALL;
6746 if (!surface_check_block_align(src_surface, src_rect))
6748 WARN("Source rectangle not block-aligned.\n");
6749 hr = WINED3DERR_INVALIDCALL;
6753 if (!surface_check_block_align(dst_surface, dst_rect))
6755 WARN("Destination rectangle not block-aligned.\n");
6756 hr = WINED3DERR_INVALIDCALL;
6760 hr = surface_cpu_blt_compressed(sbase, dbuf,
6761 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
6762 src_format, flags, fx);
6766 /* First, all the 'source-less' blits */
6767 if (flags & WINEDDBLT_COLORFILL)
6769 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
6770 flags &= ~WINEDDBLT_COLORFILL;
6773 if (flags & WINEDDBLT_DEPTHFILL)
6775 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6777 if (flags & WINEDDBLT_ROP)
6779 /* Catch some degenerate cases here. */
6783 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
6785 case 0xaa0029: /* No-op */
6788 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
6790 case SRCCOPY: /* Well, we do that below? */
6793 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
6796 flags &= ~WINEDDBLT_ROP;
6798 if (flags & WINEDDBLT_DDROPS)
6800 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
6802 /* Now the 'with source' blits. */
6805 int sx, xinc, sy, yinc;
6807 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
6810 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
6811 && (srcwidth != dstwidth || srcheight != dstheight))
6813 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6814 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
6817 xinc = (srcwidth << 16) / dstwidth;
6818 yinc = (srcheight << 16) / dstheight;
6822 /* No effects, we can cheat here. */
6823 if (dstwidth == srcwidth)
6825 if (dstheight == srcheight)
6827 /* No stretching in either direction. This needs to be as
6828 * fast as possible. */
6831 /* Check for overlapping surfaces. */
6832 if (src_surface != dst_surface || dst_rect->top < src_rect->top
6833 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
6835 /* No overlap, or dst above src, so copy from top downwards. */
6836 for (y = 0; y < dstheight; ++y)
6838 memcpy(dbuf, sbuf, width);
6839 sbuf += src_map.row_pitch;
6840 dbuf += dst_map.row_pitch;
6843 else if (dst_rect->top > src_rect->top)
6845 /* Copy from bottom upwards. */
6846 sbuf += src_map.row_pitch * dstheight;
6847 dbuf += dst_map.row_pitch * dstheight;
6848 for (y = 0; y < dstheight; ++y)
6850 sbuf -= src_map.row_pitch;
6851 dbuf -= dst_map.row_pitch;
6852 memcpy(dbuf, sbuf, width);
6857 /* Src and dst overlapping on the same line, use memmove. */
6858 for (y = 0; y < dstheight; ++y)
6860 memmove(dbuf, sbuf, width);
6861 sbuf += src_map.row_pitch;
6862 dbuf += dst_map.row_pitch;
6868 /* Stretching in y direction only. */
6869 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6871 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6872 memcpy(dbuf, sbuf, width);
6873 dbuf += dst_map.row_pitch;
6879 /* Stretching in X direction. */
6881 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6883 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6885 if ((sy >> 16) == (last_sy >> 16))
6887 /* This source row is the same as last source row -
6888 * Copy the already stretched row. */
6889 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
6893 #define STRETCH_ROW(type) \
6895 const type *s = (const type *)sbuf; \
6896 type *d = (type *)dbuf; \
6897 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6898 d[x] = s[sx >> 16]; \
6916 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
6920 s = sbuf + 3 * (sx >> 16);
6921 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
6922 d[0] = (pixel ) & 0xff;
6923 d[1] = (pixel >> 8) & 0xff;
6924 d[2] = (pixel >> 16) & 0xff;
6930 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
6931 hr = WINED3DERR_NOTAVAILABLE;
6936 dbuf += dst_map.row_pitch;
6943 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
6944 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
6945 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
6946 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
6948 /* The color keying flags are checked for correctness in ddraw */
6949 if (flags & WINEDDBLT_KEYSRC)
6951 keylow = src_surface->src_blt_color_key.color_space_low_value;
6952 keyhigh = src_surface->src_blt_color_key.color_space_high_value;
6954 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6956 keylow = fx->ddckSrcColorkey.color_space_low_value;
6957 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
6960 if (flags & WINEDDBLT_KEYDEST)
6962 /* Destination color keys are taken from the source surface! */
6963 destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
6964 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
6966 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
6968 destkeylow = fx->ddckDestColorkey.color_space_low_value;
6969 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
6979 get_color_masks(src_format, masks);
6984 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
6987 if (flags & WINEDDBLT_DDFX)
6989 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
6992 dTopRight = dbuf + ((dstwidth - 1) * bpp);
6993 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
6994 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
6996 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
6998 /* I don't think we need to do anything about this flag */
6999 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
7001 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
7004 dTopRight = dTopLeft;
7007 dBottomRight = dBottomLeft;
7009 dstxinc = dstxinc * -1;
7011 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
7014 dTopLeft = dBottomLeft;
7017 dTopRight = dBottomRight;
7019 dstyinc = dstyinc * -1;
7021 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
7023 /* I don't think we need to do anything about this flag */
7024 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
7026 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
7029 dBottomRight = dTopLeft;
7032 dBottomLeft = dTopRight;
7034 dstxinc = dstxinc * -1;
7035 dstyinc = dstyinc * -1;
7037 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
7040 dTopLeft = dBottomLeft;
7041 dBottomLeft = dBottomRight;
7042 dBottomRight = dTopRight;
7047 dstxinc = dstxinc * -1;
7049 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7052 dTopLeft = dTopRight;
7053 dTopRight = dBottomRight;
7054 dBottomRight = dBottomLeft;
7059 dstyinc = dstyinc * -1;
7061 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7063 /* I don't think we need to do anything about this flag */
7064 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7067 flags &= ~(WINEDDBLT_DDFX);
7070 #define COPY_COLORKEY_FX(type) \
7073 type *d = (type *)dbuf, *dx, tmp; \
7074 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7076 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7078 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7080 tmp = s[sx >> 16]; \
7081 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7082 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7086 dx = (type *)(((BYTE *)dx) + dstxinc); \
7088 d = (type *)(((BYTE *)d) + dstyinc); \
7095 COPY_COLORKEY_FX(BYTE);
7098 COPY_COLORKEY_FX(WORD);
7101 COPY_COLORKEY_FX(DWORD);
7106 BYTE *d = dbuf, *dx;
7107 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7109 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7111 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7113 DWORD pixel, dpixel = 0;
7114 s = sbuf + 3 * (sx>>16);
7115 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7116 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7117 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7118 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7120 dx[0] = (pixel ) & 0xff;
7121 dx[1] = (pixel >> 8) & 0xff;
7122 dx[2] = (pixel >> 16) & 0xff;
7131 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7132 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7133 hr = WINED3DERR_NOTAVAILABLE;
7135 #undef COPY_COLORKEY_FX
7141 if (flags && FIXME_ON(d3d_surface))
7143 FIXME("\tUnsupported flags: %#x.\n", flags);
7147 wined3d_surface_unmap(dst_surface);
7148 if (src_surface && src_surface != dst_surface)
7149 wined3d_surface_unmap(src_surface);
7150 /* Release the converted surface, if any. */
7151 if (src_surface && src_surface != orig_src)
7152 wined3d_surface_decref(src_surface);
7157 /* Do not call while under the GL lock. */
7158 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7159 const RECT *dst_rect, const struct wined3d_color *color)
7161 static const RECT src_rect;
7164 memset(&BltFx, 0, sizeof(BltFx));
7165 BltFx.dwSize = sizeof(BltFx);
7166 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7167 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7168 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7171 /* Do not call while under the GL lock. */
7172 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7173 struct wined3d_surface *surface, const RECT *rect, float depth)
7175 FIXME("Depth filling not implemented by cpu_blit.\n");
7176 return WINED3DERR_INVALIDCALL;
7179 const struct blit_shader cpu_blit = {
7185 cpu_blit_color_fill,
7186 cpu_blit_depth_fill,
7189 static HRESULT surface_init(struct wined3d_surface *surface, enum wined3d_surface_type surface_type, UINT alignment,
7190 UINT width, UINT height, UINT level, enum wined3d_multisample_type multisample_type,
7191 UINT multisample_quality, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7192 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops)
7194 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7195 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7196 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7197 unsigned int resource_size;
7200 if (multisample_quality > 0)
7202 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7203 multisample_quality = 0;
7206 /* Quick lockable sanity check.
7207 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7208 * this function is too deep to need to care about things like this.
7209 * Levels need to be checked too, since they all affect what can be done. */
7212 case WINED3D_POOL_SCRATCH:
7215 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7216 "which are mutually exclusive, setting lockable to TRUE.\n");
7221 case WINED3D_POOL_SYSTEM_MEM:
7223 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7226 case WINED3D_POOL_MANAGED:
7227 if (usage & WINED3DUSAGE_DYNAMIC)
7228 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7231 case WINED3D_POOL_DEFAULT:
7232 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7233 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7237 FIXME("Unknown pool %#x.\n", pool);
7241 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7242 FIXME("Trying to create a render target that isn't in the default pool.\n");
7244 /* FIXME: Check that the format is supported by the device. */
7246 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7248 return WINED3DERR_INVALIDCALL;
7250 surface->surface_type = surface_type;
7252 switch (surface_type)
7254 case WINED3D_SURFACE_TYPE_OPENGL:
7255 surface->surface_ops = &surface_ops;
7258 case WINED3D_SURFACE_TYPE_GDI:
7259 surface->surface_ops = &gdi_surface_ops;
7263 ERR("Requested unknown surface implementation %#x.\n", surface_type);
7264 return WINED3DERR_INVALIDCALL;
7267 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7268 multisample_type, multisample_quality, usage, pool, width, height, 1,
7269 resource_size, parent, parent_ops, &surface_resource_ops);
7272 WARN("Failed to initialize resource, returning %#x.\n", hr);
7276 /* "Standalone" surface. */
7277 surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7279 surface->texture_level = level;
7280 list_init(&surface->overlays);
7283 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7284 if (flags & WINED3D_SURFACE_DISCARD)
7285 surface->flags |= SFLAG_DISCARD;
7286 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7287 surface->flags |= SFLAG_PIN_SYSMEM;
7288 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7289 surface->flags |= SFLAG_LOCKABLE;
7290 /* I'm not sure if this qualifies as a hack or as an optimization. It
7291 * seems reasonable to assume that lockable render targets will get
7292 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7293 * creation. However, the other reason we want to do this is that several
7294 * ddraw applications access surface memory while the surface isn't
7295 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7296 * future locks prevents these from crashing. */
7297 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7298 surface->flags |= SFLAG_DYNLOCK;
7300 /* Mark the texture as dirty so that it gets loaded first time around. */
7301 surface_add_dirty_rect(surface, NULL);
7302 list_init(&surface->renderbuffers);
7304 TRACE("surface %p, memory %p, size %u\n",
7305 surface, surface->resource.allocatedMemory, surface->resource.size);
7307 /* Call the private setup routine */
7308 hr = surface->surface_ops->surface_private_setup(surface);
7311 ERR("Private setup failed, returning %#x\n", hr);
7312 surface_cleanup(surface);
7316 /* Similar to lockable rendertargets above, creating the DIB section
7317 * during surface initialization prevents the sysmem pointer from changing
7318 * after a wined3d_surface_getdc() call. */
7319 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7320 && SUCCEEDED(surface_create_dib_section(surface)))
7322 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7323 surface->resource.heapMemory = NULL;
7324 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7330 HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
7331 enum wined3d_format_id format_id, UINT level, DWORD usage, enum wined3d_pool pool,
7332 enum wined3d_multisample_type multisample_type, DWORD multisample_quality,
7333 enum wined3d_surface_type surface_type, DWORD flags, void *parent,
7334 const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface)
7336 struct wined3d_surface *object;
7339 TRACE("device %p, width %u, height %u, format %s, level %u\n",
7340 device, width, height, debug_d3dformat(format_id), level);
7341 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7342 surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
7343 TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type, flags, parent, parent_ops);
7345 if (surface_type == WINED3D_SURFACE_TYPE_OPENGL && !device->adapter)
7347 ERR("OpenGL surfaces are not available without OpenGL.\n");
7348 return WINED3DERR_NOTAVAILABLE;
7351 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
7354 ERR("Failed to allocate surface memory.\n");
7355 return WINED3DERR_OUTOFVIDEOMEMORY;
7358 hr = surface_init(object, surface_type, device->surface_alignment, width, height, level,
7359 multisample_type, multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops);
7362 WARN("Failed to initialize surface, returning %#x.\n", hr);
7363 HeapFree(GetProcessHeap(), 0, object);
7367 TRACE("Created surface %p.\n", object);