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 HRESULT 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);
3179 HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3180 DWORD flags, const struct wined3d_color_key *color_key)
3182 TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3184 if (flags & WINEDDCKEY_COLORSPACE)
3186 FIXME(" colorkey value not supported (%08x) !\n", flags);
3187 return WINED3DERR_INVALIDCALL;
3190 /* Dirtify the surface, but only if a key was changed. */
3193 switch (flags & ~WINEDDCKEY_COLORSPACE)
3195 case WINEDDCKEY_DESTBLT:
3196 surface->dst_blt_color_key = *color_key;
3197 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3200 case WINEDDCKEY_DESTOVERLAY:
3201 surface->dst_overlay_color_key = *color_key;
3202 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3205 case WINEDDCKEY_SRCOVERLAY:
3206 surface->src_overlay_color_key = *color_key;
3207 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3210 case WINEDDCKEY_SRCBLT:
3211 surface->src_blt_color_key = *color_key;
3212 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3218 switch (flags & ~WINEDDCKEY_COLORSPACE)
3220 case WINEDDCKEY_DESTBLT:
3221 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3224 case WINEDDCKEY_DESTOVERLAY:
3225 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3228 case WINEDDCKEY_SRCOVERLAY:
3229 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3232 case WINEDDCKEY_SRCBLT:
3233 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3241 struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3243 TRACE("surface %p.\n", surface);
3245 return surface->palette;
3248 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3250 const struct wined3d_format *format = surface->resource.format;
3253 TRACE("surface %p.\n", surface);
3255 if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3257 /* Since compressed formats are block based, pitch means the amount of
3258 * bytes to the next row of block rather than the next row of pixels. */
3259 UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3260 pitch = row_block_count * format->block_byte_count;
3264 unsigned char alignment = surface->resource.device->surface_alignment;
3265 pitch = surface->resource.format->byte_count * surface->resource.width; /* Bytes / row */
3266 pitch = (pitch + alignment - 1) & ~(alignment - 1);
3269 TRACE("Returning %u.\n", pitch);
3274 HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem)
3276 TRACE("surface %p, mem %p.\n", surface, mem);
3278 if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3280 WARN("Surface is mapped or the DC is in use.\n");
3281 return WINED3DERR_INVALIDCALL;
3284 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3285 if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3287 ERR("Not supported on render targets.\n");
3288 return WINED3DERR_INVALIDCALL;
3291 if (mem && mem != surface->resource.allocatedMemory)
3293 void *release = NULL;
3295 /* Do I have to copy the old surface content? */
3296 if (surface->flags & SFLAG_DIBSECTION)
3298 DeleteDC(surface->hDC);
3299 DeleteObject(surface->dib.DIBsection);
3300 surface->dib.bitmap_data = NULL;
3301 surface->resource.allocatedMemory = NULL;
3302 surface->hDC = NULL;
3303 surface->flags &= ~SFLAG_DIBSECTION;
3305 else if (!(surface->flags & SFLAG_USERPTR))
3307 release = surface->resource.heapMemory;
3308 surface->resource.heapMemory = NULL;
3310 surface->resource.allocatedMemory = mem;
3311 surface->flags |= SFLAG_USERPTR;
3313 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3314 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3316 /* For client textures OpenGL has to be notified. */
3317 if (surface->flags & SFLAG_CLIENT)
3318 surface_release_client_storage(surface);
3320 /* Now free the old memory if any. */
3321 HeapFree(GetProcessHeap(), 0, release);
3323 else if (surface->flags & SFLAG_USERPTR)
3325 /* HeapMemory should be NULL already. */
3326 if (surface->resource.heapMemory)
3327 ERR("User pointer surface has heap memory allocated.\n");
3331 surface->resource.allocatedMemory = NULL;
3332 surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3334 if (surface->flags & SFLAG_CLIENT)
3335 surface_release_client_storage(surface);
3337 surface_prepare_system_memory(surface);
3340 surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3346 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3350 TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3352 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3354 WARN("Not an overlay surface.\n");
3355 return WINEDDERR_NOTAOVERLAYSURFACE;
3358 w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3359 h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3360 surface->overlay_destrect.left = x;
3361 surface->overlay_destrect.top = y;
3362 surface->overlay_destrect.right = x + w;
3363 surface->overlay_destrect.bottom = y + h;
3365 surface_draw_overlay(surface);
3370 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3372 TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3374 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3376 TRACE("Not an overlay surface.\n");
3377 return WINEDDERR_NOTAOVERLAYSURFACE;
3380 if (!surface->overlay_dest)
3382 TRACE("Overlay not visible.\n");
3385 return WINEDDERR_OVERLAYNOTVISIBLE;
3388 *x = surface->overlay_destrect.left;
3389 *y = surface->overlay_destrect.top;
3391 TRACE("Returning position %d, %d.\n", *x, *y);
3396 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3397 DWORD flags, struct wined3d_surface *ref)
3399 FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3401 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3403 TRACE("Not an overlay surface.\n");
3404 return WINEDDERR_NOTAOVERLAYSURFACE;
3410 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3411 struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3413 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3414 surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3416 if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3418 WARN("Not an overlay surface.\n");
3419 return WINEDDERR_NOTAOVERLAYSURFACE;
3421 else if (!dst_surface)
3423 WARN("Dest surface is NULL.\n");
3424 return WINED3DERR_INVALIDCALL;
3429 surface->overlay_srcrect = *src_rect;
3433 surface->overlay_srcrect.left = 0;
3434 surface->overlay_srcrect.top = 0;
3435 surface->overlay_srcrect.right = surface->resource.width;
3436 surface->overlay_srcrect.bottom = surface->resource.height;
3441 surface->overlay_destrect = *dst_rect;
3445 surface->overlay_destrect.left = 0;
3446 surface->overlay_destrect.top = 0;
3447 surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3448 surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3451 if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3453 surface->overlay_dest = NULL;
3454 list_remove(&surface->overlay_entry);
3457 if (flags & WINEDDOVER_SHOW)
3459 if (surface->overlay_dest != dst_surface)
3461 surface->overlay_dest = dst_surface;
3462 list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3465 else if (flags & WINEDDOVER_HIDE)
3467 /* tests show that the rectangles are erased on hide */
3468 surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3469 surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3470 surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3471 surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3472 surface->overlay_dest = NULL;
3475 surface_draw_overlay(surface);
3480 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3481 UINT width, UINT height, enum wined3d_format_id format_id,
3482 enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3484 struct wined3d_device *device = surface->resource.device;
3485 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3486 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3487 UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3489 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3490 surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3493 return WINED3DERR_INVALIDCALL;
3495 if (device->d3d_initialized)
3496 surface->resource.resource_ops->resource_unload(&surface->resource);
3498 if (surface->flags & SFLAG_DIBSECTION)
3500 DeleteDC(surface->hDC);
3501 DeleteObject(surface->dib.DIBsection);
3502 surface->dib.bitmap_data = NULL;
3503 surface->flags &= ~SFLAG_DIBSECTION;
3506 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3507 surface->resource.allocatedMemory = NULL;
3508 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3509 surface->resource.heapMemory = NULL;
3511 surface->resource.width = width;
3512 surface->resource.height = height;
3513 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3514 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3516 surface->pow2Width = width;
3517 surface->pow2Height = height;
3521 surface->pow2Width = surface->pow2Height = 1;
3522 while (surface->pow2Width < width)
3523 surface->pow2Width <<= 1;
3524 while (surface->pow2Height < height)
3525 surface->pow2Height <<= 1;
3528 if (surface->pow2Width != width || surface->pow2Height != height)
3529 surface->flags |= SFLAG_NONPOW2;
3531 surface->flags &= ~SFLAG_NONPOW2;
3533 surface->resource.format = format;
3534 surface->resource.multisample_type = multisample_type;
3535 surface->resource.multisample_quality = multisample_quality;
3536 surface->resource.size = resource_size;
3538 if (!surface_init_sysmem(surface))
3539 return E_OUTOFMEMORY;
3544 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3545 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3547 unsigned short *dst_s;
3551 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3553 for (y = 0; y < h; ++y)
3555 src_f = (const float *)(src + y * pitch_in);
3556 dst_s = (unsigned short *) (dst + y * pitch_out);
3557 for (x = 0; x < w; ++x)
3559 dst_s[x] = float_32_to_16(src_f + x);
3564 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3565 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3567 static const unsigned char convert_5to8[] =
3569 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3570 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3571 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3572 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3574 static const unsigned char convert_6to8[] =
3576 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3577 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3578 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3579 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3580 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3581 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3582 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3583 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3587 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3589 for (y = 0; y < h; ++y)
3591 const WORD *src_line = (const WORD *)(src + y * pitch_in);
3592 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3593 for (x = 0; x < w; ++x)
3595 WORD pixel = src_line[x];
3596 dst_line[x] = 0xff000000
3597 | convert_5to8[(pixel & 0xf800) >> 11] << 16
3598 | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3599 | convert_5to8[(pixel & 0x001f)];
3604 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3605 * in both cases we're just setting the X / Alpha channel to 0xff. */
3606 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3607 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3611 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3613 for (y = 0; y < h; ++y)
3615 const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3616 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3618 for (x = 0; x < w; ++x)
3620 dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3625 static inline BYTE cliptobyte(int x)
3627 return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3630 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3631 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3633 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3636 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3638 for (y = 0; y < h; ++y)
3640 const BYTE *src_line = src + y * pitch_in;
3641 DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3642 for (x = 0; x < w; ++x)
3644 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3645 * C = Y - 16; D = U - 128; E = V - 128;
3646 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3647 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3648 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3649 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3650 * U and V are shared between the pixels. */
3651 if (!(x & 1)) /* For every even pixel, read new U and V. */
3653 d = (int) src_line[1] - 128;
3654 e = (int) src_line[3] - 128;
3656 g2 = - 100 * d - 208 * e + 128;
3659 c2 = 298 * ((int) src_line[0] - 16);
3660 dst_line[x] = 0xff000000
3661 | cliptobyte((c2 + r2) >> 8) << 16 /* red */
3662 | cliptobyte((c2 + g2) >> 8) << 8 /* green */
3663 | cliptobyte((c2 + b2) >> 8); /* blue */
3664 /* Scale RGB values to 0..255 range,
3665 * then clip them if still not in range (may be negative),
3666 * then shift them within DWORD if necessary. */
3672 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3673 DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3676 int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3678 TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3680 for (y = 0; y < h; ++y)
3682 const BYTE *src_line = src + y * pitch_in;
3683 WORD *dst_line = (WORD *)(dst + y * pitch_out);
3684 for (x = 0; x < w; ++x)
3686 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3687 * C = Y - 16; D = U - 128; E = V - 128;
3688 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3689 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3690 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3691 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3692 * U and V are shared between the pixels. */
3693 if (!(x & 1)) /* For every even pixel, read new U and V. */
3695 d = (int) src_line[1] - 128;
3696 e = (int) src_line[3] - 128;
3698 g2 = - 100 * d - 208 * e + 128;
3701 c2 = 298 * ((int) src_line[0] - 16);
3702 dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11 /* red */
3703 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5 /* green */
3704 | (cliptobyte((c2 + b2) >> 8) >> 3); /* blue */
3705 /* Scale RGB values to 0..255 range,
3706 * then clip them if still not in range (may be negative),
3707 * then shift them within DWORD if necessary. */
3713 struct d3dfmt_converter_desc
3715 enum wined3d_format_id from, to;
3716 void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3719 static const struct d3dfmt_converter_desc converters[] =
3721 {WINED3DFMT_R32_FLOAT, WINED3DFMT_R16_FLOAT, convert_r32_float_r16_float},
3722 {WINED3DFMT_B5G6R5_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_r5g6b5_x8r8g8b8},
3723 {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3724 {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM, convert_a8r8g8b8_x8r8g8b8},
3725 {WINED3DFMT_YUY2, WINED3DFMT_B8G8R8X8_UNORM, convert_yuy2_x8r8g8b8},
3726 {WINED3DFMT_YUY2, WINED3DFMT_B5G6R5_UNORM, convert_yuy2_r5g6b5},
3729 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
3730 enum wined3d_format_id to)
3734 for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
3736 if (converters[i].from == from && converters[i].to == to)
3737 return &converters[i];
3743 /*****************************************************************************
3744 * surface_convert_format
3746 * Creates a duplicate of a surface in a different format. Is used by Blt to
3747 * blit between surfaces with different formats.
3750 * source: Source surface
3751 * fmt: Requested destination format
3753 *****************************************************************************/
3754 static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
3756 struct wined3d_map_desc src_map, dst_map;
3757 const struct d3dfmt_converter_desc *conv;
3758 struct wined3d_surface *ret = NULL;
3761 conv = find_converter(source->resource.format->id, to_fmt);
3764 FIXME("Cannot find a conversion function from format %s to %s.\n",
3765 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
3769 wined3d_surface_create(source->resource.device, source->resource.width,
3770 source->resource.height, to_fmt, 0 /* level */, 0 /* usage */, WINED3D_POOL_SCRATCH,
3771 WINED3D_MULTISAMPLE_NONE /* TODO: Multisampled conversion */, 0 /* MultiSampleQuality */,
3772 source->surface_type, WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD,
3773 NULL /* parent */, &wined3d_null_parent_ops, &ret);
3776 ERR("Failed to create a destination surface for conversion.\n");
3780 memset(&src_map, 0, sizeof(src_map));
3781 memset(&dst_map, 0, sizeof(dst_map));
3783 if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
3785 ERR("Failed to lock the source surface.\n");
3786 wined3d_surface_decref(ret);
3789 if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
3791 ERR("Failed to lock the destination surface.\n");
3792 wined3d_surface_unmap(source);
3793 wined3d_surface_decref(ret);
3797 conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
3798 source->resource.width, source->resource.height);
3800 wined3d_surface_unmap(ret);
3801 wined3d_surface_unmap(source);
3806 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
3807 unsigned int bpp, UINT pitch, DWORD color)
3814 #define COLORFILL_ROW(type) \
3816 type *d = (type *)buf; \
3817 for (x = 0; x < width; ++x) \
3818 d[x] = (type)color; \
3824 COLORFILL_ROW(BYTE);
3828 COLORFILL_ROW(WORD);
3834 for (x = 0; x < width; ++x, d += 3)
3836 d[0] = (color ) & 0xff;
3837 d[1] = (color >> 8) & 0xff;
3838 d[2] = (color >> 16) & 0xff;
3843 COLORFILL_ROW(DWORD);
3847 FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
3848 return WINED3DERR_NOTAVAILABLE;
3851 #undef COLORFILL_ROW
3853 /* Now copy first row. */
3855 for (y = 1; y < height; ++y)
3858 memcpy(buf, first, width * bpp);
3864 struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
3866 return surface_from_resource(resource);
3869 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
3871 TRACE("surface %p.\n", surface);
3873 if (!surface->resource.map_count)
3875 WARN("Trying to unmap unmapped surface.\n");
3876 return WINEDDERR_NOTLOCKED;
3878 --surface->resource.map_count;
3880 surface->surface_ops->surface_unmap(surface);
3885 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
3886 struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
3888 const struct wined3d_format *format = surface->resource.format;
3890 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
3891 surface, map_desc, wine_dbgstr_rect(rect), flags);
3893 if (surface->resource.map_count)
3895 WARN("Surface is already mapped.\n");
3896 return WINED3DERR_INVALIDCALL;
3899 if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
3900 && !surface_check_block_align(surface, rect))
3902 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
3903 wine_dbgstr_rect(rect), format->block_width, format->block_height);
3905 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
3906 return WINED3DERR_INVALIDCALL;
3909 ++surface->resource.map_count;
3911 if (!(surface->flags & SFLAG_LOCKABLE))
3912 WARN("Trying to lock unlockable surface.\n");
3914 /* Performance optimization: Count how often a surface is mapped, if it is
3915 * mapped regularly do not throw away the system memory copy. This avoids
3916 * the need to download the surface from OpenGL all the time. The surface
3917 * is still downloaded if the OpenGL texture is changed. */
3918 if (!(surface->flags & SFLAG_DYNLOCK))
3920 if (++surface->lockCount > MAXLOCKCOUNT)
3922 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3923 surface->flags |= SFLAG_DYNLOCK;
3927 surface->surface_ops->surface_map(surface, rect, flags);
3929 if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
3930 map_desc->row_pitch = surface->resource.width * format->byte_count;
3932 map_desc->row_pitch = wined3d_surface_get_pitch(surface);
3933 map_desc->slice_pitch = 0;
3937 map_desc->data = surface->resource.allocatedMemory;
3938 surface->lockedRect.left = 0;
3939 surface->lockedRect.top = 0;
3940 surface->lockedRect.right = surface->resource.width;
3941 surface->lockedRect.bottom = surface->resource.height;
3945 if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
3947 /* Compressed textures are block based, so calculate the offset of
3948 * the block that contains the top-left pixel of the locked rectangle. */
3949 map_desc->data = surface->resource.allocatedMemory
3950 + ((rect->top / format->block_height) * map_desc->row_pitch)
3951 + ((rect->left / format->block_width) * format->block_byte_count);
3955 map_desc->data = surface->resource.allocatedMemory
3956 + (map_desc->row_pitch * rect->top)
3957 + (rect->left * format->byte_count);
3959 surface->lockedRect.left = rect->left;
3960 surface->lockedRect.top = rect->top;
3961 surface->lockedRect.right = rect->right;
3962 surface->lockedRect.bottom = rect->bottom;
3965 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3966 TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
3971 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
3973 struct wined3d_map_desc map;
3976 TRACE("surface %p, dc %p.\n", surface, dc);
3978 if (surface->flags & SFLAG_USERPTR)
3980 ERR("Not supported on surfaces with application-provided memory.\n");
3981 return WINEDDERR_NODC;
3984 /* Give more detailed info for ddraw. */
3985 if (surface->flags & SFLAG_DCINUSE)
3986 return WINEDDERR_DCALREADYCREATED;
3988 /* Can't GetDC if the surface is locked. */
3989 if (surface->resource.map_count)
3990 return WINED3DERR_INVALIDCALL;
3992 /* Create a DIB section if there isn't a dc yet. */
3995 if (surface->flags & SFLAG_CLIENT)
3997 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3998 surface_release_client_storage(surface);
4000 hr = surface_create_dib_section(surface);
4002 return WINED3DERR_INVALIDCALL;
4004 /* Use the DIB section from now on if we are not using a PBO. */
4005 if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
4007 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
4008 surface->resource.heapMemory = NULL;
4009 surface->resource.allocatedMemory = surface->dib.bitmap_data;
4013 /* Map the surface. */
4014 hr = wined3d_surface_map(surface, &map, NULL, 0);
4017 ERR("Map failed, hr %#x.\n", hr);
4021 /* Sync the DIB with the PBO. This can't be done earlier because Map()
4022 * activates the allocatedMemory. */
4023 if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4024 memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4026 if (surface->resource.format->id == WINED3DFMT_P8_UINT
4027 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4029 /* GetDC on palettized formats is unsupported in D3D9, and the method
4030 * is missing in D3D8, so this should only be used for DX <=7
4031 * surfaces (with non-device palettes). */
4032 const PALETTEENTRY *pal = NULL;
4034 if (surface->palette)
4036 pal = surface->palette->palents;
4040 struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4041 struct wined3d_surface *dds_primary = swapchain->front_buffer;
4043 if (dds_primary && dds_primary->palette)
4044 pal = dds_primary->palette->palents;
4052 for (i = 0; i < 256; ++i)
4054 col[i].rgbRed = pal[i].peRed;
4055 col[i].rgbGreen = pal[i].peGreen;
4056 col[i].rgbBlue = pal[i].peBlue;
4057 col[i].rgbReserved = 0;
4059 SetDIBColorTable(surface->hDC, 0, 256, col);
4063 surface->flags |= SFLAG_DCINUSE;
4066 TRACE("Returning dc %p.\n", *dc);
4071 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4073 TRACE("surface %p, dc %p.\n", surface, dc);
4075 if (!(surface->flags & SFLAG_DCINUSE))
4076 return WINEDDERR_NODC;
4078 if (surface->hDC != dc)
4080 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4082 return WINEDDERR_NODC;
4085 /* Copy the contents of the DIB over to the PBO. */
4086 if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4087 memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4089 /* We locked first, so unlock now. */
4090 wined3d_surface_unmap(surface);
4092 surface->flags &= ~SFLAG_DCINUSE;
4097 HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4099 TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4105 FIXME("Ignoring flags %#x.\n", flags);
4107 WARN("Ignoring flags %#x.\n", flags);
4110 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
4112 ERR("Not supported on swapchain surfaces.\n");
4113 return WINEDDERR_NOTFLIPPABLE;
4116 /* Flipping is only supported on render targets and overlays. */
4117 if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
4119 WARN("Tried to flip a non-render target, non-overlay surface.\n");
4120 return WINEDDERR_NOTFLIPPABLE;
4123 flip_surface(surface, override);
4125 /* Update overlays if they're visible. */
4126 if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4127 return surface_draw_overlay(surface);
4132 /* Do not call while under the GL lock. */
4133 void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4135 struct wined3d_device *device = surface->resource.device;
4137 TRACE("iface %p, srgb %#x.\n", surface, srgb);
4139 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4141 struct wined3d_texture *texture = surface->container.u.texture;
4143 TRACE("Passing to container (%p).\n", texture);
4144 texture->texture_ops->texture_preload(texture, srgb);
4148 struct wined3d_context *context;
4150 TRACE("(%p) : About to load surface\n", surface);
4152 /* TODO: Use already acquired context when possible. */
4153 context = context_acquire(device, NULL);
4155 surface_load(surface, srgb == SRGB_SRGB);
4157 if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4159 /* Tell opengl to try and keep this texture in video ram (well mostly) */
4163 context->gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &surface->texture_name, &tmp);
4167 context_release(context);
4171 /* Read the framebuffer back into the surface */
4172 static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4174 struct wined3d_device *device = surface->resource.device;
4175 const struct wined3d_gl_info *gl_info;
4176 struct wined3d_context *context;
4180 BYTE *row, *top, *bottom;
4184 BOOL srcIsUpsideDown;
4189 context = context_acquire(device, surface);
4190 context_apply_blit_state(context, device);
4191 gl_info = context->gl_info;
4195 /* Select the correct read buffer, and give some debug output.
4196 * There is no need to keep track of the current read buffer or reset it, every part of the code
4197 * that reads sets the read buffer as desired.
4199 if (surface_is_offscreen(surface))
4201 /* Mapping the primary render target which is not on a swapchain.
4202 * Read from the back buffer. */
4203 TRACE("Mapping offscreen render target.\n");
4204 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4205 srcIsUpsideDown = TRUE;
4209 /* Onscreen surfaces are always part of a swapchain */
4210 GLenum buffer = surface_get_gl_buffer(surface);
4211 TRACE("Mapping %#x buffer.\n", buffer);
4212 gl_info->gl_ops.gl.p_glReadBuffer(buffer);
4213 checkGLcall("glReadBuffer");
4214 srcIsUpsideDown = FALSE;
4217 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4220 local_rect.left = 0;
4222 local_rect.right = surface->resource.width;
4223 local_rect.bottom = surface->resource.height;
4229 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4231 switch (surface->resource.format->id)
4233 case WINED3DFMT_P8_UINT:
4235 if (primary_render_target_is_p8(device))
4237 /* In case of P8 render targets the index is stored in the alpha component */
4239 type = GL_UNSIGNED_BYTE;
4241 bpp = surface->resource.format->byte_count;
4245 /* GL can't return palettized data, so read ARGB pixels into a
4246 * separate block of memory and convert them into palettized format
4247 * in software. Slow, but if the app means to use palettized render
4248 * targets and locks it...
4250 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4251 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4252 * for the color channels when palettizing the colors.
4255 type = GL_UNSIGNED_BYTE;
4257 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4260 ERR("Out of memory\n");
4264 bpp = surface->resource.format->byte_count * 3;
4271 fmt = surface->resource.format->glFormat;
4272 type = surface->resource.format->glType;
4273 bpp = surface->resource.format->byte_count;
4276 if (surface->flags & SFLAG_PBO)
4278 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4279 checkGLcall("glBindBufferARB");
4282 ERR("mem not null for pbo -- unexpected\n");
4287 /* Save old pixel store pack state */
4288 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4289 checkGLcall("glGetIntegerv");
4290 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4291 checkGLcall("glGetIntegerv");
4292 gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4293 checkGLcall("glGetIntegerv");
4295 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4296 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4297 checkGLcall("glPixelStorei");
4298 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4299 checkGLcall("glPixelStorei");
4300 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4301 checkGLcall("glPixelStorei");
4303 gl_info->gl_ops.gl.p_glReadPixels(local_rect.left,
4304 !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4305 local_rect.right - local_rect.left,
4306 local_rect.bottom - local_rect.top,
4308 checkGLcall("glReadPixels");
4310 /* Reset previous pixel store pack state */
4311 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4312 checkGLcall("glPixelStorei");
4313 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4314 checkGLcall("glPixelStorei");
4315 gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4316 checkGLcall("glPixelStorei");
4318 if (surface->flags & SFLAG_PBO)
4320 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4321 checkGLcall("glBindBufferARB");
4323 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4324 * to get a pointer to it and perform the flipping in software. This is a lot
4325 * faster than calling glReadPixels for each line. In case we want more speed
4326 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4327 if (!srcIsUpsideDown)
4329 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4330 checkGLcall("glBindBufferARB");
4332 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4333 checkGLcall("glMapBufferARB");
4337 /* TODO: Merge this with the palettization loop below for P8 targets */
4338 if(!srcIsUpsideDown) {
4340 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4341 Flip the lines in software */
4342 len = (local_rect.right - local_rect.left) * bpp;
4343 off = local_rect.left * bpp;
4345 row = HeapAlloc(GetProcessHeap(), 0, len);
4347 ERR("Out of memory\n");
4348 if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4349 HeapFree(GetProcessHeap(), 0, mem);
4354 top = mem + pitch * local_rect.top;
4355 bottom = mem + pitch * (local_rect.bottom - 1);
4356 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4357 memcpy(row, top + off, len);
4358 memcpy(top + off, bottom + off, len);
4359 memcpy(bottom + off, row, len);
4363 HeapFree(GetProcessHeap(), 0, row);
4365 /* Unmap the temp PBO buffer */
4366 if (surface->flags & SFLAG_PBO)
4368 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4369 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4374 context_release(context);
4376 /* For P8 textures we need to perform an inverse palette lookup. This is
4377 * done by searching for a palette index which matches the RGB value.
4378 * Note this isn't guaranteed to work when there are multiple entries for
4379 * the same color but we have no choice. In case of P8 render targets,
4380 * the index is stored in the alpha component so no conversion is needed. */
4381 if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4383 const PALETTEENTRY *pal = NULL;
4384 DWORD width = pitch / 3;
4387 if (surface->palette)
4389 pal = surface->palette->palents;
4393 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4394 HeapFree(GetProcessHeap(), 0, mem);
4398 for(y = local_rect.top; y < local_rect.bottom; y++) {
4399 for(x = local_rect.left; x < local_rect.right; x++) {
4400 /* start lines pixels */
4401 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4402 const BYTE *green = blue + 1;
4403 const BYTE *red = green + 1;
4405 for(c = 0; c < 256; c++) {
4406 if(*red == pal[c].peRed &&
4407 *green == pal[c].peGreen &&
4408 *blue == pal[c].peBlue)
4410 *((BYTE *) dest + y * width + x) = c;
4416 HeapFree(GetProcessHeap(), 0, mem);
4420 /* Read the framebuffer contents into a texture. Note that this function
4421 * doesn't do any kind of flipping. Using this on an onscreen surface will
4422 * result in a flipped D3D texture. */
4423 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4425 struct wined3d_device *device = surface->resource.device;
4426 const struct wined3d_gl_info *gl_info;
4427 struct wined3d_context *context;
4429 context = context_acquire(device, surface);
4430 gl_info = context->gl_info;
4431 device_invalidate_state(device, STATE_FRAMEBUFFER);
4433 surface_prepare_texture(surface, context, srgb);
4434 surface_bind_and_dirtify(surface, context, srgb);
4436 TRACE("Reading back offscreen render target %p.\n", surface);
4440 if (surface_is_offscreen(surface))
4441 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4443 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
4444 checkGLcall("glReadBuffer");
4446 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4447 0, 0, 0, 0, surface->resource.width, surface->resource.height);
4448 checkGLcall("glCopyTexSubImage2D");
4452 context_release(context);
4455 /* Context activation is done by the caller. */
4456 static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4457 struct wined3d_context *context, BOOL srgb)
4459 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4460 enum wined3d_conversion_type convert;
4461 struct wined3d_format format;
4463 if (surface->flags & alloc_flag) return;
4465 d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4466 if (convert != WINED3D_CT_NONE || format.convert)
4467 surface->flags |= SFLAG_CONVERTED;
4468 else surface->flags &= ~SFLAG_CONVERTED;
4470 surface_bind_and_dirtify(surface, context, srgb);
4471 surface_allocate_surface(surface, context->gl_info, &format, srgb);
4472 surface->flags |= alloc_flag;
4475 /* Context activation is done by the caller. */
4476 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4478 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4480 struct wined3d_texture *texture = surface->container.u.texture;
4481 UINT sub_count = texture->level_count * texture->layer_count;
4484 TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4486 for (i = 0; i < sub_count; ++i)
4488 struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4489 surface_prepare_texture_internal(s, context, srgb);
4495 surface_prepare_texture_internal(surface, context, srgb);
4498 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4502 if (surface->rb_multisample)
4505 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4506 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4507 gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4508 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4509 TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4513 if (surface->rb_resolved)
4516 gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4517 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4518 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4519 surface->pow2Width, surface->pow2Height);
4520 TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4524 static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4525 const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4527 struct wined3d_device *device = surface->resource.device;
4528 UINT pitch = wined3d_surface_get_pitch(surface);
4529 const struct wined3d_gl_info *gl_info;
4530 struct wined3d_context *context;
4534 surface_get_rect(surface, rect, &local_rect);
4536 mem += local_rect.top * pitch + local_rect.left * bpp;
4537 w = local_rect.right - local_rect.left;
4538 h = local_rect.bottom - local_rect.top;
4540 /* Activate the correct context for the render target */
4541 context = context_acquire(device, surface);
4542 context_apply_blit_state(context, device);
4543 gl_info = context->gl_info;
4547 if (!surface_is_offscreen(surface))
4549 GLenum buffer = surface_get_gl_buffer(surface);
4550 TRACE("Unlocking %#x buffer.\n", buffer);
4551 context_set_draw_buffer(context, buffer);
4553 surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4554 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, -1.0f);
4558 /* Primary offscreen render target */
4559 TRACE("Offscreen render target.\n");
4560 context_set_draw_buffer(context, device->offscreenBuffer);
4562 gl_info->gl_ops.gl.p_glPixelZoom(1.0f, 1.0f);
4565 gl_info->gl_ops.gl.p_glRasterPos3i(local_rect.left, local_rect.top, 1);
4566 checkGLcall("glRasterPos3i");
4568 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4569 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4571 if (surface->flags & SFLAG_PBO)
4573 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4574 checkGLcall("glBindBufferARB");
4577 gl_info->gl_ops.gl.p_glDrawPixels(w, h, fmt, type, mem);
4578 checkGLcall("glDrawPixels");
4580 if (surface->flags & SFLAG_PBO)
4582 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4583 checkGLcall("glBindBufferARB");
4586 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4587 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4591 if (wined3d_settings.strict_draw_ordering
4592 || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4593 && surface->container.u.swapchain->front_buffer == surface))
4594 gl_info->gl_ops.gl.p_glFlush();
4596 context_release(context);
4599 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4601 /* FIXME: Is this really how color keys are supposed to work? I think it
4602 * makes more sense to compare the individual channels. */
4603 return color >= color_key->color_space_low_value
4604 && color <= color_key->color_space_high_value;
4607 void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4609 const struct wined3d_device *device = surface->resource.device;
4610 const struct wined3d_palette *pal = surface->palette;
4611 BOOL index_in_alpha = FALSE;
4614 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4615 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4616 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4617 * duplicate entries. Store the color key in the unused alpha component to speed the
4618 * download up and to make conversion unneeded. */
4619 index_in_alpha = primary_render_target_is_p8(device);
4623 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4626 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4627 * there's no palette at this time. */
4628 for (i = 0; i < 256; i++) table[i][3] = i;
4633 TRACE("Using surface palette %p\n", pal);
4634 /* Get the surface's palette */
4635 for (i = 0; i < 256; ++i)
4637 table[i][0] = pal->palents[i].peRed;
4638 table[i][1] = pal->palents[i].peGreen;
4639 table[i][2] = pal->palents[i].peBlue;
4641 /* When index_in_alpha is set the palette index is stored in the
4642 * alpha component. In case of a readback we can then read
4643 * GL_ALPHA. Color keying is handled in BltOverride using a
4644 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4645 * color key itself is passed to glAlphaFunc in other cases the
4646 * alpha component of pixels that should be masked away is set to 0. */
4649 else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4651 else if (pal->flags & WINEDDPCAPS_ALPHA)
4652 table[i][3] = pal->palents[i].peFlags;
4659 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4660 UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4665 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4666 src, dst, pitch, width, height, outpitch, conversion_type, surface);
4668 switch (conversion_type)
4670 case WINED3D_CT_NONE:
4672 memcpy(dst, src, pitch * height);
4676 case WINED3D_CT_PALETTED:
4677 case WINED3D_CT_PALETTED_CK:
4682 d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4684 for (y = 0; y < height; y++)
4686 source = src + pitch * y;
4687 dest = dst + outpitch * y;
4688 /* This is an 1 bpp format, using the width here is fine */
4689 for (x = 0; x < width; x++) {
4690 BYTE color = *source++;
4691 *dest++ = table[color][0];
4692 *dest++ = table[color][1];
4693 *dest++ = table[color][2];
4694 *dest++ = table[color][3];
4700 case WINED3D_CT_CK_565:
4702 /* Converting the 565 format in 5551 packed to emulate color-keying.
4704 Note : in all these conversion, it would be best to average the averaging
4705 pixels to get the color of the pixel that will be color-keyed to
4706 prevent 'color bleeding'. This will be done later on if ever it is
4709 Note2: Nvidia documents say that their driver does not support alpha + color keying
4710 on the same surface and disables color keying in such a case
4716 TRACE("Color keyed 565\n");
4718 for (y = 0; y < height; y++) {
4719 Source = (const WORD *)(src + y * pitch);
4720 Dest = (WORD *) (dst + y * outpitch);
4721 for (x = 0; x < width; x++ ) {
4722 WORD color = *Source++;
4723 *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
4724 if (!color_in_range(&surface->src_blt_color_key, color))
4732 case WINED3D_CT_CK_5551:
4734 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4738 TRACE("Color keyed 5551\n");
4739 for (y = 0; y < height; y++) {
4740 Source = (const WORD *)(src + y * pitch);
4741 Dest = (WORD *) (dst + y * outpitch);
4742 for (x = 0; x < width; x++ ) {
4743 WORD color = *Source++;
4745 if (!color_in_range(&surface->src_blt_color_key, color))
4748 *Dest &= ~(1 << 15);
4755 case WINED3D_CT_CK_RGB24:
4757 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4759 for (y = 0; y < height; y++)
4761 source = src + pitch * y;
4762 dest = dst + outpitch * y;
4763 for (x = 0; x < width; x++) {
4764 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4765 DWORD dstcolor = color << 8;
4766 if (!color_in_range(&surface->src_blt_color_key, color))
4768 *(DWORD*)dest = dstcolor;
4776 case WINED3D_CT_RGB32_888:
4778 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4780 for (y = 0; y < height; y++)
4782 source = src + pitch * y;
4783 dest = dst + outpitch * y;
4784 for (x = 0; x < width; x++) {
4785 DWORD color = 0xffffff & *(const DWORD*)source;
4786 DWORD dstcolor = color << 8;
4787 if (!color_in_range(&surface->src_blt_color_key, color))
4789 *(DWORD*)dest = dstcolor;
4797 case WINED3D_CT_CK_ARGB32:
4800 for (y = 0; y < height; ++y)
4802 source = src + pitch * y;
4803 dest = dst + outpitch * y;
4804 for (x = 0; x < width; ++x)
4806 DWORD color = *(const DWORD *)source;
4807 if (color_in_range(&surface->src_blt_color_key, color))
4808 color &= ~0xff000000;
4809 *(DWORD*)dest = color;
4818 ERR("Unsupported conversion type %#x.\n", conversion_type);
4823 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
4825 /* Flip the surface contents */
4830 front->hDC = back->hDC;
4834 /* Flip the DIBsection */
4836 HBITMAP tmp = front->dib.DIBsection;
4837 front->dib.DIBsection = back->dib.DIBsection;
4838 back->dib.DIBsection = tmp;
4841 /* Flip the surface data */
4845 tmp = front->dib.bitmap_data;
4846 front->dib.bitmap_data = back->dib.bitmap_data;
4847 back->dib.bitmap_data = tmp;
4849 tmp = front->resource.allocatedMemory;
4850 front->resource.allocatedMemory = back->resource.allocatedMemory;
4851 back->resource.allocatedMemory = tmp;
4853 tmp = front->resource.heapMemory;
4854 front->resource.heapMemory = back->resource.heapMemory;
4855 back->resource.heapMemory = tmp;
4860 GLuint tmp_pbo = front->pbo;
4861 front->pbo = back->pbo;
4862 back->pbo = tmp_pbo;
4865 /* Flip the opengl texture */
4869 tmp = back->texture_name;
4870 back->texture_name = front->texture_name;
4871 front->texture_name = tmp;
4873 tmp = back->texture_name_srgb;
4874 back->texture_name_srgb = front->texture_name_srgb;
4875 front->texture_name_srgb = tmp;
4877 tmp = back->rb_multisample;
4878 back->rb_multisample = front->rb_multisample;
4879 front->rb_multisample = tmp;
4881 tmp = back->rb_resolved;
4882 back->rb_resolved = front->rb_resolved;
4883 front->rb_resolved = tmp;
4885 resource_unload(&back->resource);
4886 resource_unload(&front->resource);
4890 DWORD tmp_flags = back->flags;
4891 back->flags = front->flags;
4892 front->flags = tmp_flags;
4896 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4897 * pixel copy calls. */
4898 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
4899 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
4901 struct wined3d_device *device = dst_surface->resource.device;
4902 const struct wined3d_gl_info *gl_info;
4905 struct wined3d_context *context;
4906 BOOL upsidedown = FALSE;
4907 RECT dst_rect = *dst_rect_in;
4910 if (dst_surface->container.type == WINED3D_CONTAINER_TEXTURE)
4911 dst_target = dst_surface->container.u.texture->target;
4913 dst_target = dst_surface->texture_target;
4915 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4916 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4918 if(dst_rect.top > dst_rect.bottom) {
4919 UINT tmp = dst_rect.bottom;
4920 dst_rect.bottom = dst_rect.top;
4925 context = context_acquire(device, src_surface);
4926 gl_info = context->gl_info;
4927 context_apply_blit_state(context, device);
4928 surface_internal_preload(dst_surface, SRGB_RGB);
4931 /* Bind the target texture */
4932 context_bind_texture(context, dst_target, dst_surface->texture_name);
4933 if (surface_is_offscreen(src_surface))
4935 TRACE("Reading from an offscreen target\n");
4936 upsidedown = !upsidedown;
4937 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4941 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
4943 checkGLcall("glReadBuffer");
4945 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
4946 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
4948 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4950 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4952 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4953 ERR("Texture filtering not supported in direct blit.\n");
4955 else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4956 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4958 ERR("Texture filtering not supported in direct blit\n");
4962 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4963 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4965 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
4966 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4967 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
4968 src_rect->left, src_surface->resource.height - src_rect->bottom,
4969 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4973 UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
4974 /* I have to process this row by row to swap the image,
4975 * otherwise it would be upside down, so stretching in y direction
4976 * doesn't cost extra time
4978 * However, stretching in x direction can be avoided if not necessary
4980 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
4981 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4983 /* Well, that stuff works, but it's very slow.
4984 * find a better way instead
4988 for (col = dst_rect.left; col < dst_rect.right; ++col)
4990 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4991 dst_rect.left + col /* x offset */, row /* y offset */,
4992 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
4997 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4998 dst_rect.left /* x offset */, row /* y offset */,
4999 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
5003 checkGLcall("glCopyTexSubImage2D");
5006 context_release(context);
5008 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5009 * path is never entered
5011 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5014 /* Uses the hardware to stretch and flip the image */
5015 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5016 const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5018 struct wined3d_device *device = dst_surface->resource.device;
5019 struct wined3d_swapchain *src_swapchain = NULL;
5020 GLuint src, backup = 0;
5021 float left, right, top, bottom; /* Texture coordinates */
5022 UINT fbwidth = src_surface->resource.width;
5023 UINT fbheight = src_surface->resource.height;
5024 const struct wined3d_gl_info *gl_info;
5025 struct wined3d_context *context;
5026 GLenum drawBuffer = GL_BACK;
5027 GLenum texture_target;
5028 BOOL noBackBufferBackup;
5030 BOOL upsidedown = FALSE;
5031 RECT dst_rect = *dst_rect_in;
5033 TRACE("Using hwstretch blit\n");
5034 /* Activate the Proper context for reading from the source surface, set it up for blitting */
5035 context = context_acquire(device, src_surface);
5036 gl_info = context->gl_info;
5037 context_apply_blit_state(context, device);
5038 surface_internal_preload(dst_surface, SRGB_RGB);
5040 src_offscreen = surface_is_offscreen(src_surface);
5041 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5042 if (!noBackBufferBackup && !src_surface->texture_name)
5044 /* Get it a description */
5045 surface_internal_preload(src_surface, SRGB_RGB);
5049 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5050 * This way we don't have to wait for the 2nd readback to finish to leave this function.
5052 if (context->aux_buffers >= 2)
5054 /* Got more than one aux buffer? Use the 2nd aux buffer */
5055 drawBuffer = GL_AUX1;
5057 else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5059 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5060 drawBuffer = GL_AUX0;
5063 if (noBackBufferBackup)
5065 gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
5066 checkGLcall("glGenTextures");
5067 context_bind_texture(context, GL_TEXTURE_2D, backup);
5068 texture_target = GL_TEXTURE_2D;
5072 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5073 * we are reading from the back buffer, the backup can be used as source texture
5075 texture_target = src_surface->texture_target;
5076 context_bind_texture(context, texture_target, src_surface->texture_name);
5077 gl_info->gl_ops.gl.p_glEnable(texture_target);
5078 checkGLcall("glEnable(texture_target)");
5080 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5081 src_surface->flags &= ~SFLAG_INTEXTURE;
5084 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5085 * glCopyTexSubImage is a bit picky about the parameters we pass to it
5087 if(dst_rect.top > dst_rect.bottom) {
5088 UINT tmp = dst_rect.bottom;
5089 dst_rect.bottom = dst_rect.top;
5096 TRACE("Reading from an offscreen target\n");
5097 upsidedown = !upsidedown;
5098 gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5102 gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5105 /* TODO: Only back up the part that will be overwritten */
5106 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
5108 checkGLcall("glCopyTexSubImage2D");
5110 /* No issue with overriding these - the sampler is dirty due to blit usage */
5111 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5112 wined3d_gl_mag_filter(magLookup, filter));
5113 checkGLcall("glTexParameteri");
5114 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5115 wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5116 checkGLcall("glTexParameteri");
5118 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5119 src_swapchain = src_surface->container.u.swapchain;
5120 if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
5122 src = backup ? backup : src_surface->texture_name;
5126 gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
5127 checkGLcall("glReadBuffer(GL_FRONT)");
5129 gl_info->gl_ops.gl.p_glGenTextures(1, &src);
5130 checkGLcall("glGenTextures(1, &src)");
5131 context_bind_texture(context, GL_TEXTURE_2D, src);
5133 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5134 * out for power of 2 sizes
5136 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5137 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5138 checkGLcall("glTexImage2D");
5139 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
5141 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5142 checkGLcall("glTexParameteri");
5143 gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5144 checkGLcall("glTexParameteri");
5146 gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
5147 checkGLcall("glReadBuffer(GL_BACK)");
5149 if (texture_target != GL_TEXTURE_2D)
5151 gl_info->gl_ops.gl.p_glDisable(texture_target);
5152 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5153 texture_target = GL_TEXTURE_2D;
5156 checkGLcall("glEnd and previous");
5158 left = src_rect->left;
5159 right = src_rect->right;
5163 top = src_surface->resource.height - src_rect->top;
5164 bottom = src_surface->resource.height - src_rect->bottom;
5168 top = src_surface->resource.height - src_rect->bottom;
5169 bottom = src_surface->resource.height - src_rect->top;
5172 if (src_surface->flags & SFLAG_NORMCOORD)
5174 left /= src_surface->pow2Width;
5175 right /= src_surface->pow2Width;
5176 top /= src_surface->pow2Height;
5177 bottom /= src_surface->pow2Height;
5180 /* draw the source texture stretched and upside down. The correct surface is bound already */
5181 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5182 gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5184 context_set_draw_buffer(context, drawBuffer);
5185 gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
5187 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5189 gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
5190 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5193 gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
5194 gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
5197 gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
5198 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5201 gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
5202 gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
5203 gl_info->gl_ops.gl.p_glEnd();
5204 checkGLcall("glEnd and previous");
5206 if (texture_target != dst_surface->texture_target)
5208 gl_info->gl_ops.gl.p_glDisable(texture_target);
5209 gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
5210 texture_target = dst_surface->texture_target;
5213 /* Now read the stretched and upside down image into the destination texture */
5214 context_bind_texture(context, texture_target, dst_surface->texture_name);
5215 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
5217 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5218 0, 0, /* We blitted the image to the origin */
5219 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5220 checkGLcall("glCopyTexSubImage2D");
5222 if (drawBuffer == GL_BACK)
5224 /* Write the back buffer backup back. */
5227 if (texture_target != GL_TEXTURE_2D)
5229 gl_info->gl_ops.gl.p_glDisable(texture_target);
5230 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5231 texture_target = GL_TEXTURE_2D;
5233 context_bind_texture(context, GL_TEXTURE_2D, backup);
5237 if (texture_target != src_surface->texture_target)
5239 gl_info->gl_ops.gl.p_glDisable(texture_target);
5240 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
5241 texture_target = src_surface->texture_target;
5243 context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5246 gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5248 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
5249 gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
5252 gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5253 gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5256 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5257 (float)fbheight / (float)src_surface->pow2Height);
5258 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
5261 gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5262 gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
5263 gl_info->gl_ops.gl.p_glEnd();
5265 gl_info->gl_ops.gl.p_glDisable(texture_target);
5266 checkGLcall("glDisable(texture_target)");
5269 if (src != src_surface->texture_name && src != backup)
5271 gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
5272 checkGLcall("glDeleteTextures(1, &src)");
5276 gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
5277 checkGLcall("glDeleteTextures(1, &backup)");
5282 if (wined3d_settings.strict_draw_ordering)
5283 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5285 context_release(context);
5287 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5288 * path is never entered
5290 surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5293 /* Front buffer coordinates are always full screen coordinates, but our GL
5294 * drawable is limited to the window's client area. The sysmem and texture
5295 * copies do have the full screen size. Note that GL has a bottom-left
5296 * origin, while D3D has a top-left origin. */
5297 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5299 UINT drawable_height;
5301 if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5302 && surface == surface->container.u.swapchain->front_buffer)
5304 POINT offset = {0, 0};
5307 ScreenToClient(window, &offset);
5308 OffsetRect(rect, offset.x, offset.y);
5310 GetClientRect(window, &windowsize);
5311 drawable_height = windowsize.bottom - windowsize.top;
5315 drawable_height = surface->resource.height;
5318 rect->top = drawable_height - rect->top;
5319 rect->bottom = drawable_height - rect->bottom;
5322 static void surface_blt_to_drawable(const struct wined3d_device *device,
5323 enum wined3d_texture_filter_type filter, BOOL color_key,
5324 struct wined3d_surface *src_surface, const RECT *src_rect_in,
5325 struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5327 const struct wined3d_gl_info *gl_info;
5328 struct wined3d_context *context;
5329 RECT src_rect, dst_rect;
5331 src_rect = *src_rect_in;
5332 dst_rect = *dst_rect_in;
5334 /* Make sure the surface is up-to-date. This should probably use
5335 * surface_load_location() and worry about the destination surface too,
5336 * unless we're overwriting it completely. */
5337 surface_internal_preload(src_surface, SRGB_RGB);
5339 /* Activate the destination context, set it up for blitting */
5340 context = context_acquire(device, dst_surface);
5341 gl_info = context->gl_info;
5342 context_apply_blit_state(context, device);
5344 if (!surface_is_offscreen(dst_surface))
5345 surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5347 device->blitter->set_shader(device->blit_priv, context, src_surface);
5353 gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
5354 checkGLcall("glEnable(GL_ALPHA_TEST)");
5356 /* When the primary render target uses P8, the alpha component
5357 * contains the palette index. Which means that the colorkey is one of
5358 * the palette entries. In other cases pixels that should be masked
5359 * away have alpha set to 0. */
5360 if (primary_render_target_is_p8(device))
5361 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
5362 (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5364 gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
5365 checkGLcall("glAlphaFunc");
5369 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5370 checkGLcall("glDisable(GL_ALPHA_TEST)");
5373 draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5377 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5378 checkGLcall("glDisable(GL_ALPHA_TEST)");
5383 /* Leave the opengl state valid for blitting */
5384 device->blitter->unset_shader(context->gl_info);
5386 if (wined3d_settings.strict_draw_ordering
5387 || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5388 && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5389 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5391 context_release(context);
5394 /* Do not call while under the GL lock. */
5395 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5397 struct wined3d_device *device = s->resource.device;
5398 const struct blit_shader *blitter;
5400 blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5401 NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5404 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5405 return WINED3DERR_INVALIDCALL;
5408 return blitter->color_fill(device, s, rect, color);
5411 /* Do not call while under the GL lock. */
5412 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5413 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5414 enum wined3d_texture_filter_type filter)
5416 struct wined3d_device *device = dst_surface->resource.device;
5417 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5418 struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5420 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5421 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5422 flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5424 /* Get the swapchain. One of the surfaces has to be a primary surface */
5425 if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5427 WARN("Destination is in sysmem, rejecting gl blt\n");
5428 return WINED3DERR_INVALIDCALL;
5431 if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5432 dstSwapchain = dst_surface->container.u.swapchain;
5436 if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5438 WARN("Src is in sysmem, rejecting gl blt\n");
5439 return WINED3DERR_INVALIDCALL;
5442 if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5443 srcSwapchain = src_surface->container.u.swapchain;
5446 /* Early sort out of cases where no render target is used */
5447 if (!dstSwapchain && !srcSwapchain
5448 && src_surface != device->fb.render_targets[0]
5449 && dst_surface != device->fb.render_targets[0])
5451 TRACE("No surface is render target, not using hardware blit.\n");
5452 return WINED3DERR_INVALIDCALL;
5455 /* No destination color keying supported */
5456 if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5458 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5459 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5460 return WINED3DERR_INVALIDCALL;
5463 if (dstSwapchain && dstSwapchain == srcSwapchain)
5465 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5466 return WINED3DERR_INVALIDCALL;
5469 if (dstSwapchain && srcSwapchain)
5471 FIXME("Implement hardware blit between two different swapchains\n");
5472 return WINED3DERR_INVALIDCALL;
5477 /* Handled with regular texture -> swapchain blit */
5478 if (src_surface == device->fb.render_targets[0])
5479 TRACE("Blit from active render target to a swapchain\n");
5481 else if (srcSwapchain && dst_surface == device->fb.render_targets[0])
5483 FIXME("Implement blit from a swapchain to the active render target\n");
5484 return WINED3DERR_INVALIDCALL;
5487 if ((srcSwapchain || src_surface == device->fb.render_targets[0]) && !dstSwapchain)
5489 /* Blit from render target to texture */
5492 /* P8 read back is not implemented */
5493 if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5494 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5496 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5497 return WINED3DERR_INVALIDCALL;
5500 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5502 TRACE("Color keying not supported by frame buffer to texture blit\n");
5503 return WINED3DERR_INVALIDCALL;
5504 /* Destination color key is checked above */
5507 if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5512 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5513 * flip the image nor scale it.
5515 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5516 * -> If the app wants a image width an unscaled width, copy it line per line
5517 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5518 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5519 * back buffer. This is slower than reading line per line, thus not used for flipping
5520 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5521 * pixel by pixel. */
5522 if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5523 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5525 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5526 fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5530 TRACE("Using hardware stretching to flip / stretch the texture.\n");
5531 fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5534 if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5536 HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5537 dst_surface->resource.allocatedMemory = NULL;
5538 dst_surface->resource.heapMemory = NULL;
5542 dst_surface->flags &= ~SFLAG_INSYSMEM;
5547 else if (src_surface)
5549 /* Blit from offscreen surface to render target */
5550 struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5551 DWORD oldCKeyFlags = src_surface->CKeyFlags;
5553 TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5555 if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5556 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5557 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5559 FIXME("Unsupported blit operation falling back to software\n");
5560 return WINED3DERR_INVALIDCALL;
5563 /* Color keying: Check if we have to do a color keyed blt,
5564 * and if not check if a color key is activated.
5566 * Just modify the color keying parameters in the surface and restore them afterwards
5567 * The surface keeps track of the color key last used to load the opengl surface.
5568 * PreLoad will catch the change to the flags and color key and reload if necessary.
5570 if (flags & WINEDDBLT_KEYSRC)
5572 /* Use color key from surface */
5574 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5576 /* Use color key from DDBltFx */
5577 src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5578 src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5582 /* Do not use color key */
5583 src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5586 surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5587 src_surface, src_rect, dst_surface, dst_rect);
5589 /* Restore the color key parameters */
5590 src_surface->CKeyFlags = oldCKeyFlags;
5591 src_surface->src_blt_color_key = old_blt_key;
5593 surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5598 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5599 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5600 return WINED3DERR_INVALIDCALL;
5603 /* GL locking is done by the caller */
5604 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5605 GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5607 struct wined3d_device *device = surface->resource.device;
5608 const struct wined3d_gl_info *gl_info = context->gl_info;
5609 GLint compare_mode = GL_NONE;
5610 struct blt_info info;
5611 GLint old_binding = 0;
5614 gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5616 gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
5617 gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
5618 gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5619 gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
5620 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
5621 gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
5622 gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
5623 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5624 gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5625 gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
5626 gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
5628 SetRect(&rect, 0, h, w, 0);
5629 surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5630 context_active_texture(context, context->gl_info, 0);
5631 gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
5632 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
5633 if (gl_info->supported[ARB_SHADOW])
5635 gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5636 if (compare_mode != GL_NONE)
5637 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5640 device->shader_backend->shader_select_depth_blt(device->shader_priv,
5641 gl_info, info.tex_type, &surface->ds_current_size);
5643 gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
5644 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
5645 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
5646 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
5647 gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
5648 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
5649 gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
5650 gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
5651 gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
5652 gl_info->gl_ops.gl.p_glEnd();
5654 if (compare_mode != GL_NONE)
5655 gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5656 gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
5658 gl_info->gl_ops.gl.p_glPopAttrib();
5660 device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5663 void surface_modify_ds_location(struct wined3d_surface *surface,
5664 DWORD location, UINT w, UINT h)
5666 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5668 if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5669 FIXME("Invalid location (%#x) specified.\n", location);
5671 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5672 || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5674 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5676 TRACE("Passing to container.\n");
5677 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5681 surface->ds_current_size.cx = w;
5682 surface->ds_current_size.cy = h;
5683 surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5684 surface->flags |= location;
5687 /* Context activation is done by the caller. */
5688 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5690 const struct wined3d_gl_info *gl_info = context->gl_info;
5691 struct wined3d_device *device = surface->resource.device;
5694 TRACE("surface %p, new location %#x.\n", surface, location);
5696 /* TODO: Make this work for modes other than FBO */
5697 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5699 if (!(surface->flags & location))
5701 w = surface->ds_current_size.cx;
5702 h = surface->ds_current_size.cy;
5703 surface->ds_current_size.cx = 0;
5704 surface->ds_current_size.cy = 0;
5708 w = surface->resource.width;
5709 h = surface->resource.height;
5712 if (surface->ds_current_size.cx == surface->resource.width
5713 && surface->ds_current_size.cy == surface->resource.height)
5715 TRACE("Location (%#x) is already up to date.\n", location);
5719 if (surface->current_renderbuffer)
5721 FIXME("Not supported with fixed up depth stencil.\n");
5725 if (surface->flags & SFLAG_DISCARDED)
5727 TRACE("Surface was discarded, no need copy data.\n");
5730 case SFLAG_INTEXTURE:
5731 surface_prepare_texture(surface, context, FALSE);
5733 case SFLAG_INRB_MULTISAMPLE:
5734 surface_prepare_rb(surface, gl_info, TRUE);
5736 case SFLAG_INDRAWABLE:
5740 FIXME("Unhandled location %#x\n", location);
5742 surface->flags &= ~SFLAG_DISCARDED;
5743 surface->flags |= location;
5744 surface->ds_current_size.cx = surface->resource.width;
5745 surface->ds_current_size.cy = surface->resource.height;
5749 if (!(surface->flags & SFLAG_LOCATIONS))
5751 FIXME("No up to date depth stencil location.\n");
5752 surface->flags |= location;
5753 surface->ds_current_size.cx = surface->resource.width;
5754 surface->ds_current_size.cy = surface->resource.height;
5758 if (location == SFLAG_INTEXTURE)
5760 GLint old_binding = 0;
5763 /* The render target is allowed to be smaller than the depth/stencil
5764 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5765 * than the offscreen surface. Don't overwrite the offscreen surface
5766 * with undefined data. */
5767 w = min(w, context->swapchain->desc.backbuffer_width);
5768 h = min(h, context->swapchain->desc.backbuffer_height);
5770 TRACE("Copying onscreen depth buffer to depth texture.\n");
5774 if (!device->depth_blt_texture)
5775 gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
5777 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5778 * directly on the FBO texture. That's because we need to flip. */
5779 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5780 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5781 if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
5783 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5784 bind_target = GL_TEXTURE_RECTANGLE_ARB;
5788 gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5789 bind_target = GL_TEXTURE_2D;
5791 gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
5792 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5793 * internal format, because the internal format might include stencil
5794 * data. In principle we should copy stencil data as well, but unless
5795 * the driver supports stencil export it's hard to do, and doesn't
5796 * seem to be needed in practice. If the hardware doesn't support
5797 * writing stencil data, the glCopyTexImage2D() call might trigger
5798 * software fallbacks. */
5799 gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
5800 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5801 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5802 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5803 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5804 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
5805 gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5806 gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
5808 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5809 NULL, surface, SFLAG_INTEXTURE);
5810 context_set_draw_buffer(context, GL_NONE);
5811 gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
5813 /* Do the actual blit */
5814 surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
5815 checkGLcall("depth_blt");
5817 context_invalidate_state(context, STATE_FRAMEBUFFER);
5821 if (wined3d_settings.strict_draw_ordering)
5822 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5824 else if (location == SFLAG_INDRAWABLE)
5826 TRACE("Copying depth texture to onscreen depth buffer.\n");
5830 context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5831 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5832 surface_depth_blt(surface, context, surface->texture_name,
5833 0, surface->pow2Height - h, w, h, surface->texture_target);
5834 checkGLcall("depth_blt");
5836 context_invalidate_state(context, STATE_FRAMEBUFFER);
5840 if (wined3d_settings.strict_draw_ordering)
5841 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5845 ERR("Invalid location (%#x) specified.\n", location);
5848 surface->flags |= location;
5849 surface->ds_current_size.cx = surface->resource.width;
5850 surface->ds_current_size.cy = surface->resource.height;
5853 void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
5855 const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
5856 struct wined3d_surface *overlay;
5858 TRACE("surface %p, location %s, persistent %#x.\n",
5859 surface, debug_surflocation(location), persistent);
5861 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
5862 && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
5863 && (location & SFLAG_INDRAWABLE))
5864 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5866 if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
5867 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
5868 location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
5872 if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5873 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
5875 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5877 TRACE("Passing to container.\n");
5878 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5881 surface->flags &= ~SFLAG_LOCATIONS;
5882 surface->flags |= location;
5884 /* Redraw emulated overlays, if any */
5885 if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
5887 LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
5889 surface_draw_overlay(overlay);
5895 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
5897 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5899 TRACE("Passing to container\n");
5900 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5903 surface->flags &= ~location;
5906 if (!(surface->flags & SFLAG_LOCATIONS))
5908 ERR("Surface %p does not have any up to date location.\n", surface);
5912 static DWORD resource_access_from_location(DWORD location)
5916 case SFLAG_INSYSMEM:
5917 return WINED3D_RESOURCE_ACCESS_CPU;
5919 case SFLAG_INDRAWABLE:
5920 case SFLAG_INSRGBTEX:
5921 case SFLAG_INTEXTURE:
5922 case SFLAG_INRB_MULTISAMPLE:
5923 case SFLAG_INRB_RESOLVED:
5924 return WINED3D_RESOURCE_ACCESS_GPU;
5927 FIXME("Unhandled location %#x.\n", location);
5932 static void surface_load_sysmem(struct wined3d_surface *surface,
5933 const struct wined3d_gl_info *gl_info, const RECT *rect)
5935 surface_prepare_system_memory(surface);
5937 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
5938 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5940 /* Download the surface to system memory. */
5941 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
5943 struct wined3d_device *device = surface->resource.device;
5944 struct wined3d_context *context;
5946 /* TODO: Use already acquired context when possible. */
5947 context = context_acquire(device, NULL);
5949 surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
5950 surface_download_data(surface, gl_info);
5952 context_release(context);
5957 if (surface->flags & SFLAG_INDRAWABLE)
5959 read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
5960 wined3d_surface_get_pitch(surface));
5964 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
5965 surface, surface->flags & SFLAG_LOCATIONS);
5968 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
5969 const struct wined3d_gl_info *gl_info, const RECT *rect)
5971 struct wined3d_device *device = surface->resource.device;
5972 enum wined3d_conversion_type convert;
5973 struct wined3d_format format;
5977 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
5979 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5980 return WINED3DERR_INVALIDCALL;
5983 if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
5984 surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5986 if (surface->flags & SFLAG_INTEXTURE)
5990 surface_get_rect(surface, rect, &r);
5991 surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
5996 if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
5998 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5999 * path through sysmem. */
6000 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6003 d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
6005 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6006 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
6008 if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
6010 struct wined3d_context *context;
6012 TRACE("Removing the pbo attached to surface %p.\n", surface);
6014 /* TODO: Use already acquired context when possible. */
6015 context = context_acquire(device, NULL);
6017 surface_remove_pbo(surface, gl_info);
6019 context_release(context);
6022 if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
6024 UINT height = surface->resource.height;
6025 UINT width = surface->resource.width;
6026 UINT src_pitch, dst_pitch;
6028 byte_count = format.conv_byte_count;
6029 src_pitch = wined3d_surface_get_pitch(surface);
6031 /* Stick to the alignment for the converted surface too, makes it
6032 * easier to load the surface. */
6033 dst_pitch = width * byte_count;
6034 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6036 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6038 ERR("Out of memory (%u).\n", dst_pitch * height);
6039 return E_OUTOFMEMORY;
6042 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6043 src_pitch, width, height, dst_pitch, convert, surface);
6045 surface->flags |= SFLAG_CONVERTED;
6049 surface->flags &= ~SFLAG_CONVERTED;
6050 mem = surface->resource.allocatedMemory;
6051 byte_count = format.byte_count;
6054 flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6056 /* Don't delete PBO memory. */
6057 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6058 HeapFree(GetProcessHeap(), 0, mem);
6063 static HRESULT surface_load_texture(struct wined3d_surface *surface,
6064 const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6066 RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6067 struct wined3d_device *device = surface->resource.device;
6068 enum wined3d_conversion_type convert;
6069 struct wined3d_context *context;
6070 UINT width, src_pitch, dst_pitch;
6071 struct wined3d_bo_address data;
6072 struct wined3d_format format;
6073 POINT dst_point = {0, 0};
6076 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6077 && surface_is_offscreen(surface)
6078 && (surface->flags & SFLAG_INDRAWABLE))
6080 surface_load_fb_texture(surface, srgb);
6085 if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6086 && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6087 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6088 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6089 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6092 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6093 &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6095 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6096 &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6101 if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6102 && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6103 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6104 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6105 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6107 DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6108 DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6109 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6111 surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6112 &rect, surface, dst_location, &rect);
6117 /* Upload from system memory */
6119 d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6120 TRUE /* We will use textures */, &format, &convert);
6124 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6126 /* Performance warning... */
6127 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6128 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6133 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6135 /* Performance warning... */
6136 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6137 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6141 if (!(surface->flags & SFLAG_INSYSMEM))
6143 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6144 /* Lets hope we get it from somewhere... */
6145 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6148 /* TODO: Use already acquired context when possible. */
6149 context = context_acquire(device, NULL);
6151 surface_prepare_texture(surface, context, srgb);
6152 surface_bind_and_dirtify(surface, context, srgb);
6154 if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6156 surface->flags |= SFLAG_GLCKEY;
6157 surface->gl_color_key = surface->src_blt_color_key;
6159 else surface->flags &= ~SFLAG_GLCKEY;
6161 width = surface->resource.width;
6162 src_pitch = wined3d_surface_get_pitch(surface);
6164 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6165 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6167 if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6169 TRACE("Removing the pbo attached to surface %p.\n", surface);
6170 surface_remove_pbo(surface, gl_info);
6175 /* This code is entered for texture formats which need a fixup. */
6176 UINT height = surface->resource.height;
6178 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6179 dst_pitch = width * format.conv_byte_count;
6180 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6182 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6184 ERR("Out of memory (%u).\n", dst_pitch * height);
6185 context_release(context);
6186 return E_OUTOFMEMORY;
6188 format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6189 format.byte_count = format.conv_byte_count;
6190 src_pitch = dst_pitch;
6192 else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6194 /* This code is only entered for color keying fixups */
6195 UINT height = surface->resource.height;
6197 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6198 dst_pitch = width * format.conv_byte_count;
6199 dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6201 if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6203 ERR("Out of memory (%u).\n", dst_pitch * height);
6204 context_release(context);
6205 return E_OUTOFMEMORY;
6207 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6208 width, height, dst_pitch, convert, surface);
6209 format.byte_count = format.conv_byte_count;
6210 src_pitch = dst_pitch;
6214 mem = surface->resource.allocatedMemory;
6217 data.buffer_object = surface->pbo;
6219 surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6221 context_release(context);
6223 /* Don't delete PBO memory. */
6224 if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6225 HeapFree(GetProcessHeap(), 0, mem);
6230 static void surface_multisample_resolve(struct wined3d_surface *surface)
6232 RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6234 if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6235 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6237 surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6238 surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6241 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6243 struct wined3d_device *device = surface->resource.device;
6244 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6247 TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6249 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6251 if (location == SFLAG_INTEXTURE)
6253 struct wined3d_context *context = context_acquire(device, NULL);
6254 surface_load_ds_location(surface, context, location);
6255 context_release(context);
6260 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location));
6261 return WINED3DERR_INVALIDCALL;
6265 if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6266 location = SFLAG_INTEXTURE;
6268 if (surface->flags & location)
6270 TRACE("Location already up to date.\n");
6272 if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6273 && surface_need_pbo(surface, gl_info))
6274 surface_load_pbo(surface, gl_info);
6279 if (WARN_ON(d3d_surface))
6281 DWORD required_access = resource_access_from_location(location);
6282 if ((surface->resource.access_flags & required_access) != required_access)
6283 WARN("Operation requires %#x access, but surface only has %#x.\n",
6284 required_access, surface->resource.access_flags);
6287 if (!(surface->flags & SFLAG_LOCATIONS))
6289 ERR("Surface %p does not have any up to date location.\n", surface);
6290 surface->flags |= SFLAG_LOST;
6291 return WINED3DERR_DEVICELOST;
6296 case SFLAG_INSYSMEM:
6297 surface_load_sysmem(surface, gl_info, rect);
6300 case SFLAG_INDRAWABLE:
6301 if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6305 case SFLAG_INRB_RESOLVED:
6306 surface_multisample_resolve(surface);
6309 case SFLAG_INTEXTURE:
6310 case SFLAG_INSRGBTEX:
6311 if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6316 ERR("Don't know how to handle location %#x.\n", location);
6322 surface->flags |= location;
6324 if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6325 surface_evict_sysmem(surface);
6328 if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6329 && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6331 surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6337 BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6339 struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6341 /* Not on a swapchain - must be offscreen */
6342 if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6344 /* The front buffer is always onscreen */
6345 if (surface == swapchain->front_buffer) return FALSE;
6347 /* If the swapchain is rendered to an FBO, the backbuffer is
6348 * offscreen, otherwise onscreen */
6349 return swapchain->render_to_fbo;
6352 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6353 /* Context activation is done by the caller. */
6354 static void ffp_blit_free(struct wined3d_device *device) { }
6356 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6357 /* Context activation is done by the caller. */
6358 static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6361 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) != 0;
6364 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6365 target = surface->container.u.texture->target;
6367 target = surface->texture_target;
6369 d3dfmt_p8_init_palette(surface, table, colorkey_active);
6371 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6373 GL_EXTCALL(glColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6377 /* Context activation is done by the caller. */
6378 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6380 enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6381 const struct wined3d_gl_info *gl_info = context->gl_info;
6384 if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6385 target = surface->container.u.texture->target;
6387 target = surface->texture_target;
6389 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6390 * else the surface is converted in software at upload time in LoadLocation.
6392 if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6393 && gl_info->supported[EXT_PALETTED_TEXTURE])
6394 ffp_blit_p8_upload_palette(surface, gl_info);
6397 gl_info->gl_ops.gl.p_glEnable(target);
6398 checkGLcall("glEnable(target)");
6403 /* Context activation is done by the caller. */
6404 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6407 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
6408 checkGLcall("glDisable(GL_TEXTURE_2D)");
6409 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6411 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6412 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6414 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6416 gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
6417 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6422 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6423 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6424 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6426 enum complex_fixup src_fixup;
6430 case WINED3D_BLIT_OP_COLOR_BLIT:
6431 if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6434 src_fixup = get_complex_fixup(src_format->color_fixup);
6435 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6437 TRACE("Checking support for fixup:\n");
6438 dump_color_fixup_desc(src_format->color_fixup);
6441 if (!is_identity_fixup(dst_format->color_fixup))
6443 TRACE("Destination fixups are not supported\n");
6447 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6449 TRACE("P8 fixup supported\n");
6453 /* We only support identity conversions. */
6454 if (is_identity_fixup(src_format->color_fixup))
6460 TRACE("[FAILED]\n");
6463 case WINED3D_BLIT_OP_COLOR_FILL:
6464 if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6467 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6469 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6472 else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6474 TRACE("Color fill not supported\n");
6478 /* FIXME: We should reject color fills on formats with fixups,
6479 * but this would break P8 color fills for example. */
6483 case WINED3D_BLIT_OP_DEPTH_FILL:
6487 TRACE("Unsupported blit_op=%d\n", blit_op);
6492 /* Do not call while under the GL lock. */
6493 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6494 const RECT *dst_rect, const struct wined3d_color *color)
6496 const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6497 struct wined3d_fb_state fb = {&dst_surface, NULL};
6499 device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6504 /* Do not call while under the GL lock. */
6505 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6506 struct wined3d_surface *surface, const RECT *rect, float depth)
6508 const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6509 struct wined3d_fb_state fb = {NULL, surface};
6511 device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6516 const struct blit_shader ffp_blit = {
6522 ffp_blit_color_fill,
6523 ffp_blit_depth_fill,
6526 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6531 /* Context activation is done by the caller. */
6532 static void cpu_blit_free(struct wined3d_device *device)
6536 /* Context activation is done by the caller. */
6537 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6542 /* Context activation is done by the caller. */
6543 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6547 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6548 const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6549 const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6551 if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6559 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6560 UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6561 const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6563 UINT row_block_count;
6564 const BYTE *src_row;
6571 row_block_count = (update_w + format->block_width - 1) / format->block_width;
6575 for (y = 0; y < update_h; y += format->block_height)
6577 memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6578 src_row += src_pitch;
6579 dst_row += dst_pitch;
6585 if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6587 src_row += (((update_h / format->block_height) - 1) * src_pitch);
6591 case WINED3DFMT_DXT1:
6592 for (y = 0; y < update_h; y += format->block_height)
6597 BYTE control_row[4];
6600 const struct block *s = (const struct block *)src_row;
6601 struct block *d = (struct block *)dst_row;
6603 for (x = 0; x < row_block_count; ++x)
6605 d[x].color[0] = s[x].color[0];
6606 d[x].color[1] = s[x].color[1];
6607 d[x].control_row[0] = s[x].control_row[3];
6608 d[x].control_row[1] = s[x].control_row[2];
6609 d[x].control_row[2] = s[x].control_row[1];
6610 d[x].control_row[3] = s[x].control_row[0];
6612 src_row -= src_pitch;
6613 dst_row += dst_pitch;
6617 case WINED3DFMT_DXT3:
6618 for (y = 0; y < update_h; y += format->block_height)
6624 BYTE control_row[4];
6627 const struct block *s = (const struct block *)src_row;
6628 struct block *d = (struct block *)dst_row;
6630 for (x = 0; x < row_block_count; ++x)
6632 d[x].alpha_row[0] = s[x].alpha_row[3];
6633 d[x].alpha_row[1] = s[x].alpha_row[2];
6634 d[x].alpha_row[2] = s[x].alpha_row[1];
6635 d[x].alpha_row[3] = s[x].alpha_row[0];
6636 d[x].color[0] = s[x].color[0];
6637 d[x].color[1] = s[x].color[1];
6638 d[x].control_row[0] = s[x].control_row[3];
6639 d[x].control_row[1] = s[x].control_row[2];
6640 d[x].control_row[2] = s[x].control_row[1];
6641 d[x].control_row[3] = s[x].control_row[0];
6643 src_row -= src_pitch;
6644 dst_row += dst_pitch;
6649 FIXME("Compressed flip not implemented for format %s.\n",
6650 debug_d3dformat(format->id));
6655 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
6656 debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
6661 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
6662 struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
6663 const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
6665 int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
6666 const struct wined3d_format *src_format, *dst_format;
6667 struct wined3d_surface *orig_src = src_surface;
6668 struct wined3d_map_desc dst_map, src_map;
6669 const BYTE *sbase = NULL;
6670 HRESULT hr = WINED3D_OK;
6675 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6676 dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
6677 flags, fx, debug_d3dtexturefiltertype(filter));
6679 if (src_surface == dst_surface)
6681 wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
6683 src_format = dst_surface->resource.format;
6684 dst_format = src_format;
6688 dst_format = dst_surface->resource.format;
6691 if (dst_surface->resource.format->id != src_surface->resource.format->id)
6693 src_surface = surface_convert_format(src_surface, dst_format->id);
6696 /* The conv function writes a FIXME */
6697 WARN("Cannot convert source surface format to dest format.\n");
6701 wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
6702 src_format = src_surface->resource.format;
6706 src_format = dst_format;
6709 wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
6712 bpp = dst_surface->resource.format->byte_count;
6713 srcheight = src_rect->bottom - src_rect->top;
6714 srcwidth = src_rect->right - src_rect->left;
6715 dstheight = dst_rect->bottom - dst_rect->top;
6716 dstwidth = dst_rect->right - dst_rect->left;
6717 width = (dst_rect->right - dst_rect->left) * bpp;
6720 sbase = (BYTE *)src_map.data
6721 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
6722 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
6723 if (src_surface != dst_surface)
6724 dbuf = dst_map.data;
6726 dbuf = (BYTE *)dst_map.data
6727 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
6728 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
6730 if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
6732 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
6734 if (src_surface == dst_surface)
6736 FIXME("Only plain blits supported on compressed surfaces.\n");
6741 if (srcheight != dstheight || srcwidth != dstwidth)
6743 WARN("Stretching not supported on compressed surfaces.\n");
6744 hr = WINED3DERR_INVALIDCALL;
6748 if (!surface_check_block_align(src_surface, src_rect))
6750 WARN("Source rectangle not block-aligned.\n");
6751 hr = WINED3DERR_INVALIDCALL;
6755 if (!surface_check_block_align(dst_surface, dst_rect))
6757 WARN("Destination rectangle not block-aligned.\n");
6758 hr = WINED3DERR_INVALIDCALL;
6762 hr = surface_cpu_blt_compressed(sbase, dbuf,
6763 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
6764 src_format, flags, fx);
6768 /* First, all the 'source-less' blits */
6769 if (flags & WINEDDBLT_COLORFILL)
6771 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
6772 flags &= ~WINEDDBLT_COLORFILL;
6775 if (flags & WINEDDBLT_DEPTHFILL)
6777 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6779 if (flags & WINEDDBLT_ROP)
6781 /* Catch some degenerate cases here. */
6785 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
6787 case 0xaa0029: /* No-op */
6790 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
6792 case SRCCOPY: /* Well, we do that below? */
6795 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
6798 flags &= ~WINEDDBLT_ROP;
6800 if (flags & WINEDDBLT_DDROPS)
6802 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
6804 /* Now the 'with source' blits. */
6807 int sx, xinc, sy, yinc;
6809 if (!dstwidth || !dstheight) /* Hmm... stupid program? */
6812 if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
6813 && (srcwidth != dstwidth || srcheight != dstheight))
6815 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6816 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
6819 xinc = (srcwidth << 16) / dstwidth;
6820 yinc = (srcheight << 16) / dstheight;
6824 /* No effects, we can cheat here. */
6825 if (dstwidth == srcwidth)
6827 if (dstheight == srcheight)
6829 /* No stretching in either direction. This needs to be as
6830 * fast as possible. */
6833 /* Check for overlapping surfaces. */
6834 if (src_surface != dst_surface || dst_rect->top < src_rect->top
6835 || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
6837 /* No overlap, or dst above src, so copy from top downwards. */
6838 for (y = 0; y < dstheight; ++y)
6840 memcpy(dbuf, sbuf, width);
6841 sbuf += src_map.row_pitch;
6842 dbuf += dst_map.row_pitch;
6845 else if (dst_rect->top > src_rect->top)
6847 /* Copy from bottom upwards. */
6848 sbuf += src_map.row_pitch * dstheight;
6849 dbuf += dst_map.row_pitch * dstheight;
6850 for (y = 0; y < dstheight; ++y)
6852 sbuf -= src_map.row_pitch;
6853 dbuf -= dst_map.row_pitch;
6854 memcpy(dbuf, sbuf, width);
6859 /* Src and dst overlapping on the same line, use memmove. */
6860 for (y = 0; y < dstheight; ++y)
6862 memmove(dbuf, sbuf, width);
6863 sbuf += src_map.row_pitch;
6864 dbuf += dst_map.row_pitch;
6870 /* Stretching in y direction only. */
6871 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6873 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6874 memcpy(dbuf, sbuf, width);
6875 dbuf += dst_map.row_pitch;
6881 /* Stretching in X direction. */
6883 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6885 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6887 if ((sy >> 16) == (last_sy >> 16))
6889 /* This source row is the same as last source row -
6890 * Copy the already stretched row. */
6891 memcpy(dbuf, dbuf - dst_map.row_pitch, width);
6895 #define STRETCH_ROW(type) \
6897 const type *s = (const type *)sbuf; \
6898 type *d = (type *)dbuf; \
6899 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6900 d[x] = s[sx >> 16]; \
6918 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
6922 s = sbuf + 3 * (sx >> 16);
6923 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
6924 d[0] = (pixel ) & 0xff;
6925 d[1] = (pixel >> 8) & 0xff;
6926 d[2] = (pixel >> 16) & 0xff;
6932 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
6933 hr = WINED3DERR_NOTAVAILABLE;
6938 dbuf += dst_map.row_pitch;
6945 LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
6946 DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
6947 DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
6948 if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
6950 /* The color keying flags are checked for correctness in ddraw */
6951 if (flags & WINEDDBLT_KEYSRC)
6953 keylow = src_surface->src_blt_color_key.color_space_low_value;
6954 keyhigh = src_surface->src_blt_color_key.color_space_high_value;
6956 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6958 keylow = fx->ddckSrcColorkey.color_space_low_value;
6959 keyhigh = fx->ddckSrcColorkey.color_space_high_value;
6962 if (flags & WINEDDBLT_KEYDEST)
6964 /* Destination color keys are taken from the source surface! */
6965 destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
6966 destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
6968 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
6970 destkeylow = fx->ddckDestColorkey.color_space_low_value;
6971 destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
6981 get_color_masks(src_format, masks);
6986 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
6989 if (flags & WINEDDBLT_DDFX)
6991 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
6994 dTopRight = dbuf + ((dstwidth - 1) * bpp);
6995 dBottomLeft = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
6996 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
6998 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
7000 /* I don't think we need to do anything about this flag */
7001 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
7003 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
7006 dTopRight = dTopLeft;
7009 dBottomRight = dBottomLeft;
7011 dstxinc = dstxinc * -1;
7013 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
7016 dTopLeft = dBottomLeft;
7019 dTopRight = dBottomRight;
7021 dstyinc = dstyinc * -1;
7023 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
7025 /* I don't think we need to do anything about this flag */
7026 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
7028 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
7031 dBottomRight = dTopLeft;
7034 dBottomLeft = dTopRight;
7036 dstxinc = dstxinc * -1;
7037 dstyinc = dstyinc * -1;
7039 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
7042 dTopLeft = dBottomLeft;
7043 dBottomLeft = dBottomRight;
7044 dBottomRight = dTopRight;
7049 dstxinc = dstxinc * -1;
7051 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7054 dTopLeft = dTopRight;
7055 dTopRight = dBottomRight;
7056 dBottomRight = dBottomLeft;
7061 dstyinc = dstyinc * -1;
7063 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7065 /* I don't think we need to do anything about this flag */
7066 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7069 flags &= ~(WINEDDBLT_DDFX);
7072 #define COPY_COLORKEY_FX(type) \
7075 type *d = (type *)dbuf, *dx, tmp; \
7076 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7078 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7080 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7082 tmp = s[sx >> 16]; \
7083 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7084 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7088 dx = (type *)(((BYTE *)dx) + dstxinc); \
7090 d = (type *)(((BYTE *)d) + dstyinc); \
7097 COPY_COLORKEY_FX(BYTE);
7100 COPY_COLORKEY_FX(WORD);
7103 COPY_COLORKEY_FX(DWORD);
7108 BYTE *d = dbuf, *dx;
7109 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7111 sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7113 for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7115 DWORD pixel, dpixel = 0;
7116 s = sbuf + 3 * (sx>>16);
7117 pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7118 dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7119 if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7120 && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7122 dx[0] = (pixel ) & 0xff;
7123 dx[1] = (pixel >> 8) & 0xff;
7124 dx[2] = (pixel >> 16) & 0xff;
7133 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7134 (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7135 hr = WINED3DERR_NOTAVAILABLE;
7137 #undef COPY_COLORKEY_FX
7143 if (flags && FIXME_ON(d3d_surface))
7145 FIXME("\tUnsupported flags: %#x.\n", flags);
7149 wined3d_surface_unmap(dst_surface);
7150 if (src_surface && src_surface != dst_surface)
7151 wined3d_surface_unmap(src_surface);
7152 /* Release the converted surface, if any. */
7153 if (src_surface && src_surface != orig_src)
7154 wined3d_surface_decref(src_surface);
7159 /* Do not call while under the GL lock. */
7160 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7161 const RECT *dst_rect, const struct wined3d_color *color)
7163 static const RECT src_rect;
7166 memset(&BltFx, 0, sizeof(BltFx));
7167 BltFx.dwSize = sizeof(BltFx);
7168 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7169 return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7170 WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7173 /* Do not call while under the GL lock. */
7174 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7175 struct wined3d_surface *surface, const RECT *rect, float depth)
7177 FIXME("Depth filling not implemented by cpu_blit.\n");
7178 return WINED3DERR_INVALIDCALL;
7181 const struct blit_shader cpu_blit = {
7187 cpu_blit_color_fill,
7188 cpu_blit_depth_fill,
7191 static HRESULT surface_init(struct wined3d_surface *surface, enum wined3d_surface_type surface_type, UINT alignment,
7192 UINT width, UINT height, UINT level, enum wined3d_multisample_type multisample_type,
7193 UINT multisample_quality, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7194 enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops)
7196 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7197 const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7198 BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7199 unsigned int resource_size;
7202 if (multisample_quality > 0)
7204 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7205 multisample_quality = 0;
7208 /* Quick lockable sanity check.
7209 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7210 * this function is too deep to need to care about things like this.
7211 * Levels need to be checked too, since they all affect what can be done. */
7214 case WINED3D_POOL_SCRATCH:
7217 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7218 "which are mutually exclusive, setting lockable to TRUE.\n");
7223 case WINED3D_POOL_SYSTEM_MEM:
7225 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7228 case WINED3D_POOL_MANAGED:
7229 if (usage & WINED3DUSAGE_DYNAMIC)
7230 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7233 case WINED3D_POOL_DEFAULT:
7234 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7235 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7239 FIXME("Unknown pool %#x.\n", pool);
7243 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7244 FIXME("Trying to create a render target that isn't in the default pool.\n");
7246 /* FIXME: Check that the format is supported by the device. */
7248 resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7250 return WINED3DERR_INVALIDCALL;
7252 surface->surface_type = surface_type;
7254 switch (surface_type)
7256 case WINED3D_SURFACE_TYPE_OPENGL:
7257 surface->surface_ops = &surface_ops;
7260 case WINED3D_SURFACE_TYPE_GDI:
7261 surface->surface_ops = &gdi_surface_ops;
7265 ERR("Requested unknown surface implementation %#x.\n", surface_type);
7266 return WINED3DERR_INVALIDCALL;
7269 hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7270 multisample_type, multisample_quality, usage, pool, width, height, 1,
7271 resource_size, parent, parent_ops, &surface_resource_ops);
7274 WARN("Failed to initialize resource, returning %#x.\n", hr);
7278 /* "Standalone" surface. */
7279 surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7281 surface->texture_level = level;
7282 list_init(&surface->overlays);
7285 surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7286 if (flags & WINED3D_SURFACE_DISCARD)
7287 surface->flags |= SFLAG_DISCARD;
7288 if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7289 surface->flags |= SFLAG_PIN_SYSMEM;
7290 if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7291 surface->flags |= SFLAG_LOCKABLE;
7292 /* I'm not sure if this qualifies as a hack or as an optimization. It
7293 * seems reasonable to assume that lockable render targets will get
7294 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7295 * creation. However, the other reason we want to do this is that several
7296 * ddraw applications access surface memory while the surface isn't
7297 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7298 * future locks prevents these from crashing. */
7299 if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7300 surface->flags |= SFLAG_DYNLOCK;
7302 /* Mark the texture as dirty so that it gets loaded first time around. */
7303 surface_add_dirty_rect(surface, NULL);
7304 list_init(&surface->renderbuffers);
7306 TRACE("surface %p, memory %p, size %u\n",
7307 surface, surface->resource.allocatedMemory, surface->resource.size);
7309 /* Call the private setup routine */
7310 hr = surface->surface_ops->surface_private_setup(surface);
7313 ERR("Private setup failed, returning %#x\n", hr);
7314 surface_cleanup(surface);
7318 /* Similar to lockable rendertargets above, creating the DIB section
7319 * during surface initialization prevents the sysmem pointer from changing
7320 * after a wined3d_surface_getdc() call. */
7321 if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7322 && SUCCEEDED(surface_create_dib_section(surface)))
7324 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7325 surface->resource.heapMemory = NULL;
7326 surface->resource.allocatedMemory = surface->dib.bitmap_data;
7332 HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
7333 enum wined3d_format_id format_id, UINT level, DWORD usage, enum wined3d_pool pool,
7334 enum wined3d_multisample_type multisample_type, DWORD multisample_quality,
7335 enum wined3d_surface_type surface_type, DWORD flags, void *parent,
7336 const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface)
7338 struct wined3d_surface *object;
7341 TRACE("device %p, width %u, height %u, format %s, level %u\n",
7342 device, width, height, debug_d3dformat(format_id), level);
7343 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7344 surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
7345 TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type, flags, parent, parent_ops);
7347 if (surface_type == WINED3D_SURFACE_TYPE_OPENGL && !device->adapter)
7349 ERR("OpenGL surfaces are not available without OpenGL.\n");
7350 return WINED3DERR_NOTAVAILABLE;
7353 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
7356 ERR("Failed to allocate surface memory.\n");
7357 return WINED3DERR_OUTOFVIDEOMEMORY;
7360 hr = surface_init(object, surface_type, device->surface_alignment, width, height, level,
7361 multisample_type, multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops);
7364 WARN("Failed to initialize surface, returning %#x.\n", hr);
7365 HeapFree(GetProcessHeap(), 0, object);
7369 TRACE("Created surface %p.\n", object);