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, 2013 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_perf
);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d
);
37 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
39 static void surface_cleanup(struct wined3d_surface
*surface
)
41 struct wined3d_surface
*overlay
, *cur
;
43 TRACE("surface %p.\n", surface
);
45 if (surface
->texture_name
|| (surface
->flags
& SFLAG_PBO
)
46 || surface
->rb_multisample
|| surface
->rb_resolved
47 || !list_empty(&surface
->renderbuffers
))
49 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
50 const struct wined3d_gl_info
*gl_info
;
51 struct wined3d_context
*context
;
53 context
= context_acquire(surface
->resource
.device
, NULL
);
54 gl_info
= context
->gl_info
;
56 if (surface
->texture_name
)
58 TRACE("Deleting texture %u.\n", surface
->texture_name
);
59 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &surface
->texture_name
);
62 if (surface
->flags
& SFLAG_PBO
)
64 TRACE("Deleting PBO %u.\n", surface
->pbo
);
65 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
68 if (surface
->rb_multisample
)
70 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
71 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
74 if (surface
->rb_resolved
)
76 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
77 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
80 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
82 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
83 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
84 HeapFree(GetProcessHeap(), 0, entry
);
87 context_release(context
);
90 if (surface
->flags
& SFLAG_DIBSECTION
)
92 DeleteDC(surface
->hDC
);
93 DeleteObject(surface
->dib
.DIBsection
);
94 surface
->dib
.bitmap_data
= NULL
;
95 surface
->resource
.allocatedMemory
= NULL
;
98 if (surface
->flags
& SFLAG_USERPTR
)
99 wined3d_surface_set_mem(surface
, NULL
, 0);
100 if (surface
->overlay_dest
)
101 list_remove(&surface
->overlay_entry
);
103 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
105 list_remove(&overlay
->overlay_entry
);
106 overlay
->overlay_dest
= NULL
;
109 resource_cleanup(&surface
->resource
);
112 void surface_update_draw_binding(struct wined3d_surface
*surface
)
114 if (!surface_is_offscreen(surface
) || wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
)
115 surface
->draw_binding
= SFLAG_INDRAWABLE
;
116 else if (surface
->resource
.multisample_type
)
117 surface
->draw_binding
= SFLAG_INRB_MULTISAMPLE
;
119 surface
->draw_binding
= SFLAG_INTEXTURE
;
122 void surface_set_swapchain(struct wined3d_surface
*surface
, struct wined3d_swapchain
*swapchain
)
124 TRACE("surface %p, swapchain %p.\n", surface
, swapchain
);
128 surface
->get_drawable_size
= get_drawable_size_swapchain
;
132 switch (wined3d_settings
.offscreen_rendering_mode
)
135 surface
->get_drawable_size
= get_drawable_size_fbo
;
139 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
143 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
148 surface
->swapchain
= swapchain
;
149 surface_update_draw_binding(surface
);
152 void surface_set_container(struct wined3d_surface
*surface
, struct wined3d_texture
*container
)
154 TRACE("surface %p, container %p.\n", surface
, container
);
156 if (!surface
->swapchain
)
158 switch (wined3d_settings
.offscreen_rendering_mode
)
161 surface
->get_drawable_size
= get_drawable_size_fbo
;
165 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
169 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
174 surface
->container
= container
;
175 surface_update_draw_binding(surface
);
182 enum tex_types tex_type
;
183 GLfloat coords
[4][3];
194 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
196 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
197 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
198 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
199 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
202 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
204 GLfloat (*coords
)[3] = info
->coords
;
210 FIXME("Unsupported texture target %#x\n", target
);
211 /* Fall back to GL_TEXTURE_2D */
213 info
->binding
= GL_TEXTURE_BINDING_2D
;
214 info
->bind_target
= GL_TEXTURE_2D
;
215 info
->tex_type
= tex_2d
;
216 coords
[0][0] = (float)rect
->left
/ w
;
217 coords
[0][1] = (float)rect
->top
/ h
;
220 coords
[1][0] = (float)rect
->right
/ w
;
221 coords
[1][1] = (float)rect
->top
/ h
;
224 coords
[2][0] = (float)rect
->left
/ w
;
225 coords
[2][1] = (float)rect
->bottom
/ h
;
228 coords
[3][0] = (float)rect
->right
/ w
;
229 coords
[3][1] = (float)rect
->bottom
/ h
;
233 case GL_TEXTURE_RECTANGLE_ARB
:
234 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
235 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
236 info
->tex_type
= tex_rect
;
237 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
238 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
239 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
240 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
243 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
244 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
245 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
246 info
->tex_type
= tex_cube
;
247 cube_coords_float(rect
, w
, h
, &f
);
249 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
250 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
251 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
252 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
255 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
256 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
257 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
258 info
->tex_type
= tex_cube
;
259 cube_coords_float(rect
, w
, h
, &f
);
261 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
262 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
263 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
264 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
267 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
268 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
269 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
270 info
->tex_type
= tex_cube
;
271 cube_coords_float(rect
, w
, h
, &f
);
273 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
274 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
275 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
276 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
279 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
280 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
281 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
282 info
->tex_type
= tex_cube
;
283 cube_coords_float(rect
, w
, h
, &f
);
285 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
286 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
287 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
288 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
291 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
292 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
293 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
294 info
->tex_type
= tex_cube
;
295 cube_coords_float(rect
, w
, h
, &f
);
297 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
298 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
299 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
300 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
303 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
304 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
305 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
306 info
->tex_type
= tex_cube
;
307 cube_coords_float(rect
, w
, h
, &f
);
309 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
310 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
311 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
312 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
317 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
320 *rect_out
= *rect_in
;
325 rect_out
->right
= surface
->resource
.width
;
326 rect_out
->bottom
= surface
->resource
.height
;
330 /* Context activation is done by the caller. */
331 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
332 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
334 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
335 struct blt_info info
;
337 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
339 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
340 checkGLcall("glEnable(bind_target)");
342 context_bind_texture(context
, info
.bind_target
, src_surface
->texture_name
);
344 /* Filtering for StretchRect */
345 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
346 wined3d_gl_mag_filter(magLookup
, filter
));
347 checkGLcall("glTexParameteri");
348 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
349 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
350 checkGLcall("glTexParameteri");
351 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
352 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
353 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
354 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
355 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
356 checkGLcall("glTexEnvi");
359 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
360 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
361 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
363 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
364 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
366 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
367 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
369 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
370 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
371 gl_info
->gl_ops
.gl
.p_glEnd();
373 /* Unbind the texture */
374 context_bind_texture(context
, info
.bind_target
, 0);
376 /* We changed the filtering settings on the texture. Inform the
377 * container about this to get the filters reset properly next draw. */
378 if (src_surface
->container
)
380 struct wined3d_texture
*texture
= src_surface
->container
;
381 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3D_TEXF_POINT
;
382 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3D_TEXF_POINT
;
383 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3D_TEXF_NONE
;
384 texture
->texture_rgb
.states
[WINED3DTEXSTA_SRGBTEXTURE
] = FALSE
;
388 /* Works correctly only for <= 4 bpp formats. */
389 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
391 masks
[0] = ((1 << format
->red_size
) - 1) << format
->red_offset
;
392 masks
[1] = ((1 << format
->green_size
) - 1) << format
->green_offset
;
393 masks
[2] = ((1 << format
->blue_size
) - 1) << format
->blue_offset
;
396 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
398 const struct wined3d_format
*format
= surface
->resource
.format
;
404 TRACE("surface %p.\n", surface
);
406 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
408 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
409 return WINED3DERR_INVALIDCALL
;
412 switch (format
->byte_count
)
416 /* Allocate extra space to store the RGB bit masks. */
417 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
421 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
425 /* Allocate extra space for a palette. */
426 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
427 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
432 return E_OUTOFMEMORY
;
434 /* Some applications access the surface in via DWORDs, and do not take
435 * the necessary care at the end of the surface. So we need at least
436 * 4 extra bytes at the end of the surface. Check against the page size,
437 * if the last page used for the surface has at least 4 spare bytes we're
438 * safe, otherwise add an extra line to the DIB section. */
439 GetSystemInfo(&sysInfo
);
440 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
443 TRACE("Adding an extra line to the DIB section.\n");
446 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
447 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
448 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
449 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
450 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
451 * wined3d_surface_get_pitch(surface
);
452 b_info
->bmiHeader
.biPlanes
= 1;
453 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
455 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
456 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
457 b_info
->bmiHeader
.biClrUsed
= 0;
458 b_info
->bmiHeader
.biClrImportant
= 0;
460 /* Get the bit masks */
461 masks
= (DWORD
*)b_info
->bmiColors
;
462 switch (surface
->resource
.format
->id
)
464 case WINED3DFMT_B8G8R8_UNORM
:
465 b_info
->bmiHeader
.biCompression
= BI_RGB
;
468 case WINED3DFMT_B5G5R5X1_UNORM
:
469 case WINED3DFMT_B5G5R5A1_UNORM
:
470 case WINED3DFMT_B4G4R4A4_UNORM
:
471 case WINED3DFMT_B4G4R4X4_UNORM
:
472 case WINED3DFMT_B2G3R3_UNORM
:
473 case WINED3DFMT_B2G3R3A8_UNORM
:
474 case WINED3DFMT_R10G10B10A2_UNORM
:
475 case WINED3DFMT_R8G8B8A8_UNORM
:
476 case WINED3DFMT_R8G8B8X8_UNORM
:
477 case WINED3DFMT_B10G10R10A2_UNORM
:
478 case WINED3DFMT_B5G6R5_UNORM
:
479 case WINED3DFMT_R16G16B16A16_UNORM
:
480 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
481 get_color_masks(format
, masks
);
485 /* Don't know palette */
486 b_info
->bmiHeader
.biCompression
= BI_RGB
;
490 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
491 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
492 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
493 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->dib
.bitmap_data
, 0, 0);
495 if (!surface
->dib
.DIBsection
)
497 ERR("Failed to create DIB section.\n");
498 HeapFree(GetProcessHeap(), 0, b_info
);
499 return HRESULT_FROM_WIN32(GetLastError());
502 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
503 /* Copy the existing surface to the dib section. */
504 if (surface
->resource
.allocatedMemory
)
506 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
,
507 surface
->resource
.height
* wined3d_surface_get_pitch(surface
));
511 /* This is to make maps read the GL texture although memory is allocated. */
512 surface
->flags
&= ~SFLAG_INSYSMEM
;
514 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
516 HeapFree(GetProcessHeap(), 0, b_info
);
518 /* Now allocate a DC. */
519 surface
->hDC
= CreateCompatibleDC(0);
520 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
521 TRACE("Using wined3d palette %p.\n", surface
->palette
);
522 SelectPalette(surface
->hDC
, surface
->palette
? surface
->palette
->hpal
: 0, FALSE
);
524 surface
->flags
|= SFLAG_DIBSECTION
;
529 static BOOL
surface_need_pbo(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
531 if (surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
533 if (!(surface
->flags
& SFLAG_DYNLOCK
))
535 if (surface
->flags
& (SFLAG_CONVERTED
| SFLAG_NONPOW2
| SFLAG_PIN_SYSMEM
))
537 if (!gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
])
543 static void surface_load_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
545 struct wined3d_context
*context
;
548 context
= context_acquire(surface
->resource
.device
, NULL
);
550 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
551 error
= gl_info
->gl_ops
.gl
.p_glGetError();
552 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
553 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
555 TRACE("Binding PBO %u.\n", surface
->pbo
);
557 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
558 checkGLcall("glBindBufferARB");
560 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->resource
.size
+ 4,
561 surface
->resource
.allocatedMemory
, GL_STREAM_DRAW_ARB
));
562 checkGLcall("glBufferDataARB");
564 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
565 checkGLcall("glBindBufferARB");
567 /* We don't need the system memory anymore and we can't even use it for PBOs. */
568 if (!(surface
->flags
& SFLAG_CLIENT
))
569 wined3d_resource_free_sysmem(&surface
->resource
);
570 surface
->resource
.allocatedMemory
= NULL
;
571 surface
->flags
|= SFLAG_PBO
;
572 context_release(context
);
575 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
577 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
579 TRACE("surface %p.\n", surface
);
581 if (!(surface
->flags
& SFLAG_PBO
) && surface_need_pbo(surface
, gl_info
))
582 surface_load_pbo(surface
, gl_info
);
583 else if (!(surface
->resource
.allocatedMemory
|| surface
->flags
& SFLAG_PBO
))
585 /* Whatever surface we have, make sure that there is memory allocated
586 * for the downloaded copy, or a PBO to map. */
587 if (!surface
->resource
.heap_memory
&& !wined3d_resource_allocate_sysmem(&surface
->resource
))
588 ERR("Failed to allocate system memory.\n");
589 surface
->resource
.allocatedMemory
= surface
->resource
.heap_memory
;
591 if (surface
->flags
& SFLAG_INSYSMEM
)
592 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
596 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
598 if (surface
->resource
.map_count
|| (surface
->flags
& SFLAG_DONOTFREE
))
601 wined3d_resource_free_sysmem(&surface
->resource
);
602 surface
->resource
.allocatedMemory
= NULL
;
603 surface_invalidate_location(surface
, SFLAG_INSYSMEM
);
606 /* Context activation is done by the caller. */
607 static void surface_bind(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
609 TRACE("surface %p, context %p, srgb %#x.\n", surface
, context
, srgb
);
611 if (surface
->container
)
613 struct wined3d_texture
*texture
= surface
->container
;
615 TRACE("Passing to container (%p).\n", texture
);
616 texture
->texture_ops
->texture_bind(texture
, context
, srgb
);
620 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
622 if (surface
->texture_level
)
624 ERR("Standalone surface %p is non-zero texture level %u.\n",
625 surface
, surface
->texture_level
);
629 ERR("Trying to bind standalone surface %p as sRGB.\n", surface
);
631 if (!surface
->texture_name
)
633 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &surface
->texture_name
);
634 checkGLcall("glGenTextures");
636 TRACE("Surface %p given name %u.\n", surface
, surface
->texture_name
);
638 context_bind_texture(context
, surface
->texture_target
, surface
->texture_name
);
639 gl_info
->gl_ops
.gl
.p_glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
640 gl_info
->gl_ops
.gl
.p_glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
641 gl_info
->gl_ops
.gl
.p_glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
642 gl_info
->gl_ops
.gl
.p_glTexParameteri(surface
->texture_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
643 gl_info
->gl_ops
.gl
.p_glTexParameteri(surface
->texture_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
644 checkGLcall("glTexParameteri");
648 context_bind_texture(context
, surface
->texture_target
, surface
->texture_name
);
653 /* Context activation is done by the caller. */
654 static void surface_bind_and_dirtify(struct wined3d_surface
*surface
,
655 struct wined3d_context
*context
, BOOL srgb
)
657 DWORD active_sampler
;
659 /* We don't need a specific texture unit, but after binding the texture
660 * the current unit is dirty. Read the unit back instead of switching to
661 * 0, this avoids messing around with the state manager's GL states. The
662 * current texture unit should always be a valid one.
664 * To be more specific, this is tricky because we can implicitly be
665 * called from sampler() in state.c. This means we can't touch anything
666 * other than whatever happens to be the currently active texture, or we
667 * would risk marking already applied sampler states dirty again. */
668 active_sampler
= context
->rev_tex_unit_map
[context
->active_texture
];
670 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
671 context_invalidate_state(context
, STATE_SAMPLER(active_sampler
));
672 surface_bind(surface
, context
, srgb
);
675 static void surface_force_reload(struct wined3d_surface
*surface
)
677 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
680 static void surface_release_client_storage(struct wined3d_surface
*surface
)
682 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
683 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
685 if (surface
->texture_name
)
687 surface_bind_and_dirtify(surface
, context
, FALSE
);
688 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
689 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
691 if (surface
->texture_name_srgb
)
693 surface_bind_and_dirtify(surface
, context
, TRUE
);
694 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
695 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
698 context_release(context
);
700 surface_invalidate_location(surface
, SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
701 surface_force_reload(surface
);
704 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
706 /* TODO: Check against the maximum texture sizes supported by the video card. */
707 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
708 unsigned int pow2Width
, pow2Height
;
710 TRACE("surface %p.\n", surface
);
712 surface
->texture_name
= 0;
713 surface
->texture_target
= GL_TEXTURE_2D
;
715 /* Non-power2 support */
716 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
718 pow2Width
= surface
->resource
.width
;
719 pow2Height
= surface
->resource
.height
;
723 /* Find the nearest pow2 match */
724 pow2Width
= pow2Height
= 1;
725 while (pow2Width
< surface
->resource
.width
)
727 while (pow2Height
< surface
->resource
.height
)
730 surface
->pow2Width
= pow2Width
;
731 surface
->pow2Height
= pow2Height
;
733 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
735 /* TODO: Add support for non power two compressed textures. */
736 if (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
738 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
739 surface
, surface
->resource
.width
, surface
->resource
.height
);
740 return WINED3DERR_NOTAVAILABLE
;
744 if (pow2Width
!= surface
->resource
.width
745 || pow2Height
!= surface
->resource
.height
)
747 surface
->flags
|= SFLAG_NONPOW2
;
750 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
751 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
753 /* One of three options:
754 * 1: Do the same as we do with NPOT and scale the texture, (any
755 * texture ops would require the texture to be scaled which is
757 * 2: Set the texture to the maximum size (bad idea).
758 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
759 * 4: Create the surface, but allow it to be used only for DirectDraw
760 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
761 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
762 * the render target. */
763 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
|| surface
->resource
.pool
== WINED3D_POOL_MANAGED
)
765 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
766 return WINED3DERR_NOTAVAILABLE
;
769 /* We should never use this surface in combination with OpenGL! */
770 TRACE("Creating an oversized surface: %ux%u.\n",
771 surface
->pow2Width
, surface
->pow2Height
);
774 switch (wined3d_settings
.offscreen_rendering_mode
)
777 surface
->get_drawable_size
= get_drawable_size_fbo
;
781 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
785 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
786 return WINED3DERR_INVALIDCALL
;
789 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
790 surface
->flags
|= SFLAG_DISCARDED
;
795 static void surface_realize_palette(struct wined3d_surface
*surface
)
797 struct wined3d_palette
*palette
= surface
->palette
;
799 TRACE("surface %p.\n", surface
);
801 if (!palette
) return;
803 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
804 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
806 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
808 /* Make sure the texture is up to date. This call doesn't do
809 * anything if the texture is already up to date. */
810 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
812 /* We want to force a palette refresh, so mark the drawable as not being up to date */
813 if (!surface_is_offscreen(surface
))
814 surface_invalidate_location(surface
, SFLAG_INDRAWABLE
);
818 if (!(surface
->flags
& SFLAG_INSYSMEM
))
820 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
821 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
823 surface_invalidate_location(surface
, ~SFLAG_INSYSMEM
);
827 if (surface
->flags
& SFLAG_DIBSECTION
)
832 TRACE("Updating the DC's palette.\n");
834 for (i
= 0; i
< 256; ++i
)
836 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
837 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
838 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
839 col
[i
].rgbReserved
= 0;
841 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
844 /* Propagate the changes to the drawable when we have a palette. */
845 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
846 surface_load_location(surface
, surface
->draw_binding
, NULL
);
849 static HRESULT
surface_draw_overlay(struct wined3d_surface
*surface
)
853 /* If there's no destination surface there is nothing to do. */
854 if (!surface
->overlay_dest
)
857 /* Blt calls ModifyLocation on the dest surface, which in turn calls
858 * DrawOverlay to update the overlay. Prevent an endless recursion. */
859 if (surface
->overlay_dest
->flags
& SFLAG_INOVERLAYDRAW
)
862 surface
->overlay_dest
->flags
|= SFLAG_INOVERLAYDRAW
;
863 hr
= wined3d_surface_blt(surface
->overlay_dest
, &surface
->overlay_destrect
, surface
,
864 &surface
->overlay_srcrect
, WINEDDBLT_WAIT
, NULL
, WINED3D_TEXF_LINEAR
);
865 surface
->overlay_dest
->flags
&= ~SFLAG_INOVERLAYDRAW
;
870 static void surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
872 struct wined3d_device
*device
= surface
->resource
.device
;
873 const RECT
*pass_rect
= rect
;
875 TRACE("surface %p, rect %s, flags %#x.\n",
876 surface
, wine_dbgstr_rect(rect
), flags
);
878 if (flags
& WINED3D_MAP_DISCARD
)
880 TRACE("WINED3D_MAP_DISCARD flag passed, marking SYSMEM as up to date.\n");
881 surface_prepare_system_memory(surface
);
882 surface_validate_location(surface
, SFLAG_INSYSMEM
);
883 surface_invalidate_location(surface
, ~SFLAG_INSYSMEM
);
887 if (surface
->resource
.usage
& WINED3DUSAGE_DYNAMIC
)
888 WARN_(d3d_perf
)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
890 /* surface_load_location() does not check if the rectangle specifies
891 * the full surface. Most callers don't need that, so do it here. */
892 if (rect
&& !rect
->top
&& !rect
->left
893 && rect
->right
== surface
->resource
.width
894 && rect
->bottom
== surface
->resource
.height
)
896 surface_load_location(surface
, SFLAG_INSYSMEM
, pass_rect
);
899 if (surface
->flags
& SFLAG_PBO
)
901 const struct wined3d_gl_info
*gl_info
;
902 struct wined3d_context
*context
;
904 context
= context_acquire(device
, NULL
);
905 gl_info
= context
->gl_info
;
907 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
908 checkGLcall("glBindBufferARB");
910 /* This shouldn't happen but could occur if some other function
911 * didn't handle the PBO properly. */
912 if (surface
->resource
.allocatedMemory
)
913 ERR("The surface already has PBO memory allocated.\n");
915 surface
->resource
.allocatedMemory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
916 checkGLcall("glMapBufferARB");
918 /* Make sure the PBO isn't set anymore in order not to break non-PBO
920 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
921 checkGLcall("glBindBufferARB");
923 context_release(context
);
926 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
929 surface_add_dirty_rect(surface
, NULL
);
932 struct wined3d_box b
;
936 b
.right
= rect
->right
;
937 b
.bottom
= rect
->bottom
;
940 surface_add_dirty_rect(surface
, &b
);
945 static void surface_unmap(struct wined3d_surface
*surface
)
947 struct wined3d_device
*device
= surface
->resource
.device
;
950 TRACE("surface %p.\n", surface
);
952 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
954 if (surface
->flags
& SFLAG_PBO
)
956 const struct wined3d_gl_info
*gl_info
;
957 struct wined3d_context
*context
;
959 TRACE("Freeing PBO memory.\n");
961 context
= context_acquire(device
, NULL
);
962 gl_info
= context
->gl_info
;
964 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
965 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
966 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
967 checkGLcall("glUnmapBufferARB");
968 context_release(context
);
970 surface
->resource
.allocatedMemory
= NULL
;
973 TRACE("dirtyfied %u.\n", surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
) ? 0 : 1);
975 if (surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
))
977 TRACE("Not dirtified, nothing to do.\n");
981 if (surface
->swapchain
&& surface
->swapchain
->front_buffer
== surface
)
983 if (!surface
->dirtyRect
.left
&& !surface
->dirtyRect
.top
984 && surface
->dirtyRect
.right
== surface
->resource
.width
985 && surface
->dirtyRect
.bottom
== surface
->resource
.height
)
991 /* TODO: Proper partial rectangle tracking. */
993 surface
->flags
|= SFLAG_INSYSMEM
;
996 surface_load_location(surface
, surface
->draw_binding
, fullsurface
? NULL
: &surface
->dirtyRect
);
998 /* Partial rectangle tracking is not commonly implemented, it is only
999 * done for render targets. INSYSMEM was set before to tell
1000 * surface_load_location() where to read the rectangle from.
1001 * Indrawable is set because all modifications from the partial
1002 * sysmem copy are written back to the drawable, thus the surface is
1003 * merged again in the drawable. The sysmem copy is not fully up to
1004 * date because only a subrectangle was read in Map(). */
1007 surface_validate_location(surface
, surface
->draw_binding
);
1008 surface_invalidate_location(surface
, ~surface
->draw_binding
);
1009 surface_evict_sysmem(surface
);
1012 surface
->dirtyRect
.left
= surface
->resource
.width
;
1013 surface
->dirtyRect
.top
= surface
->resource
.height
;
1014 surface
->dirtyRect
.right
= 0;
1015 surface
->dirtyRect
.bottom
= 0;
1017 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
1019 FIXME("Depth / stencil buffer locking is not implemented.\n");
1023 /* Overlays have to be redrawn manually after changes with the GL implementation */
1024 if (surface
->overlay_dest
)
1025 surface_draw_overlay(surface
);
1028 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
1030 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
1032 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
1037 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
1038 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1039 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1041 const struct wined3d_gl_info
*gl_info
;
1042 struct wined3d_context
*context
;
1043 DWORD src_mask
, dst_mask
;
1046 TRACE("device %p\n", device
);
1047 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1048 src_surface
, debug_surflocation(src_location
), wine_dbgstr_rect(src_rect
));
1049 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1050 dst_surface
, debug_surflocation(dst_location
), wine_dbgstr_rect(dst_rect
));
1052 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1053 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1055 if (src_mask
!= dst_mask
)
1057 ERR("Incompatible formats %s and %s.\n",
1058 debug_d3dformat(src_surface
->resource
.format
->id
),
1059 debug_d3dformat(dst_surface
->resource
.format
->id
));
1065 ERR("Not a depth / stencil format: %s.\n",
1066 debug_d3dformat(src_surface
->resource
.format
->id
));
1071 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
1072 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
1073 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
1074 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
1076 /* Make sure the locations are up-to-date. Loading the destination
1077 * surface isn't required if the entire surface is overwritten. */
1078 surface_load_location(src_surface
, src_location
, NULL
);
1079 if (!surface_is_full_rect(dst_surface
, dst_rect
))
1080 surface_load_location(dst_surface
, dst_location
, NULL
);
1082 context
= context_acquire(device
, NULL
);
1083 if (!context
->valid
)
1085 context_release(context
);
1086 WARN("Invalid context, skipping blit.\n");
1090 gl_info
= context
->gl_info
;
1092 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
1093 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1095 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
1096 context_set_draw_buffer(context
, GL_NONE
);
1097 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1098 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
1100 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
1102 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
1103 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
1105 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
1107 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
1109 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
1110 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
1112 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
1113 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
1116 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
1117 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
1119 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
1120 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
1121 checkGLcall("glBlitFramebuffer()");
1123 if (wined3d_settings
.strict_draw_ordering
)
1124 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
1126 context_release(context
);
1129 /* Blit between surface locations. Onscreen on different swapchains is not supported.
1130 * Depth / stencil is not supported. */
1131 static void surface_blt_fbo(const struct wined3d_device
*device
, enum wined3d_texture_filter_type filter
,
1132 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
1133 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
1135 const struct wined3d_gl_info
*gl_info
;
1136 struct wined3d_context
*context
;
1137 RECT src_rect
, dst_rect
;
1141 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
1142 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1143 src_surface
, debug_surflocation(src_location
), wine_dbgstr_rect(src_rect_in
));
1144 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1145 dst_surface
, debug_surflocation(dst_location
), wine_dbgstr_rect(dst_rect_in
));
1147 src_rect
= *src_rect_in
;
1148 dst_rect
= *dst_rect_in
;
1152 case WINED3D_TEXF_LINEAR
:
1153 gl_filter
= GL_LINEAR
;
1157 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
1158 case WINED3D_TEXF_NONE
:
1159 case WINED3D_TEXF_POINT
:
1160 gl_filter
= GL_NEAREST
;
1164 /* Resolve the source surface first if needed. */
1165 if (src_location
== SFLAG_INRB_MULTISAMPLE
1166 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
1167 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
1168 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
1169 src_location
= SFLAG_INRB_RESOLVED
;
1171 /* Make sure the locations are up-to-date. Loading the destination
1172 * surface isn't required if the entire surface is overwritten. (And is
1173 * in fact harmful if we're being called by surface_load_location() with
1174 * the purpose of loading the destination surface.) */
1175 surface_load_location(src_surface
, src_location
, NULL
);
1176 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
1177 surface_load_location(dst_surface
, dst_location
, NULL
);
1179 if (src_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, src_surface
);
1180 else if (dst_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, dst_surface
);
1181 else context
= context_acquire(device
, NULL
);
1183 if (!context
->valid
)
1185 context_release(context
);
1186 WARN("Invalid context, skipping blit.\n");
1190 gl_info
= context
->gl_info
;
1192 if (src_location
== SFLAG_INDRAWABLE
)
1194 TRACE("Source surface %p is onscreen.\n", src_surface
);
1195 buffer
= surface_get_gl_buffer(src_surface
);
1196 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
1200 TRACE("Source surface %p is offscreen.\n", src_surface
);
1201 buffer
= GL_COLOR_ATTACHMENT0
;
1204 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
1205 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
1206 checkGLcall("glReadBuffer()");
1207 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1209 if (dst_location
== SFLAG_INDRAWABLE
)
1211 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
1212 buffer
= surface_get_gl_buffer(dst_surface
);
1213 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
1217 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
1218 buffer
= GL_COLOR_ATTACHMENT0
;
1221 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
1222 context_set_draw_buffer(context
, buffer
);
1223 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1224 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
1226 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
1227 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
1228 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
1229 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
1230 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
1232 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
1233 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
1235 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
1236 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
1237 checkGLcall("glBlitFramebuffer()");
1239 if (wined3d_settings
.strict_draw_ordering
1240 || (dst_location
== SFLAG_INDRAWABLE
1241 && dst_surface
->swapchain
->front_buffer
== dst_surface
))
1242 gl_info
->gl_ops
.gl
.p_glFlush();
1244 context_release(context
);
1247 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
1248 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
1249 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
1251 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
1254 /* Source and/or destination need to be on the GL side */
1255 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
1260 case WINED3D_BLIT_OP_COLOR_BLIT
:
1261 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
1263 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1267 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1268 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1270 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1278 if (!(src_format
->id
== dst_format
->id
1279 || (is_identity_fixup(src_format
->color_fixup
)
1280 && is_identity_fixup(dst_format
->color_fixup
))))
1286 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1287 DWORD color
, struct wined3d_color
*float_color
)
1289 const struct wined3d_format
*format
= surface
->resource
.format
;
1290 const struct wined3d_device
*device
= surface
->resource
.device
;
1294 case WINED3DFMT_P8_UINT
:
1295 if (surface
->palette
)
1297 float_color
->r
= surface
->palette
->palents
[color
].peRed
/ 255.0f
;
1298 float_color
->g
= surface
->palette
->palents
[color
].peGreen
/ 255.0f
;
1299 float_color
->b
= surface
->palette
->palents
[color
].peBlue
/ 255.0f
;
1303 float_color
->r
= 0.0f
;
1304 float_color
->g
= 0.0f
;
1305 float_color
->b
= 0.0f
;
1307 float_color
->a
= swapchain_is_p8(device
->swapchains
[0]) ? color
/ 255.0f
: 1.0f
;
1310 case WINED3DFMT_B5G6R5_UNORM
:
1311 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1312 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1313 float_color
->b
= (color
& 0x1f) / 31.0f
;
1314 float_color
->a
= 1.0f
;
1317 case WINED3DFMT_B8G8R8_UNORM
:
1318 case WINED3DFMT_B8G8R8X8_UNORM
:
1319 float_color
->r
= D3DCOLOR_R(color
);
1320 float_color
->g
= D3DCOLOR_G(color
);
1321 float_color
->b
= D3DCOLOR_B(color
);
1322 float_color
->a
= 1.0f
;
1325 case WINED3DFMT_B8G8R8A8_UNORM
:
1326 float_color
->r
= D3DCOLOR_R(color
);
1327 float_color
->g
= D3DCOLOR_G(color
);
1328 float_color
->b
= D3DCOLOR_B(color
);
1329 float_color
->a
= D3DCOLOR_A(color
);
1333 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1340 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1342 const struct wined3d_format
*format
= surface
->resource
.format
;
1346 case WINED3DFMT_S1_UINT_D15_UNORM
:
1347 *float_depth
= depth
/ (float)0x00007fff;
1350 case WINED3DFMT_D16_UNORM
:
1351 *float_depth
= depth
/ (float)0x0000ffff;
1354 case WINED3DFMT_D24_UNORM_S8_UINT
:
1355 case WINED3DFMT_X8D24_UNORM
:
1356 *float_depth
= depth
/ (float)0x00ffffff;
1359 case WINED3DFMT_D32_UNORM
:
1360 *float_depth
= depth
/ (float)0xffffffff;
1364 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1371 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1373 const struct wined3d_resource
*resource
= &surface
->resource
;
1374 struct wined3d_device
*device
= resource
->device
;
1375 const struct blit_shader
*blitter
;
1377 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1378 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1381 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1382 return WINED3DERR_INVALIDCALL
;
1385 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1388 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1389 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1391 struct wined3d_device
*device
= src_surface
->resource
.device
;
1393 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1394 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1395 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1396 return WINED3DERR_INVALIDCALL
;
1398 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
1400 surface_modify_ds_location(dst_surface
, dst_location
,
1401 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1406 HRESULT CDECL
wined3d_surface_get_render_target_data(struct wined3d_surface
*surface
,
1407 struct wined3d_surface
*render_target
)
1409 TRACE("surface %p, render_target %p.\n", surface
, render_target
);
1411 /* TODO: Check surface sizes, pools, etc. */
1413 if (render_target
->resource
.multisample_type
)
1414 return WINED3DERR_INVALIDCALL
;
1416 return wined3d_surface_blt(surface
, NULL
, render_target
, NULL
, 0, NULL
, WINED3D_TEXF_POINT
);
1419 /* Context activation is done by the caller. */
1420 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1422 if (surface
->flags
& SFLAG_DIBSECTION
)
1424 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1428 if (!surface
->resource
.heap_memory
)
1429 wined3d_resource_allocate_sysmem(&surface
->resource
);
1430 else if (!(surface
->flags
& SFLAG_CLIENT
))
1431 ERR("Surface %p has heap_memory %p and flags %#x.\n",
1432 surface
, surface
->resource
.heap_memory
, surface
->flags
);
1434 surface
->resource
.allocatedMemory
= surface
->resource
.heap_memory
;
1437 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
1438 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1439 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0,
1440 surface
->resource
.size
, surface
->resource
.allocatedMemory
));
1441 checkGLcall("glGetBufferSubDataARB");
1442 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1443 checkGLcall("glDeleteBuffersARB");
1446 surface
->flags
&= ~SFLAG_PBO
;
1449 static BOOL
surface_init_sysmem(struct wined3d_surface
*surface
)
1451 if (!surface
->resource
.allocatedMemory
)
1453 if (!surface
->resource
.heap_memory
)
1455 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
1457 ERR("Failed to allocate system memory.\n");
1461 else if (!(surface
->flags
& SFLAG_CLIENT
))
1463 ERR("Surface %p has heap_memory %p and flags %#x.\n",
1464 surface
, surface
->resource
.heap_memory
, surface
->flags
);
1467 surface
->resource
.allocatedMemory
= surface
->resource
.heap_memory
;
1471 memset(surface
->resource
.allocatedMemory
, 0, surface
->resource
.size
);
1474 surface_validate_location(surface
, SFLAG_INSYSMEM
);
1475 surface_invalidate_location(surface
, ~SFLAG_INSYSMEM
);
1480 static void surface_unload(struct wined3d_resource
*resource
)
1482 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1483 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1484 struct wined3d_device
*device
= resource
->device
;
1485 const struct wined3d_gl_info
*gl_info
;
1486 struct wined3d_context
*context
;
1488 TRACE("surface %p.\n", surface
);
1490 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
1492 /* Default pool resources are supposed to be destroyed before Reset is called.
1493 * Implicit resources stay however. So this means we have an implicit render target
1494 * or depth stencil. The content may be destroyed, but we still have to tear down
1495 * opengl resources, so we cannot leave early.
1497 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1498 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1499 * or the depth stencil into an FBO the texture or render buffer will be removed
1500 * and all flags get lost
1502 if (!(surface
->flags
& SFLAG_PBO
))
1503 surface_init_sysmem(surface
);
1504 /* We also get here when the ddraw swapchain is destroyed, for example
1505 * for a mode switch. In this case this surface won't necessarily be
1506 * an implicit surface. We have to mark it lost so that the
1507 * application can restore it after the mode switch. */
1508 surface
->flags
|= SFLAG_LOST
;
1512 /* Load the surface into system memory */
1513 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
1514 surface_invalidate_location(surface
, surface
->draw_binding
);
1516 surface_invalidate_location(surface
, SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
1517 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1519 context
= context_acquire(device
, NULL
);
1520 gl_info
= context
->gl_info
;
1522 /* Destroy PBOs, but load them into real sysmem before */
1523 if (surface
->flags
& SFLAG_PBO
)
1524 surface_remove_pbo(surface
, gl_info
);
1526 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1527 * all application-created targets the application has to release the surface
1528 * before calling _Reset
1530 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1532 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1533 list_remove(&entry
->entry
);
1534 HeapFree(GetProcessHeap(), 0, entry
);
1536 list_init(&surface
->renderbuffers
);
1537 surface
->current_renderbuffer
= NULL
;
1539 /* If we're in a texture, the texture name belongs to the texture.
1540 * Otherwise, destroy it. */
1541 if (!surface
->container
)
1543 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &surface
->texture_name
);
1544 surface
->texture_name
= 0;
1545 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &surface
->texture_name_srgb
);
1546 surface
->texture_name_srgb
= 0;
1548 if (surface
->rb_multisample
)
1550 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1551 surface
->rb_multisample
= 0;
1553 if (surface
->rb_resolved
)
1555 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1556 surface
->rb_resolved
= 0;
1559 context_release(context
);
1561 resource_unload(resource
);
1564 static const struct wined3d_resource_ops surface_resource_ops
=
1569 static const struct wined3d_surface_ops surface_ops
=
1571 surface_private_setup
,
1572 surface_realize_palette
,
1577 /*****************************************************************************
1578 * Initializes the GDI surface, aka creates the DIB section we render to
1579 * The DIB section creation is done by calling GetDC, which will create the
1580 * section and releasing the dc to allow the app to use it. The dib section
1581 * will stay until the surface is released
1583 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1584 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1585 * avoid confusion in the shared surface code.
1588 * WINED3D_OK on success
1589 * The return values of called methods on failure
1591 *****************************************************************************/
1592 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1596 TRACE("surface %p.\n", surface
);
1598 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1600 ERR("Overlays not yet supported by GDI surfaces.\n");
1601 return WINED3DERR_INVALIDCALL
;
1604 /* Sysmem textures have memory already allocated - release it,
1605 * this avoids an unnecessary memcpy. */
1606 hr
= surface_create_dib_section(surface
);
1609 wined3d_resource_free_sysmem(&surface
->resource
);
1610 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1613 /* We don't mind the nonpow2 stuff in GDI. */
1614 surface
->pow2Width
= surface
->resource
.width
;
1615 surface
->pow2Height
= surface
->resource
.height
;
1620 static void gdi_surface_realize_palette(struct wined3d_surface
*surface
)
1622 struct wined3d_palette
*palette
= surface
->palette
;
1624 TRACE("surface %p.\n", surface
);
1626 if (!palette
) return;
1628 if (surface
->flags
& SFLAG_DIBSECTION
)
1633 TRACE("Updating the DC's palette.\n");
1635 for (i
= 0; i
< 256; ++i
)
1637 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
1638 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
1639 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
1640 col
[i
].rgbReserved
= 0;
1642 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
1645 /* Update the image because of the palette change. Some games like e.g.
1646 * Red Alert call SetEntries a lot to implement fading. */
1647 /* Tell the swapchain to update the screen. */
1648 if (surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
)
1649 x11_copy_to_screen(surface
->swapchain
, NULL
);
1652 static void gdi_surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
1654 TRACE("surface %p, rect %s, flags %#x.\n",
1655 surface
, wine_dbgstr_rect(rect
), flags
);
1657 if (!(surface
->flags
& SFLAG_DIBSECTION
))
1661 /* This happens on gdi surfaces if the application set a user pointer
1662 * and resets it. Recreate the DIB section. */
1663 if (FAILED(hr
= surface_create_dib_section(surface
)))
1665 ERR("Failed to create dib section, hr %#x.\n", hr
);
1668 wined3d_resource_free_sysmem(&surface
->resource
);
1669 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1673 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1675 TRACE("surface %p.\n", surface
);
1677 /* Tell the swapchain to update the screen. */
1678 if (surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
)
1679 x11_copy_to_screen(surface
->swapchain
, &surface
->lockedRect
);
1681 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
1684 static const struct wined3d_surface_ops gdi_surface_ops
=
1686 gdi_surface_private_setup
,
1687 gdi_surface_realize_palette
,
1692 void surface_set_texture_name(struct wined3d_surface
*surface
, GLuint name
, BOOL srgb
)
1694 TRACE("surface %p, name %u, srgb %#x.\n", surface
, name
, srgb
);
1697 surface
->texture_name_srgb
= name
;
1699 surface
->texture_name
= name
;
1701 surface_force_reload(surface
);
1704 void surface_set_texture_target(struct wined3d_surface
*surface
, GLenum target
, GLint level
)
1706 TRACE("surface %p, target %#x.\n", surface
, target
);
1708 if (surface
->texture_target
!= target
)
1710 if (target
== GL_TEXTURE_RECTANGLE_ARB
)
1712 surface
->flags
&= ~SFLAG_NORMCOORD
;
1714 else if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
1716 surface
->flags
|= SFLAG_NORMCOORD
;
1719 surface
->texture_target
= target
;
1720 surface
->texture_level
= level
;
1721 surface_force_reload(surface
);
1724 /* This call just downloads data, the caller is responsible for binding the
1725 * correct texture. */
1726 /* Context activation is done by the caller. */
1727 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1729 const struct wined3d_format
*format
= surface
->resource
.format
;
1731 /* Only support read back of converted P8 surfaces. */
1732 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1734 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1738 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1740 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1741 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
,
1742 surface
->resource
.allocatedMemory
);
1744 if (surface
->flags
& SFLAG_PBO
)
1746 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
1747 checkGLcall("glBindBufferARB");
1748 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
1749 checkGLcall("glGetCompressedTexImageARB");
1750 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1751 checkGLcall("glBindBufferARB");
1755 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
1756 surface
->texture_level
, surface
->resource
.allocatedMemory
));
1757 checkGLcall("glGetCompressedTexImageARB");
1763 GLenum gl_format
= format
->glFormat
;
1764 GLenum gl_type
= format
->glType
;
1768 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
1769 if (format
->id
== WINED3DFMT_P8_UINT
&& swapchain_is_p8(surface
->resource
.device
->swapchains
[0]))
1771 gl_format
= GL_ALPHA
;
1772 gl_type
= GL_UNSIGNED_BYTE
;
1775 if (surface
->flags
& SFLAG_NONPOW2
)
1777 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
1778 src_pitch
= format
->byte_count
* surface
->pow2Width
;
1779 dst_pitch
= wined3d_surface_get_pitch(surface
);
1780 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
1781 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
1785 mem
= surface
->resource
.allocatedMemory
;
1788 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1789 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1791 if (surface
->flags
& SFLAG_PBO
)
1793 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
1794 checkGLcall("glBindBufferARB");
1796 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1797 gl_format
, gl_type
, NULL
);
1798 checkGLcall("glGetTexImage");
1800 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1801 checkGLcall("glBindBufferARB");
1805 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1806 gl_format
, gl_type
, mem
);
1807 checkGLcall("glGetTexImage");
1810 if (surface
->flags
& SFLAG_NONPOW2
)
1812 const BYTE
*src_data
;
1816 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1817 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1818 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1820 * We're doing this...
1822 * instead of boxing the texture :
1823 * |<-texture width ->| -->pow2width| /\
1824 * |111111111111111111| | |
1825 * |222 Texture 222222| boxed empty | texture height
1826 * |3333 Data 33333333| | |
1827 * |444444444444444444| | \/
1828 * ----------------------------------- |
1829 * | boxed empty | boxed empty | pow2height
1831 * -----------------------------------
1834 * we're repacking the data to the expected texture width
1836 * |<-texture width ->| -->pow2width| /\
1837 * |111111111111111111222222222222222| |
1838 * |222333333333333333333444444444444| texture height
1842 * | empty | pow2height
1844 * -----------------------------------
1848 * |<-texture width ->| /\
1849 * |111111111111111111|
1850 * |222222222222222222|texture height
1851 * |333333333333333333|
1852 * |444444444444444444| \/
1853 * --------------------
1855 * this also means that any references to allocatedMemory should work with the data as if were a
1856 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
1858 * internally the texture is still stored in a boxed format so any references to textureName will
1859 * get a boxed texture with width pow2width and not a texture of width resource.width.
1861 * Performance should not be an issue, because applications normally do not lock the surfaces when
1862 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
1863 * and doesn't have to be re-read. */
1865 dst_data
= surface
->resource
.allocatedMemory
;
1866 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
1867 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1869 memcpy(dst_data
, src_data
, dst_pitch
);
1870 src_data
+= src_pitch
;
1871 dst_data
+= dst_pitch
;
1874 HeapFree(GetProcessHeap(), 0, mem
);
1878 /* Surface has now been downloaded */
1879 surface
->flags
|= SFLAG_INSYSMEM
;
1882 /* This call just uploads data, the caller is responsible for binding the
1883 * correct texture. */
1884 /* Context activation is done by the caller. */
1885 static void surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1886 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1887 BOOL srgb
, const struct wined3d_bo_address
*data
)
1889 UINT update_w
= src_rect
->right
- src_rect
->left
;
1890 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1892 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1893 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1894 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1896 if (surface
->resource
.map_count
)
1898 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
1899 surface
->flags
|= SFLAG_PIN_SYSMEM
;
1902 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1904 update_h
*= format
->height_scale
.numerator
;
1905 update_h
/= format
->height_scale
.denominator
;
1908 if (data
->buffer_object
)
1910 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
1911 checkGLcall("glBindBufferARB");
1914 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1916 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1917 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1918 const BYTE
*addr
= data
->addr
;
1921 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1922 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1925 internal
= format
->glGammaInternal
;
1926 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
1927 internal
= format
->rtInternal
;
1929 internal
= format
->glInternal
;
1931 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
1932 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1933 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1935 if (row_length
== src_pitch
)
1937 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1938 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1944 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
1945 * can't use the unpack row length like below. */
1946 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1948 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1949 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1950 y
+= format
->block_height
;
1954 checkGLcall("glCompressedTexSubImage2DARB");
1958 const BYTE
*addr
= data
->addr
;
1960 addr
+= src_rect
->top
* src_pitch
;
1961 addr
+= src_rect
->left
* format
->byte_count
;
1963 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1964 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1965 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1967 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1968 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1969 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1970 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1971 checkGLcall("glTexSubImage2D");
1974 if (data
->buffer_object
)
1976 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1977 checkGLcall("glBindBufferARB");
1980 if (wined3d_settings
.strict_draw_ordering
)
1981 gl_info
->gl_ops
.gl
.p_glFlush();
1983 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1985 struct wined3d_device
*device
= surface
->resource
.device
;
1988 for (i
= 0; i
< device
->context_count
; ++i
)
1990 context_surface_update(device
->contexts
[i
], surface
);
1995 static HRESULT
d3dfmt_get_conv(const struct wined3d_surface
*surface
, BOOL need_alpha_ck
, BOOL use_texturing
,
1996 struct wined3d_format
*format
, enum wined3d_conversion_type
*conversion_type
)
1998 BOOL colorkey_active
= need_alpha_ck
&& (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
1999 const struct wined3d_device
*device
= surface
->resource
.device
;
2000 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
2001 BOOL blit_supported
= FALSE
;
2003 /* Copy the default values from the surface. Below we might perform fixups */
2004 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2005 *format
= *surface
->resource
.format
;
2006 *conversion_type
= WINED3D_CT_NONE
;
2008 /* Ok, now look if we have to do any conversion */
2009 switch (surface
->resource
.format
->id
)
2011 case WINED3DFMT_P8_UINT
:
2012 /* Below the call to blit_supported is disabled for Wine 1.2
2013 * because the function isn't operating correctly yet. At the
2014 * moment 8-bit blits are handled in software and if certain GL
2015 * extensions are around, surface conversion is performed at
2016 * upload time. The blit_supported call recognizes it as a
2017 * destination fixup. This type of upload 'fixup' and 8-bit to
2018 * 8-bit blits need to be handled by the blit_shader.
2019 * TODO: get rid of this #if 0. */
2021 blit_supported
= device
->blitter
->blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
2022 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
2023 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
);
2025 blit_supported
= gl_info
->supported
[ARB_FRAGMENT_PROGRAM
];
2027 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2028 * texturing. Further also use conversion in case of color keying.
2029 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2030 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2031 * conflicts with this.
2033 if (!((blit_supported
&& device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
2034 || colorkey_active
|| !use_texturing
)
2036 format
->glFormat
= GL_RGBA
;
2037 format
->glInternal
= GL_RGBA
;
2038 format
->glType
= GL_UNSIGNED_BYTE
;
2039 format
->conv_byte_count
= 4;
2040 if (colorkey_active
)
2041 *conversion_type
= WINED3D_CT_PALETTED_CK
;
2043 *conversion_type
= WINED3D_CT_PALETTED
;
2047 case WINED3DFMT_B2G3R3_UNORM
:
2048 /* **********************
2049 GL_UNSIGNED_BYTE_3_3_2
2050 ********************** */
2051 if (colorkey_active
) {
2052 /* This texture format will never be used.. So do not care about color keying
2053 up until the point in time it will be needed :-) */
2054 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2058 case WINED3DFMT_B5G6R5_UNORM
:
2059 if (colorkey_active
)
2061 *conversion_type
= WINED3D_CT_CK_565
;
2062 format
->glFormat
= GL_RGBA
;
2063 format
->glInternal
= GL_RGB5_A1
;
2064 format
->glType
= GL_UNSIGNED_SHORT_5_5_5_1
;
2065 format
->conv_byte_count
= 2;
2069 case WINED3DFMT_B5G5R5X1_UNORM
:
2070 if (colorkey_active
)
2072 *conversion_type
= WINED3D_CT_CK_5551
;
2073 format
->glFormat
= GL_BGRA
;
2074 format
->glInternal
= GL_RGB5_A1
;
2075 format
->glType
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
2076 format
->conv_byte_count
= 2;
2080 case WINED3DFMT_B8G8R8_UNORM
:
2081 if (colorkey_active
)
2083 *conversion_type
= WINED3D_CT_CK_RGB24
;
2084 format
->glFormat
= GL_RGBA
;
2085 format
->glInternal
= GL_RGBA8
;
2086 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
2087 format
->conv_byte_count
= 4;
2091 case WINED3DFMT_B8G8R8X8_UNORM
:
2092 if (colorkey_active
)
2094 *conversion_type
= WINED3D_CT_RGB32_888
;
2095 format
->glFormat
= GL_RGBA
;
2096 format
->glInternal
= GL_RGBA8
;
2097 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
2098 format
->conv_byte_count
= 4;
2102 case WINED3DFMT_B8G8R8A8_UNORM
:
2103 if (colorkey_active
)
2105 *conversion_type
= WINED3D_CT_CK_ARGB32
;
2106 format
->conv_byte_count
= 4;
2114 if (*conversion_type
!= WINED3D_CT_NONE
)
2116 format
->rtInternal
= format
->glInternal
;
2117 format
->glGammaInternal
= format
->glInternal
;
2123 static BOOL
surface_check_block_align(struct wined3d_surface
*surface
, const RECT
*rect
)
2125 UINT width_mask
, height_mask
;
2127 if (!rect
->left
&& !rect
->top
2128 && rect
->right
== surface
->resource
.width
2129 && rect
->bottom
== surface
->resource
.height
)
2132 /* This assumes power of two block sizes, but NPOT block sizes would be
2134 width_mask
= surface
->resource
.format
->block_width
- 1;
2135 height_mask
= surface
->resource
.format
->block_height
- 1;
2137 if (!(rect
->left
& width_mask
) && !(rect
->top
& height_mask
)
2138 && !(rect
->right
& width_mask
) && !(rect
->bottom
& height_mask
))
2144 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
2145 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
2147 const struct wined3d_format
*src_format
;
2148 const struct wined3d_format
*dst_format
;
2149 const struct wined3d_gl_info
*gl_info
;
2150 enum wined3d_conversion_type convert
;
2151 struct wined3d_context
*context
;
2152 struct wined3d_bo_address data
;
2153 struct wined3d_format format
;
2154 UINT update_w
, update_h
;
2160 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2161 dst_surface
, wine_dbgstr_point(dst_point
),
2162 src_surface
, wine_dbgstr_rect(src_rect
));
2164 src_format
= src_surface
->resource
.format
;
2165 dst_format
= dst_surface
->resource
.format
;
2167 if (src_format
->id
!= dst_format
->id
)
2169 WARN("Source and destination surfaces should have the same format.\n");
2170 return WINED3DERR_INVALIDCALL
;
2179 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
2181 WARN("Invalid destination point.\n");
2182 return WINED3DERR_INVALIDCALL
;
2189 r
.right
= src_surface
->resource
.width
;
2190 r
.bottom
= src_surface
->resource
.height
;
2193 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
2194 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
2196 WARN("Invalid source rectangle.\n");
2197 return WINED3DERR_INVALIDCALL
;
2200 dst_w
= dst_surface
->resource
.width
;
2201 dst_h
= dst_surface
->resource
.height
;
2203 update_w
= src_rect
->right
- src_rect
->left
;
2204 update_h
= src_rect
->bottom
- src_rect
->top
;
2206 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
2207 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
2209 WARN("Destination out of bounds.\n");
2210 return WINED3DERR_INVALIDCALL
;
2213 if ((src_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(src_surface
, src_rect
))
2215 WARN("Source rectangle not block-aligned.\n");
2216 return WINED3DERR_INVALIDCALL
;
2219 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
2220 if ((dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(dst_surface
, &dst_rect
))
2222 WARN("Destination rectangle not block-aligned.\n");
2223 return WINED3DERR_INVALIDCALL
;
2226 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2227 d3dfmt_get_conv(dst_surface
, FALSE
, TRUE
, &format
, &convert
);
2228 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
2229 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
2231 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
2232 gl_info
= context
->gl_info
;
2234 /* Only load the surface for partial updates. For newly allocated texture
2235 * the texture wouldn't be the current location, and we'd upload zeroes
2236 * just to overwrite them again. */
2237 if (update_w
== dst_w
&& update_h
== dst_h
)
2238 surface_prepare_texture(dst_surface
, context
, FALSE
);
2240 surface_load_location(dst_surface
, SFLAG_INTEXTURE
, NULL
);
2241 surface_bind(dst_surface
, context
, FALSE
);
2243 data
.buffer_object
= src_surface
->pbo
;
2244 data
.addr
= src_surface
->resource
.allocatedMemory
;
2245 src_pitch
= wined3d_surface_get_pitch(src_surface
);
2247 surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
, src_pitch
, dst_point
, FALSE
, &data
);
2249 context_invalidate_active_texture(context
);
2251 context_release(context
);
2253 surface_validate_location(dst_surface
, SFLAG_INTEXTURE
);
2254 surface_invalidate_location(dst_surface
, ~SFLAG_INTEXTURE
);
2259 /* This call just allocates the texture, the caller is responsible for binding
2260 * the correct texture. */
2261 /* Context activation is done by the caller. */
2262 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2263 const struct wined3d_format
*format
, BOOL srgb
)
2265 BOOL disable_client_storage
= FALSE
;
2266 GLsizei width
= surface
->pow2Width
;
2267 GLsizei height
= surface
->pow2Height
;
2268 const BYTE
*mem
= NULL
;
2273 internal
= format
->glGammaInternal
;
2275 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2277 internal
= format
->rtInternal
;
2281 internal
= format
->glInternal
;
2285 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format
->id
));
2287 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
2289 height
*= format
->height_scale
.numerator
;
2290 height
/= format
->height_scale
.denominator
;
2293 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",
2294 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
2295 internal
, width
, height
, format
->glFormat
, format
->glType
);
2297 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
2299 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
2300 || !surface
->resource
.allocatedMemory
)
2302 /* In some cases we want to disable client storage.
2303 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2304 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2305 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2306 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2308 surface
->flags
&= ~SFLAG_CLIENT
;
2312 surface
->flags
|= SFLAG_CLIENT
;
2314 /* Point OpenGL to our allocated texture memory. Do not use
2315 * resource.allocatedMemory here because it might point into a
2316 * PBO. Instead use heap_memory. */
2317 mem
= surface
->resource
.heap_memory
;
2319 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2320 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2321 disable_client_storage
= TRUE
;
2325 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
2327 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
2328 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
2329 checkGLcall("glCompressedTexImage2DARB");
2333 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
2334 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
2335 checkGLcall("glTexImage2D");
2338 if (disable_client_storage
)
2340 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2341 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2345 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2346 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2347 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2348 /* Context activation is done by the caller. */
2349 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
2351 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
2352 struct wined3d_renderbuffer_entry
*entry
;
2353 GLuint renderbuffer
= 0;
2354 unsigned int src_width
, src_height
;
2355 unsigned int width
, height
;
2357 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
2359 width
= rt
->pow2Width
;
2360 height
= rt
->pow2Height
;
2364 width
= surface
->pow2Width
;
2365 height
= surface
->pow2Height
;
2368 src_width
= surface
->pow2Width
;
2369 src_height
= surface
->pow2Height
;
2371 /* A depth stencil smaller than the render target is not valid */
2372 if (width
> src_width
|| height
> src_height
) return;
2374 /* Remove any renderbuffer set if the sizes match */
2375 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
2376 || (width
== src_width
&& height
== src_height
))
2378 surface
->current_renderbuffer
= NULL
;
2382 /* Look if we've already got a renderbuffer of the correct dimensions */
2383 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
2385 if (entry
->width
== width
&& entry
->height
== height
)
2387 renderbuffer
= entry
->id
;
2388 surface
->current_renderbuffer
= entry
;
2395 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
2396 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
2397 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
2398 surface
->resource
.format
->glInternal
, width
, height
);
2400 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
2401 entry
->width
= width
;
2402 entry
->height
= height
;
2403 entry
->id
= renderbuffer
;
2404 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
2406 surface
->current_renderbuffer
= entry
;
2409 checkGLcall("set_compatible_renderbuffer");
2412 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
2414 const struct wined3d_swapchain
*swapchain
= surface
->swapchain
;
2416 TRACE("surface %p.\n", surface
);
2420 ERR("Surface %p is not on a swapchain.\n", surface
);
2424 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
)
2426 if (swapchain
->render_to_fbo
)
2428 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2429 return GL_COLOR_ATTACHMENT0
;
2431 TRACE("Returning GL_BACK\n");
2434 else if (surface
== swapchain
->front_buffer
)
2436 TRACE("Returning GL_FRONT\n");
2440 FIXME("Higher back buffer, returning GL_BACK\n");
2444 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2445 void surface_add_dirty_rect(struct wined3d_surface
*surface
, const struct wined3d_box
*dirty_rect
)
2447 TRACE("surface %p, dirty_rect %p.\n", surface
, dirty_rect
);
2449 if (!(surface
->flags
& SFLAG_INSYSMEM
) && (surface
->flags
& SFLAG_INTEXTURE
))
2450 /* No partial locking for textures yet. */
2451 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2453 surface_validate_location(surface
, SFLAG_INSYSMEM
);
2454 surface_invalidate_location(surface
, ~SFLAG_INSYSMEM
);
2458 surface
->dirtyRect
.left
= min(surface
->dirtyRect
.left
, dirty_rect
->left
);
2459 surface
->dirtyRect
.top
= min(surface
->dirtyRect
.top
, dirty_rect
->top
);
2460 surface
->dirtyRect
.right
= max(surface
->dirtyRect
.right
, dirty_rect
->right
);
2461 surface
->dirtyRect
.bottom
= max(surface
->dirtyRect
.bottom
, dirty_rect
->bottom
);
2465 surface
->dirtyRect
.left
= 0;
2466 surface
->dirtyRect
.top
= 0;
2467 surface
->dirtyRect
.right
= surface
->resource
.width
;
2468 surface
->dirtyRect
.bottom
= surface
->resource
.height
;
2471 /* if the container is a texture then mark it dirty. */
2472 if (surface
->container
)
2474 TRACE("Passing to container.\n");
2475 wined3d_texture_set_dirty(surface
->container
);
2479 HRESULT
surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
2481 DWORD flag
= srgb
? SFLAG_INSRGBTEX
: SFLAG_INTEXTURE
;
2484 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
2486 if (surface
->resource
.pool
== WINED3D_POOL_SCRATCH
)
2488 ERR("Not supported on scratch surfaces.\n");
2489 return WINED3DERR_INVALIDCALL
;
2492 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
2494 /* Reload if either the texture and sysmem have different ideas about the
2495 * color key, or the actual key values changed. */
2496 if (ck_changed
|| ((surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
2497 && (surface
->gl_color_key
.color_space_low_value
!= surface
->src_blt_color_key
.color_space_low_value
2498 || surface
->gl_color_key
.color_space_high_value
!= surface
->src_blt_color_key
.color_space_high_value
)))
2500 TRACE("Reloading because of color keying\n");
2501 /* To perform the color key conversion we need a sysmem copy of
2502 * the surface. Make sure we have it. */
2504 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2505 surface_invalidate_location(surface
, ~SFLAG_INSYSMEM
);
2506 /* Switching color keying on / off may change the internal format. */
2508 surface_force_reload(surface
);
2510 else if (!(surface
->flags
& flag
))
2512 TRACE("Reloading because surface is dirty.\n");
2516 TRACE("surface is already in texture\n");
2520 /* No partial locking for textures yet. */
2521 surface_load_location(surface
, flag
, NULL
);
2522 surface_evict_sysmem(surface
);
2527 /* See also float_16_to_32() in wined3d_private.h */
2528 static inline unsigned short float_32_to_16(const float *in
)
2531 float tmp
= fabsf(*in
);
2532 unsigned int mantissa
;
2535 /* Deal with special numbers */
2541 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2543 if (tmp
< powf(2, 10))
2549 } while (tmp
< powf(2, 10));
2551 else if (tmp
>= powf(2, 11))
2557 } while (tmp
>= powf(2, 11));
2560 mantissa
= (unsigned int)tmp
;
2561 if (tmp
- mantissa
>= 0.5f
)
2562 ++mantissa
; /* Round to nearest, away from zero. */
2564 exp
+= 10; /* Normalize the mantissa. */
2565 exp
+= 15; /* Exponent is encoded with excess 15. */
2567 if (exp
> 30) /* too big */
2569 ret
= 0x7c00; /* INF */
2573 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2576 mantissa
= mantissa
>> 1;
2579 ret
= mantissa
& 0x3ff;
2583 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2586 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2590 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2594 TRACE("surface %p, swapchain %p, container %p.\n",
2595 surface
, surface
->swapchain
, surface
->container
);
2597 if (surface
->swapchain
)
2598 return wined3d_swapchain_incref(surface
->swapchain
);
2600 if (surface
->container
)
2601 return wined3d_texture_incref(surface
->container
);
2603 refcount
= InterlockedIncrement(&surface
->resource
.ref
);
2604 TRACE("%p increasing refcount to %u.\n", surface
, refcount
);
2609 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2613 TRACE("surface %p, swapchain %p, container %p.\n",
2614 surface
, surface
->swapchain
, surface
->container
);
2616 if (surface
->swapchain
)
2617 return wined3d_swapchain_decref(surface
->swapchain
);
2619 if (surface
->container
)
2620 return wined3d_texture_decref(surface
->container
);
2622 refcount
= InterlockedDecrement(&surface
->resource
.ref
);
2623 TRACE("%p decreasing refcount to %u.\n", surface
, refcount
);
2627 surface_cleanup(surface
);
2628 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
2630 TRACE("Destroyed surface %p.\n", surface
);
2631 HeapFree(GetProcessHeap(), 0, surface
);
2637 DWORD CDECL
wined3d_surface_set_priority(struct wined3d_surface
*surface
, DWORD priority
)
2639 return resource_set_priority(&surface
->resource
, priority
);
2642 DWORD CDECL
wined3d_surface_get_priority(const struct wined3d_surface
*surface
)
2644 return resource_get_priority(&surface
->resource
);
2647 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2649 struct wined3d_context
*context
;
2650 TRACE("surface %p.\n", surface
);
2652 if (!surface
->resource
.device
->d3d_initialized
)
2654 ERR("D3D not initialized.\n");
2658 context
= context_acquire(surface
->resource
.device
, NULL
);
2659 surface_internal_preload(surface
, context
, SRGB_ANY
);
2660 context_release(context
);
2663 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2665 TRACE("surface %p.\n", surface
);
2667 return surface
->resource
.parent
;
2670 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2672 TRACE("surface %p.\n", surface
);
2674 return &surface
->resource
;
2677 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2679 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2683 case WINEDDGBS_CANBLT
:
2684 case WINEDDGBS_ISBLTDONE
:
2688 return WINED3DERR_INVALIDCALL
;
2692 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2694 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2696 /* XXX: DDERR_INVALIDSURFACETYPE */
2700 case WINEDDGFS_CANFLIP
:
2701 case WINEDDGFS_ISFLIPDONE
:
2705 return WINED3DERR_INVALIDCALL
;
2709 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2711 TRACE("surface %p.\n", surface
);
2713 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2714 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2717 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2719 TRACE("surface %p.\n", surface
);
2721 surface
->flags
&= ~SFLAG_LOST
;
2725 void CDECL
wined3d_surface_set_palette(struct wined3d_surface
*surface
, struct wined3d_palette
*palette
)
2727 TRACE("surface %p, palette %p.\n", surface
, palette
);
2729 if (surface
->palette
== palette
)
2731 TRACE("Nop palette change.\n");
2735 if (surface
->palette
&& (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
2736 surface
->palette
->flags
&= ~WINEDDPCAPS_PRIMARYSURFACE
;
2738 surface
->palette
= palette
;
2742 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
2743 palette
->flags
|= WINEDDPCAPS_PRIMARYSURFACE
;
2745 surface
->surface_ops
->surface_realize_palette(surface
);
2749 HRESULT CDECL
wined3d_surface_set_color_key(struct wined3d_surface
*surface
,
2750 DWORD flags
, const struct wined3d_color_key
*color_key
)
2752 TRACE("surface %p, flags %#x, color_key %p.\n", surface
, flags
, color_key
);
2754 if (flags
& WINEDDCKEY_COLORSPACE
)
2756 FIXME(" colorkey value not supported (%08x) !\n", flags
);
2757 return WINED3DERR_INVALIDCALL
;
2760 /* Dirtify the surface, but only if a key was changed. */
2763 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
2765 case WINEDDCKEY_DESTBLT
:
2766 surface
->dst_blt_color_key
= *color_key
;
2767 surface
->CKeyFlags
|= WINEDDSD_CKDESTBLT
;
2770 case WINEDDCKEY_DESTOVERLAY
:
2771 surface
->dst_overlay_color_key
= *color_key
;
2772 surface
->CKeyFlags
|= WINEDDSD_CKDESTOVERLAY
;
2775 case WINEDDCKEY_SRCOVERLAY
:
2776 surface
->src_overlay_color_key
= *color_key
;
2777 surface
->CKeyFlags
|= WINEDDSD_CKSRCOVERLAY
;
2780 case WINEDDCKEY_SRCBLT
:
2781 surface
->src_blt_color_key
= *color_key
;
2782 surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
2788 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
2790 case WINEDDCKEY_DESTBLT
:
2791 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTBLT
;
2794 case WINEDDCKEY_DESTOVERLAY
:
2795 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTOVERLAY
;
2798 case WINEDDCKEY_SRCOVERLAY
:
2799 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCOVERLAY
;
2802 case WINEDDCKEY_SRCBLT
:
2803 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
2811 struct wined3d_palette
* CDECL
wined3d_surface_get_palette(const struct wined3d_surface
*surface
)
2813 TRACE("surface %p.\n", surface
);
2815 return surface
->palette
;
2818 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
2820 const struct wined3d_format
*format
= surface
->resource
.format
;
2823 TRACE("surface %p.\n", surface
);
2826 return surface
->pitch
;
2828 if (format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
2830 /* Since compressed formats are block based, pitch means the amount of
2831 * bytes to the next row of block rather than the next row of pixels. */
2832 UINT row_block_count
= (surface
->resource
.width
+ format
->block_width
- 1) / format
->block_width
;
2833 pitch
= row_block_count
* format
->block_byte_count
;
2837 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
2838 pitch
= surface
->resource
.format
->byte_count
* surface
->resource
.width
; /* Bytes / row */
2839 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
2842 TRACE("Returning %u.\n", pitch
);
2847 HRESULT CDECL
wined3d_surface_set_mem(struct wined3d_surface
*surface
, void *mem
, UINT pitch
)
2849 TRACE("surface %p, mem %p.\n", surface
, mem
);
2851 if (surface
->resource
.map_count
|| (surface
->flags
& SFLAG_DCINUSE
))
2853 WARN("Surface is mapped or the DC is in use.\n");
2854 return WINED3DERR_INVALIDCALL
;
2857 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
2858 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
2860 ERR("Not supported on render targets.\n");
2861 return WINED3DERR_INVALIDCALL
;
2864 if (mem
&& mem
!= surface
->resource
.allocatedMemory
)
2866 /* Do I have to copy the old surface content? */
2867 if (surface
->flags
& SFLAG_DIBSECTION
)
2869 DeleteDC(surface
->hDC
);
2870 DeleteObject(surface
->dib
.DIBsection
);
2871 surface
->dib
.bitmap_data
= NULL
;
2872 surface
->resource
.allocatedMemory
= NULL
;
2873 surface
->hDC
= NULL
;
2874 surface
->flags
&= ~SFLAG_DIBSECTION
;
2876 else if (!(surface
->flags
& SFLAG_USERPTR
))
2878 wined3d_resource_free_sysmem(&surface
->resource
);
2880 surface
->resource
.allocatedMemory
= mem
;
2881 surface
->flags
|= SFLAG_USERPTR
;
2883 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
2884 surface_validate_location(surface
, SFLAG_INSYSMEM
);
2885 surface_invalidate_location(surface
, ~SFLAG_INSYSMEM
);
2887 /* For client textures OpenGL has to be notified. */
2888 if (surface
->flags
& SFLAG_CLIENT
)
2889 surface_release_client_storage(surface
);
2891 else if (surface
->flags
& SFLAG_USERPTR
)
2893 /* heap_memory should be NULL already. */
2894 if (surface
->resource
.heap_memory
)
2895 ERR("User pointer surface has heap memory allocated.\n");
2899 surface
->resource
.allocatedMemory
= NULL
;
2900 surface
->flags
&= ~(SFLAG_USERPTR
| SFLAG_INSYSMEM
);
2902 if (surface
->flags
& SFLAG_CLIENT
)
2903 surface_release_client_storage(surface
);
2905 surface_prepare_system_memory(surface
);
2908 surface_validate_location(surface
, SFLAG_INSYSMEM
);
2909 surface_invalidate_location(surface
, ~SFLAG_INSYSMEM
);
2912 surface
->pitch
= pitch
;
2917 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
2921 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
2923 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2925 WARN("Not an overlay surface.\n");
2926 return WINEDDERR_NOTAOVERLAYSURFACE
;
2929 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
2930 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
2931 surface
->overlay_destrect
.left
= x
;
2932 surface
->overlay_destrect
.top
= y
;
2933 surface
->overlay_destrect
.right
= x
+ w
;
2934 surface
->overlay_destrect
.bottom
= y
+ h
;
2936 surface_draw_overlay(surface
);
2941 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
2943 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
2945 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2947 TRACE("Not an overlay surface.\n");
2948 return WINEDDERR_NOTAOVERLAYSURFACE
;
2951 if (!surface
->overlay_dest
)
2953 TRACE("Overlay not visible.\n");
2956 return WINEDDERR_OVERLAYNOTVISIBLE
;
2959 *x
= surface
->overlay_destrect
.left
;
2960 *y
= surface
->overlay_destrect
.top
;
2962 TRACE("Returning position %d, %d.\n", *x
, *y
);
2967 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
2968 DWORD flags
, struct wined3d_surface
*ref
)
2970 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
2972 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2974 TRACE("Not an overlay surface.\n");
2975 return WINEDDERR_NOTAOVERLAYSURFACE
;
2981 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
2982 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
2984 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2985 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
2987 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2989 WARN("Not an overlay surface.\n");
2990 return WINEDDERR_NOTAOVERLAYSURFACE
;
2992 else if (!dst_surface
)
2994 WARN("Dest surface is NULL.\n");
2995 return WINED3DERR_INVALIDCALL
;
3000 surface
->overlay_srcrect
= *src_rect
;
3004 surface
->overlay_srcrect
.left
= 0;
3005 surface
->overlay_srcrect
.top
= 0;
3006 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
3007 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
3012 surface
->overlay_destrect
= *dst_rect
;
3016 surface
->overlay_destrect
.left
= 0;
3017 surface
->overlay_destrect
.top
= 0;
3018 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
3019 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
3022 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
3024 surface
->overlay_dest
= NULL
;
3025 list_remove(&surface
->overlay_entry
);
3028 if (flags
& WINEDDOVER_SHOW
)
3030 if (surface
->overlay_dest
!= dst_surface
)
3032 surface
->overlay_dest
= dst_surface
;
3033 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
3036 else if (flags
& WINEDDOVER_HIDE
)
3038 /* tests show that the rectangles are erased on hide */
3039 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
3040 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
3041 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
3042 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
3043 surface
->overlay_dest
= NULL
;
3046 surface_draw_overlay(surface
);
3051 HRESULT CDECL
wined3d_surface_update_desc(struct wined3d_surface
*surface
,
3052 UINT width
, UINT height
, enum wined3d_format_id format_id
,
3053 enum wined3d_multisample_type multisample_type
, UINT multisample_quality
)
3055 struct wined3d_device
*device
= surface
->resource
.device
;
3056 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
3057 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
3058 UINT resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, width
, height
, 1);
3060 TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3061 surface
, width
, height
, debug_d3dformat(format_id
), multisample_type
, multisample_type
);
3064 return WINED3DERR_INVALIDCALL
;
3066 if (device
->d3d_initialized
)
3067 surface
->resource
.resource_ops
->resource_unload(&surface
->resource
);
3069 if (surface
->flags
& SFLAG_DIBSECTION
)
3071 DeleteDC(surface
->hDC
);
3072 DeleteObject(surface
->dib
.DIBsection
);
3073 surface
->dib
.bitmap_data
= NULL
;
3074 surface
->flags
&= ~SFLAG_DIBSECTION
;
3077 surface
->flags
&= ~(SFLAG_LOCATIONS
| SFLAG_USERPTR
);
3078 surface
->resource
.allocatedMemory
= NULL
;
3079 wined3d_resource_free_sysmem(&surface
->resource
);
3081 surface
->resource
.width
= width
;
3082 surface
->resource
.height
= height
;
3083 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
3084 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
3086 surface
->pow2Width
= width
;
3087 surface
->pow2Height
= height
;
3091 surface
->pow2Width
= surface
->pow2Height
= 1;
3092 while (surface
->pow2Width
< width
)
3093 surface
->pow2Width
<<= 1;
3094 while (surface
->pow2Height
< height
)
3095 surface
->pow2Height
<<= 1;
3098 if (surface
->pow2Width
!= width
|| surface
->pow2Height
!= height
)
3099 surface
->flags
|= SFLAG_NONPOW2
;
3101 surface
->flags
&= ~SFLAG_NONPOW2
;
3103 surface
->resource
.format
= format
;
3104 surface
->resource
.multisample_type
= multisample_type
;
3105 surface
->resource
.multisample_quality
= multisample_quality
;
3106 surface
->resource
.size
= resource_size
;
3108 if (!surface_init_sysmem(surface
))
3109 return E_OUTOFMEMORY
;
3114 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
3115 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3117 unsigned short *dst_s
;
3121 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3123 for (y
= 0; y
< h
; ++y
)
3125 src_f
= (const float *)(src
+ y
* pitch_in
);
3126 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
3127 for (x
= 0; x
< w
; ++x
)
3129 dst_s
[x
] = float_32_to_16(src_f
+ x
);
3134 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3135 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3137 static const unsigned char convert_5to8
[] =
3139 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3140 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3141 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3142 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3144 static const unsigned char convert_6to8
[] =
3146 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3147 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3148 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3149 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3150 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3151 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3152 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3153 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3157 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3159 for (y
= 0; y
< h
; ++y
)
3161 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
3162 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3163 for (x
= 0; x
< w
; ++x
)
3165 WORD pixel
= src_line
[x
];
3166 dst_line
[x
] = 0xff000000
3167 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
3168 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
3169 | convert_5to8
[(pixel
& 0x001f)];
3174 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3175 * in both cases we're just setting the X / Alpha channel to 0xff. */
3176 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3177 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3181 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3183 for (y
= 0; y
< h
; ++y
)
3185 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
3186 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3188 for (x
= 0; x
< w
; ++x
)
3190 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
3195 static inline BYTE
cliptobyte(int x
)
3197 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
3200 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3201 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3203 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3206 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3208 for (y
= 0; y
< h
; ++y
)
3210 const BYTE
*src_line
= src
+ y
* pitch_in
;
3211 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3212 for (x
= 0; x
< w
; ++x
)
3214 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3215 * C = Y - 16; D = U - 128; E = V - 128;
3216 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3217 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3218 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3219 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3220 * U and V are shared between the pixels. */
3221 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3223 d
= (int) src_line
[1] - 128;
3224 e
= (int) src_line
[3] - 128;
3226 g2
= - 100 * d
- 208 * e
+ 128;
3229 c2
= 298 * ((int) src_line
[0] - 16);
3230 dst_line
[x
] = 0xff000000
3231 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
3232 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
3233 | cliptobyte((c2
+ b2
) >> 8); /* blue */
3234 /* Scale RGB values to 0..255 range,
3235 * then clip them if still not in range (may be negative),
3236 * then shift them within DWORD if necessary. */
3242 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
3243 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3246 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3248 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
3250 for (y
= 0; y
< h
; ++y
)
3252 const BYTE
*src_line
= src
+ y
* pitch_in
;
3253 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
3254 for (x
= 0; x
< w
; ++x
)
3256 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3257 * C = Y - 16; D = U - 128; E = V - 128;
3258 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3259 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3260 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3261 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3262 * U and V are shared between the pixels. */
3263 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3265 d
= (int) src_line
[1] - 128;
3266 e
= (int) src_line
[3] - 128;
3268 g2
= - 100 * d
- 208 * e
+ 128;
3271 c2
= 298 * ((int) src_line
[0] - 16);
3272 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
3273 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
3274 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
3275 /* Scale RGB values to 0..255 range,
3276 * then clip them if still not in range (may be negative),
3277 * then shift them within DWORD if necessary. */
3283 struct d3dfmt_converter_desc
3285 enum wined3d_format_id from
, to
;
3286 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
3289 static const struct d3dfmt_converter_desc converters
[] =
3291 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
3292 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
3293 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3294 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3295 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
3296 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
3299 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
3300 enum wined3d_format_id to
)
3304 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
3306 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
3307 return &converters
[i
];
3313 /*****************************************************************************
3314 * surface_convert_format
3316 * Creates a duplicate of a surface in a different format. Is used by Blt to
3317 * blit between surfaces with different formats.
3320 * source: Source surface
3321 * fmt: Requested destination format
3323 *****************************************************************************/
3324 static struct wined3d_surface
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
3326 struct wined3d_map_desc src_map
, dst_map
;
3327 const struct d3dfmt_converter_desc
*conv
;
3328 struct wined3d_surface
*ret
= NULL
;
3331 conv
= find_converter(source
->resource
.format
->id
, to_fmt
);
3334 FIXME("Cannot find a conversion function from format %s to %s.\n",
3335 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
3339 /* FIXME: Multisampled conversion? */
3340 if (FAILED(hr
= wined3d_surface_create(source
->resource
.device
, source
->resource
.width
, source
->resource
.height
,
3341 to_fmt
, 0, WINED3D_POOL_SCRATCH
, WINED3D_MULTISAMPLE_NONE
, 0,
3342 WINED3D_SURFACE_MAPPABLE
| WINED3D_SURFACE_DISCARD
, NULL
, &wined3d_null_parent_ops
, &ret
)))
3344 ERR("Failed to create a destination surface for conversion.\n");
3348 memset(&src_map
, 0, sizeof(src_map
));
3349 memset(&dst_map
, 0, sizeof(dst_map
));
3351 if (FAILED(hr
= wined3d_surface_map(source
, &src_map
, NULL
, WINED3D_MAP_READONLY
)))
3353 ERR("Failed to lock the source surface.\n");
3354 wined3d_surface_decref(ret
);
3357 if (FAILED(hr
= wined3d_surface_map(ret
, &dst_map
, NULL
, WINED3D_MAP_READONLY
)))
3359 ERR("Failed to lock the destination surface.\n");
3360 wined3d_surface_unmap(source
);
3361 wined3d_surface_decref(ret
);
3365 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
3366 source
->resource
.width
, source
->resource
.height
);
3368 wined3d_surface_unmap(ret
);
3369 wined3d_surface_unmap(source
);
3374 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
3375 unsigned int bpp
, UINT pitch
, DWORD color
)
3382 #define COLORFILL_ROW(type) \
3384 type *d = (type *)buf; \
3385 for (x = 0; x < width; ++x) \
3386 d[x] = (type)color; \
3392 COLORFILL_ROW(BYTE
);
3396 COLORFILL_ROW(WORD
);
3402 for (x
= 0; x
< width
; ++x
, d
+= 3)
3404 d
[0] = (color
) & 0xff;
3405 d
[1] = (color
>> 8) & 0xff;
3406 d
[2] = (color
>> 16) & 0xff;
3411 COLORFILL_ROW(DWORD
);
3415 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
3416 return WINED3DERR_NOTAVAILABLE
;
3419 #undef COLORFILL_ROW
3421 /* Now copy first row. */
3423 for (y
= 1; y
< height
; ++y
)
3426 memcpy(buf
, first
, width
* bpp
);
3432 struct wined3d_surface
* CDECL
wined3d_surface_from_resource(struct wined3d_resource
*resource
)
3434 return surface_from_resource(resource
);
3437 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
3439 TRACE("surface %p.\n", surface
);
3441 if (!surface
->resource
.map_count
)
3443 WARN("Trying to unmap unmapped surface.\n");
3444 return WINEDDERR_NOTLOCKED
;
3446 --surface
->resource
.map_count
;
3448 surface
->surface_ops
->surface_unmap(surface
);
3453 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
3454 struct wined3d_map_desc
*map_desc
, const RECT
*rect
, DWORD flags
)
3456 const struct wined3d_format
*format
= surface
->resource
.format
;
3458 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
3459 surface
, map_desc
, wine_dbgstr_rect(rect
), flags
);
3461 if (surface
->resource
.map_count
)
3463 WARN("Surface is already mapped.\n");
3464 return WINED3DERR_INVALIDCALL
;
3467 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && rect
3468 && !surface_check_block_align(surface
, rect
))
3470 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
3471 wine_dbgstr_rect(rect
), format
->block_width
, format
->block_height
);
3473 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
3474 return WINED3DERR_INVALIDCALL
;
3477 ++surface
->resource
.map_count
;
3479 if (!(surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
3480 WARN("Trying to lock unlockable surface.\n");
3482 /* Performance optimization: Count how often a surface is mapped, if it is
3483 * mapped regularly do not throw away the system memory copy. This avoids
3484 * the need to download the surface from OpenGL all the time. The surface
3485 * is still downloaded if the OpenGL texture is changed. */
3486 if (!(surface
->flags
& SFLAG_DYNLOCK
))
3488 if (++surface
->lockCount
> MAXLOCKCOUNT
)
3490 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3491 surface
->flags
|= SFLAG_DYNLOCK
;
3495 surface
->surface_ops
->surface_map(surface
, rect
, flags
);
3497 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
3498 map_desc
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
3500 map_desc
->row_pitch
= wined3d_surface_get_pitch(surface
);
3501 map_desc
->slice_pitch
= 0;
3505 map_desc
->data
= surface
->resource
.allocatedMemory
;
3506 surface
->lockedRect
.left
= 0;
3507 surface
->lockedRect
.top
= 0;
3508 surface
->lockedRect
.right
= surface
->resource
.width
;
3509 surface
->lockedRect
.bottom
= surface
->resource
.height
;
3513 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
3515 /* Compressed textures are block based, so calculate the offset of
3516 * the block that contains the top-left pixel of the locked rectangle. */
3517 map_desc
->data
= surface
->resource
.allocatedMemory
3518 + ((rect
->top
/ format
->block_height
) * map_desc
->row_pitch
)
3519 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
3523 map_desc
->data
= surface
->resource
.allocatedMemory
3524 + (map_desc
->row_pitch
* rect
->top
)
3525 + (rect
->left
* format
->byte_count
);
3527 surface
->lockedRect
.left
= rect
->left
;
3528 surface
->lockedRect
.top
= rect
->top
;
3529 surface
->lockedRect
.right
= rect
->right
;
3530 surface
->lockedRect
.bottom
= rect
->bottom
;
3533 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
3534 TRACE("Returning memory %p, pitch %u.\n", map_desc
->data
, map_desc
->row_pitch
);
3539 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
3541 struct wined3d_map_desc map
;
3544 TRACE("surface %p, dc %p.\n", surface
, dc
);
3546 if (surface
->flags
& SFLAG_USERPTR
)
3548 ERR("Not supported on surfaces with application-provided memory.\n");
3549 return WINEDDERR_NODC
;
3552 /* Give more detailed info for ddraw. */
3553 if (surface
->flags
& SFLAG_DCINUSE
)
3554 return WINEDDERR_DCALREADYCREATED
;
3556 /* Can't GetDC if the surface is locked. */
3557 if (surface
->resource
.map_count
)
3558 return WINED3DERR_INVALIDCALL
;
3560 /* Create a DIB section if there isn't a dc yet. */
3563 if (surface
->flags
& SFLAG_CLIENT
)
3565 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
3566 surface_release_client_storage(surface
);
3568 hr
= surface_create_dib_section(surface
);
3570 return WINED3DERR_INVALIDCALL
;
3572 /* Use the DIB section from now on if we are not using a PBO. */
3573 if (!(surface
->flags
& (SFLAG_PBO
| SFLAG_PIN_SYSMEM
)))
3575 wined3d_resource_free_sysmem(&surface
->resource
);
3576 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
3580 /* Map the surface. */
3581 hr
= wined3d_surface_map(surface
, &map
, NULL
, 0);
3584 ERR("Map failed, hr %#x.\n", hr
);
3588 /* Sync the DIB with the PBO. This can't be done earlier because Map()
3589 * activates the allocatedMemory. */
3590 if (surface
->flags
& (SFLAG_PBO
| SFLAG_PIN_SYSMEM
))
3591 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
3593 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3594 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3596 /* GetDC on palettized formats is unsupported in D3D9, and the method
3597 * is missing in D3D8, so this should only be used for DX <=7
3598 * surfaces (with non-device palettes). */
3599 const PALETTEENTRY
*pal
= NULL
;
3601 if (surface
->palette
)
3603 pal
= surface
->palette
->palents
;
3607 struct wined3d_swapchain
*swapchain
= surface
->resource
.device
->swapchains
[0];
3608 struct wined3d_surface
*dds_primary
= swapchain
->front_buffer
;
3610 if (dds_primary
&& dds_primary
->palette
)
3611 pal
= dds_primary
->palette
->palents
;
3619 for (i
= 0; i
< 256; ++i
)
3621 col
[i
].rgbRed
= pal
[i
].peRed
;
3622 col
[i
].rgbGreen
= pal
[i
].peGreen
;
3623 col
[i
].rgbBlue
= pal
[i
].peBlue
;
3624 col
[i
].rgbReserved
= 0;
3626 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
3630 surface
->flags
|= SFLAG_DCINUSE
;
3633 TRACE("Returning dc %p.\n", *dc
);
3638 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
3640 TRACE("surface %p, dc %p.\n", surface
, dc
);
3642 if (!(surface
->flags
& SFLAG_DCINUSE
))
3643 return WINEDDERR_NODC
;
3645 if (surface
->hDC
!= dc
)
3647 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3649 return WINEDDERR_NODC
;
3652 /* Copy the contents of the DIB over to the PBO. */
3653 if ((surface
->flags
& (SFLAG_PBO
| SFLAG_PIN_SYSMEM
)) && surface
->resource
.allocatedMemory
)
3654 memcpy(surface
->resource
.allocatedMemory
, surface
->dib
.bitmap_data
, surface
->resource
.size
);
3656 /* We locked first, so unlock now. */
3657 wined3d_surface_unmap(surface
);
3659 surface
->flags
&= ~SFLAG_DCINUSE
;
3664 HRESULT CDECL
wined3d_surface_flip(struct wined3d_surface
*surface
, struct wined3d_surface
*override
, DWORD flags
)
3666 TRACE("surface %p, override %p, flags %#x.\n", surface
, override
, flags
);
3672 FIXME("Ignoring flags %#x.\n", flags
);
3674 WARN("Ignoring flags %#x.\n", flags
);
3677 if (surface
->swapchain
)
3679 ERR("Not supported on swapchain surfaces.\n");
3680 return WINEDDERR_NOTFLIPPABLE
;
3683 flip_surface(surface
, override
);
3685 /* Update overlays if they're visible. */
3686 if ((surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
) && surface
->overlay_dest
)
3687 return surface_draw_overlay(surface
);
3692 /* Context activation is done by the caller */
3693 void surface_internal_preload(struct wined3d_surface
*surface
,
3694 struct wined3d_context
*context
, enum WINED3DSRGB srgb
)
3696 TRACE("iface %p, srgb %#x.\n", surface
, srgb
);
3698 if (surface
->container
)
3700 struct wined3d_texture
*texture
= surface
->container
;
3702 TRACE("Passing to container (%p).\n", texture
);
3703 texture
->texture_ops
->texture_preload(texture
, context
, srgb
);
3707 TRACE("(%p) : About to load surface\n", surface
);
3709 surface_load(surface
, srgb
== SRGB_SRGB
);
3711 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
3713 /* Tell opengl to try and keep this texture in video ram (well mostly) */
3716 context
->gl_info
->gl_ops
.gl
.p_glPrioritizeTextures(1, &surface
->texture_name
, &tmp
);
3721 /* Read the framebuffer back into the surface */
3722 static void read_from_framebuffer(struct wined3d_surface
*surface
, const RECT
*rect
, void *dest
, UINT pitch
)
3724 struct wined3d_device
*device
= surface
->resource
.device
;
3725 const struct wined3d_gl_info
*gl_info
;
3726 struct wined3d_context
*context
;
3730 BYTE
*row
, *top
, *bottom
;
3734 BOOL srcIsUpsideDown
;
3739 context
= context_acquire(device
, surface
);
3740 context_apply_blit_state(context
, device
);
3741 gl_info
= context
->gl_info
;
3743 /* Select the correct read buffer, and give some debug output.
3744 * There is no need to keep track of the current read buffer or reset it, every part of the code
3745 * that reads sets the read buffer as desired.
3747 if (surface_is_offscreen(surface
))
3749 /* Mapping the primary render target which is not on a swapchain.
3750 * Read from the back buffer. */
3751 TRACE("Mapping offscreen render target.\n");
3752 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3753 srcIsUpsideDown
= TRUE
;
3757 /* Onscreen surfaces are always part of a swapchain */
3758 GLenum buffer
= surface_get_gl_buffer(surface
);
3759 TRACE("Mapping %#x buffer.\n", buffer
);
3760 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
3761 checkGLcall("glReadBuffer");
3762 srcIsUpsideDown
= FALSE
;
3765 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
3768 local_rect
.left
= 0;
3770 local_rect
.right
= surface
->resource
.width
;
3771 local_rect
.bottom
= surface
->resource
.height
;
3777 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
3779 switch (surface
->resource
.format
->id
)
3781 case WINED3DFMT_P8_UINT
:
3783 if (swapchain_is_p8(context
->swapchain
))
3785 /* In case of P8 render targets the index is stored in the alpha component */
3787 type
= GL_UNSIGNED_BYTE
;
3789 bpp
= surface
->resource
.format
->byte_count
;
3793 /* GL can't return palettized data, so read ARGB pixels into a
3794 * separate block of memory and convert them into palettized format
3795 * in software. Slow, but if the app means to use palettized render
3796 * targets and locks it...
3798 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
3799 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
3800 * for the color channels when palettizing the colors.
3803 type
= GL_UNSIGNED_BYTE
;
3805 mem
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
* 3);
3808 ERR("Out of memory\n");
3811 bpp
= surface
->resource
.format
->byte_count
* 3;
3818 fmt
= surface
->resource
.format
->glFormat
;
3819 type
= surface
->resource
.format
->glType
;
3820 bpp
= surface
->resource
.format
->byte_count
;
3823 if (surface
->flags
& SFLAG_PBO
)
3825 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
3826 checkGLcall("glBindBufferARB");
3829 ERR("mem not null for pbo -- unexpected\n");
3834 /* Save old pixel store pack state */
3835 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_PACK_ROW_LENGTH
, &rowLen
);
3836 checkGLcall("glGetIntegerv");
3837 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_PACK_SKIP_PIXELS
, &skipPix
);
3838 checkGLcall("glGetIntegerv");
3839 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_PACK_SKIP_ROWS
, &skipRow
);
3840 checkGLcall("glGetIntegerv");
3842 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3843 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
3844 checkGLcall("glPixelStorei");
3845 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_SKIP_PIXELS
, local_rect
.left
);
3846 checkGLcall("glPixelStorei");
3847 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_SKIP_ROWS
, local_rect
.top
);
3848 checkGLcall("glPixelStorei");
3850 gl_info
->gl_ops
.gl
.p_glReadPixels(local_rect
.left
,
3851 !srcIsUpsideDown
? (surface
->resource
.height
- local_rect
.bottom
) : local_rect
.top
,
3852 local_rect
.right
- local_rect
.left
,
3853 local_rect
.bottom
- local_rect
.top
,
3855 checkGLcall("glReadPixels");
3857 /* Reset previous pixel store pack state */
3858 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, rowLen
);
3859 checkGLcall("glPixelStorei");
3860 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_SKIP_PIXELS
, skipPix
);
3861 checkGLcall("glPixelStorei");
3862 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_SKIP_ROWS
, skipRow
);
3863 checkGLcall("glPixelStorei");
3865 if (surface
->flags
& SFLAG_PBO
)
3867 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
3868 checkGLcall("glBindBufferARB");
3870 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
3871 * to get a pointer to it and perform the flipping in software. This is a lot
3872 * faster than calling glReadPixels for each line. In case we want more speed
3873 * we should rerender it flipped in a FBO and read the data back from the FBO. */
3874 if (!srcIsUpsideDown
)
3876 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
3877 checkGLcall("glBindBufferARB");
3879 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
3880 checkGLcall("glMapBufferARB");
3884 /* TODO: Merge this with the palettization loop below for P8 targets */
3885 if(!srcIsUpsideDown
) {
3887 /* glReadPixels returns the image upside down, and there is no way to prevent this.
3888 Flip the lines in software */
3889 len
= (local_rect
.right
- local_rect
.left
) * bpp
;
3890 off
= local_rect
.left
* bpp
;
3892 row
= HeapAlloc(GetProcessHeap(), 0, len
);
3894 ERR("Out of memory\n");
3895 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3896 HeapFree(GetProcessHeap(), 0, mem
);
3900 top
= mem
+ pitch
* local_rect
.top
;
3901 bottom
= mem
+ pitch
* (local_rect
.bottom
- 1);
3902 for(i
= 0; i
< (local_rect
.bottom
- local_rect
.top
) / 2; i
++) {
3903 memcpy(row
, top
+ off
, len
);
3904 memcpy(top
+ off
, bottom
+ off
, len
);
3905 memcpy(bottom
+ off
, row
, len
);
3909 HeapFree(GetProcessHeap(), 0, row
);
3911 /* Unmap the temp PBO buffer */
3912 if (surface
->flags
& SFLAG_PBO
)
3914 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
3915 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
3919 /* For P8 textures we need to perform an inverse palette lookup. This is
3920 * done by searching for a palette index which matches the RGB value.
3921 * Note this isn't guaranteed to work when there are multiple entries for
3922 * the same color but we have no choice. In case of P8 render targets,
3923 * the index is stored in the alpha component so no conversion is needed. */
3924 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
&& !swapchain_is_p8(context
->swapchain
))
3926 const PALETTEENTRY
*pal
= NULL
;
3927 DWORD width
= pitch
/ 3;
3930 if (surface
->palette
)
3932 pal
= surface
->palette
->palents
;
3936 ERR("Palette is missing, cannot perform inverse palette lookup\n");
3937 HeapFree(GetProcessHeap(), 0, mem
);
3941 for(y
= local_rect
.top
; y
< local_rect
.bottom
; y
++) {
3942 for(x
= local_rect
.left
; x
< local_rect
.right
; x
++) {
3943 /* start lines pixels */
3944 const BYTE
*blue
= mem
+ y
* pitch
+ x
* (sizeof(BYTE
) * 3);
3945 const BYTE
*green
= blue
+ 1;
3946 const BYTE
*red
= green
+ 1;
3948 for(c
= 0; c
< 256; c
++) {
3949 if(*red
== pal
[c
].peRed
&&
3950 *green
== pal
[c
].peGreen
&&
3951 *blue
== pal
[c
].peBlue
)
3953 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
3959 HeapFree(GetProcessHeap(), 0, mem
);
3962 context_release(context
);
3965 /* Read the framebuffer contents into a texture. Note that this function
3966 * doesn't do any kind of flipping. Using this on an onscreen surface will
3967 * result in a flipped D3D texture. */
3968 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
)
3970 struct wined3d_device
*device
= surface
->resource
.device
;
3971 const struct wined3d_gl_info
*gl_info
;
3972 struct wined3d_context
*context
;
3974 context
= context_acquire(device
, surface
);
3975 gl_info
= context
->gl_info
;
3976 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
3978 surface_prepare_texture(surface
, context
, srgb
);
3979 surface_bind_and_dirtify(surface
, context
, srgb
);
3981 TRACE("Reading back offscreen render target %p.\n", surface
);
3983 if (surface_is_offscreen(surface
))
3984 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3986 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(surface
));
3987 checkGLcall("glReadBuffer");
3989 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
3990 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
3991 checkGLcall("glCopyTexSubImage2D");
3993 context_release(context
);
3996 /* Context activation is done by the caller. */
3997 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
3998 struct wined3d_context
*context
, BOOL srgb
)
4000 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
4001 enum wined3d_conversion_type convert
;
4002 struct wined3d_format format
;
4004 if (surface
->flags
& alloc_flag
) return;
4006 d3dfmt_get_conv(surface
, TRUE
, TRUE
, &format
, &convert
);
4007 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
4008 surface
->flags
|= SFLAG_CONVERTED
;
4009 else surface
->flags
&= ~SFLAG_CONVERTED
;
4011 surface_bind_and_dirtify(surface
, context
, srgb
);
4012 surface_allocate_surface(surface
, context
->gl_info
, &format
, srgb
);
4013 surface
->flags
|= alloc_flag
;
4016 /* Context activation is done by the caller. */
4017 void surface_prepare_texture(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
4019 if (surface
->container
)
4021 struct wined3d_texture
*texture
= surface
->container
;
4022 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
4025 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
4027 for (i
= 0; i
< sub_count
; ++i
)
4029 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
4030 surface_prepare_texture_internal(s
, context
, srgb
);
4036 surface_prepare_texture_internal(surface
, context
, srgb
);
4039 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
4043 if (surface
->rb_multisample
)
4046 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
4047 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
4048 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
4049 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
4050 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
4054 if (surface
->rb_resolved
)
4057 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
4058 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
4059 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
4060 surface
->pow2Width
, surface
->pow2Height
);
4061 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
4065 static BOOL
color_in_range(const struct wined3d_color_key
*color_key
, DWORD color
)
4067 /* FIXME: Is this really how color keys are supposed to work? I think it
4068 * makes more sense to compare the individual channels. */
4069 return color
>= color_key
->color_space_low_value
4070 && color
<= color_key
->color_space_high_value
;
4073 void d3dfmt_p8_init_palette(const struct wined3d_surface
*surface
, BYTE table
[256][4], BOOL colorkey
)
4075 const struct wined3d_device
*device
= surface
->resource
.device
;
4076 const struct wined3d_palette
*pal
= surface
->palette
;
4077 BOOL index_in_alpha
= FALSE
;
4080 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4081 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4082 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4083 * duplicate entries. Store the color key in the unused alpha component to speed the
4084 * download up and to make conversion unneeded. */
4085 index_in_alpha
= swapchain_is_p8(device
->swapchains
[0]);
4089 FIXME("No palette set.\n");
4092 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4093 * there's no palette at this time. */
4094 for (i
= 0; i
< 256; i
++) table
[i
][3] = i
;
4099 TRACE("Using surface palette %p\n", pal
);
4100 /* Get the surface's palette */
4101 for (i
= 0; i
< 256; ++i
)
4103 table
[i
][0] = pal
->palents
[i
].peRed
;
4104 table
[i
][1] = pal
->palents
[i
].peGreen
;
4105 table
[i
][2] = pal
->palents
[i
].peBlue
;
4107 /* When index_in_alpha is set the palette index is stored in the
4108 * alpha component. In case of a readback we can then read
4109 * GL_ALPHA. Color keying is handled in surface_blt_special() using a
4110 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4111 * color key itself is passed to glAlphaFunc in other cases the
4112 * alpha component of pixels that should be masked away is set to 0. */
4115 else if (colorkey
&& color_in_range(&surface
->src_blt_color_key
, i
))
4117 else if (pal
->flags
& WINEDDPCAPS_ALPHA
)
4118 table
[i
][3] = pal
->palents
[i
].peFlags
;
4125 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
,
4126 UINT outpitch
, enum wined3d_conversion_type conversion_type
, struct wined3d_surface
*surface
)
4131 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4132 src
, dst
, pitch
, width
, height
, outpitch
, conversion_type
, surface
);
4134 switch (conversion_type
)
4136 case WINED3D_CT_NONE
:
4138 memcpy(dst
, src
, pitch
* height
);
4142 case WINED3D_CT_PALETTED
:
4143 case WINED3D_CT_PALETTED_CK
:
4148 d3dfmt_p8_init_palette(surface
, table
, (conversion_type
== WINED3D_CT_PALETTED_CK
));
4150 for (y
= 0; y
< height
; y
++)
4152 source
= src
+ pitch
* y
;
4153 dest
= dst
+ outpitch
* y
;
4154 /* This is an 1 bpp format, using the width here is fine */
4155 for (x
= 0; x
< width
; x
++) {
4156 BYTE color
= *source
++;
4157 *dest
++ = table
[color
][0];
4158 *dest
++ = table
[color
][1];
4159 *dest
++ = table
[color
][2];
4160 *dest
++ = table
[color
][3];
4166 case WINED3D_CT_CK_565
:
4168 /* Converting the 565 format in 5551 packed to emulate color-keying.
4170 Note : in all these conversion, it would be best to average the averaging
4171 pixels to get the color of the pixel that will be color-keyed to
4172 prevent 'color bleeding'. This will be done later on if ever it is
4175 Note2: Nvidia documents say that their driver does not support alpha + color keying
4176 on the same surface and disables color keying in such a case
4182 TRACE("Color keyed 565\n");
4184 for (y
= 0; y
< height
; y
++) {
4185 Source
= (const WORD
*)(src
+ y
* pitch
);
4186 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4187 for (x
= 0; x
< width
; x
++ ) {
4188 WORD color
= *Source
++;
4189 *Dest
= ((color
& 0xffc0) | ((color
& 0x1f) << 1));
4190 if (!color_in_range(&surface
->src_blt_color_key
, color
))
4198 case WINED3D_CT_CK_5551
:
4200 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4204 TRACE("Color keyed 5551\n");
4205 for (y
= 0; y
< height
; y
++) {
4206 Source
= (const WORD
*)(src
+ y
* pitch
);
4207 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4208 for (x
= 0; x
< width
; x
++ ) {
4209 WORD color
= *Source
++;
4211 if (!color_in_range(&surface
->src_blt_color_key
, color
))
4214 *Dest
&= ~(1 << 15);
4221 case WINED3D_CT_CK_RGB24
:
4223 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4225 for (y
= 0; y
< height
; y
++)
4227 source
= src
+ pitch
* y
;
4228 dest
= dst
+ outpitch
* y
;
4229 for (x
= 0; x
< width
; x
++) {
4230 DWORD color
= ((DWORD
)source
[0] << 16) + ((DWORD
)source
[1] << 8) + (DWORD
)source
[2] ;
4231 DWORD dstcolor
= color
<< 8;
4232 if (!color_in_range(&surface
->src_blt_color_key
, color
))
4234 *(DWORD
*)dest
= dstcolor
;
4242 case WINED3D_CT_RGB32_888
:
4244 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4246 for (y
= 0; y
< height
; y
++)
4248 source
= src
+ pitch
* y
;
4249 dest
= dst
+ outpitch
* y
;
4250 for (x
= 0; x
< width
; x
++) {
4251 DWORD color
= 0xffffff & *(const DWORD
*)source
;
4252 DWORD dstcolor
= color
<< 8;
4253 if (!color_in_range(&surface
->src_blt_color_key
, color
))
4255 *(DWORD
*)dest
= dstcolor
;
4263 case WINED3D_CT_CK_ARGB32
:
4266 for (y
= 0; y
< height
; ++y
)
4268 source
= src
+ pitch
* y
;
4269 dest
= dst
+ outpitch
* y
;
4270 for (x
= 0; x
< width
; ++x
)
4272 DWORD color
= *(const DWORD
*)source
;
4273 if (color_in_range(&surface
->src_blt_color_key
, color
))
4274 color
&= ~0xff000000;
4275 *(DWORD
*)dest
= color
;
4284 ERR("Unsupported conversion type %#x.\n", conversion_type
);
4289 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
4291 /* Flip the surface contents */
4296 front
->hDC
= back
->hDC
;
4300 /* Flip the DIBsection */
4302 HBITMAP tmp
= front
->dib
.DIBsection
;
4303 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
4304 back
->dib
.DIBsection
= tmp
;
4307 /* Flip the surface data */
4311 tmp
= front
->dib
.bitmap_data
;
4312 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
4313 back
->dib
.bitmap_data
= tmp
;
4315 tmp
= front
->resource
.allocatedMemory
;
4316 front
->resource
.allocatedMemory
= back
->resource
.allocatedMemory
;
4317 back
->resource
.allocatedMemory
= tmp
;
4319 tmp
= front
->resource
.heap_memory
;
4320 front
->resource
.heap_memory
= back
->resource
.heap_memory
;
4321 back
->resource
.heap_memory
= tmp
;
4326 GLuint tmp_pbo
= front
->pbo
;
4327 front
->pbo
= back
->pbo
;
4328 back
->pbo
= tmp_pbo
;
4331 /* Flip the opengl texture */
4335 tmp
= back
->texture_name
;
4336 back
->texture_name
= front
->texture_name
;
4337 front
->texture_name
= tmp
;
4339 tmp
= back
->texture_name_srgb
;
4340 back
->texture_name_srgb
= front
->texture_name_srgb
;
4341 front
->texture_name_srgb
= tmp
;
4343 tmp
= back
->rb_multisample
;
4344 back
->rb_multisample
= front
->rb_multisample
;
4345 front
->rb_multisample
= tmp
;
4347 tmp
= back
->rb_resolved
;
4348 back
->rb_resolved
= front
->rb_resolved
;
4349 front
->rb_resolved
= tmp
;
4351 resource_unload(&back
->resource
);
4352 resource_unload(&front
->resource
);
4356 DWORD tmp_flags
= back
->flags
;
4357 back
->flags
= front
->flags
;
4358 front
->flags
= tmp_flags
;
4362 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4363 * pixel copy calls. */
4364 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4365 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
4367 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4368 const struct wined3d_gl_info
*gl_info
;
4370 struct wined3d_context
*context
;
4371 BOOL upsidedown
= FALSE
;
4372 RECT dst_rect
= *dst_rect_in
;
4375 if (dst_surface
->container
)
4376 dst_target
= dst_surface
->container
->target
;
4378 dst_target
= dst_surface
->texture_target
;
4380 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4381 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4383 if(dst_rect
.top
> dst_rect
.bottom
) {
4384 UINT tmp
= dst_rect
.bottom
;
4385 dst_rect
.bottom
= dst_rect
.top
;
4390 context
= context_acquire(device
, src_surface
);
4391 gl_info
= context
->gl_info
;
4392 context_apply_blit_state(context
, device
);
4393 surface_internal_preload(dst_surface
, context
, SRGB_RGB
);
4395 /* Bind the target texture */
4396 context_bind_texture(context
, dst_target
, dst_surface
->texture_name
);
4397 if (surface_is_offscreen(src_surface
))
4399 TRACE("Reading from an offscreen target\n");
4400 upsidedown
= !upsidedown
;
4401 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
4405 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
4407 checkGLcall("glReadBuffer");
4409 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
4410 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
4412 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4414 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4416 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
4417 ERR("Texture filtering not supported in direct blit.\n");
4419 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
4420 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4422 ERR("Texture filtering not supported in direct blit\n");
4426 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4427 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4429 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
4430 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4431 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
4432 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
4433 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
4438 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
4439 /* I have to process this row by row to swap the image,
4440 * otherwise it would be upside down, so stretching in y direction
4441 * doesn't cost extra time
4443 * However, stretching in x direction can be avoided if not necessary
4445 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
4446 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4448 /* Well, that stuff works, but it's very slow.
4449 * find a better way instead
4453 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
4455 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4456 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
4457 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
4462 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4463 dst_rect
.left
/* x offset */, row
/* y offset */,
4464 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
4468 checkGLcall("glCopyTexSubImage2D");
4470 context_release(context
);
4472 /* The texture is now most up to date - If the surface is a render target
4473 * and has a drawable, this path is never entered. */
4474 surface_validate_location(dst_surface
, SFLAG_INTEXTURE
);
4475 surface_invalidate_location(dst_surface
, ~SFLAG_INTEXTURE
);
4478 /* Uses the hardware to stretch and flip the image */
4479 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4480 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
4482 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4483 GLuint src
, backup
= 0;
4484 float left
, right
, top
, bottom
; /* Texture coordinates */
4485 UINT fbwidth
= src_surface
->resource
.width
;
4486 UINT fbheight
= src_surface
->resource
.height
;
4487 const struct wined3d_gl_info
*gl_info
;
4488 struct wined3d_context
*context
;
4489 GLenum drawBuffer
= GL_BACK
;
4490 GLenum texture_target
;
4491 BOOL noBackBufferBackup
;
4493 BOOL upsidedown
= FALSE
;
4494 RECT dst_rect
= *dst_rect_in
;
4496 TRACE("Using hwstretch blit\n");
4497 /* Activate the Proper context for reading from the source surface, set it up for blitting */
4498 context
= context_acquire(device
, src_surface
);
4499 gl_info
= context
->gl_info
;
4500 context_apply_blit_state(context
, device
);
4501 surface_internal_preload(dst_surface
, context
, SRGB_RGB
);
4503 src_offscreen
= surface_is_offscreen(src_surface
);
4504 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
4505 if (!noBackBufferBackup
&& !src_surface
->texture_name
)
4507 /* Get it a description */
4508 surface_internal_preload(src_surface
, context
, SRGB_RGB
);
4511 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
4512 * This way we don't have to wait for the 2nd readback to finish to leave this function.
4514 if (context
->aux_buffers
>= 2)
4516 /* Got more than one aux buffer? Use the 2nd aux buffer */
4517 drawBuffer
= GL_AUX1
;
4519 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
4521 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
4522 drawBuffer
= GL_AUX0
;
4525 if (noBackBufferBackup
)
4527 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
4528 checkGLcall("glGenTextures");
4529 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
4530 texture_target
= GL_TEXTURE_2D
;
4534 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
4535 * we are reading from the back buffer, the backup can be used as source texture
4537 texture_target
= src_surface
->texture_target
;
4538 context_bind_texture(context
, texture_target
, src_surface
->texture_name
);
4539 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
4540 checkGLcall("glEnable(texture_target)");
4542 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
4543 src_surface
->flags
&= ~SFLAG_INTEXTURE
;
4546 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4547 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4549 if(dst_rect
.top
> dst_rect
.bottom
) {
4550 UINT tmp
= dst_rect
.bottom
;
4551 dst_rect
.bottom
= dst_rect
.top
;
4558 TRACE("Reading from an offscreen target\n");
4559 upsidedown
= !upsidedown
;
4560 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
4564 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
4567 /* TODO: Only back up the part that will be overwritten */
4568 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
4570 checkGLcall("glCopyTexSubImage2D");
4572 /* No issue with overriding these - the sampler is dirty due to blit usage */
4573 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
4574 wined3d_gl_mag_filter(magLookup
, filter
));
4575 checkGLcall("glTexParameteri");
4576 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
4577 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
4578 checkGLcall("glTexParameteri");
4580 if (!src_surface
->swapchain
|| src_surface
== src_surface
->swapchain
->back_buffers
[0])
4582 src
= backup
? backup
: src_surface
->texture_name
;
4586 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
4587 checkGLcall("glReadBuffer(GL_FRONT)");
4589 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
4590 checkGLcall("glGenTextures(1, &src)");
4591 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
4593 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
4594 * out for power of 2 sizes
4596 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
4597 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
4598 checkGLcall("glTexImage2D");
4599 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
4601 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
4602 checkGLcall("glTexParameteri");
4603 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
4604 checkGLcall("glTexParameteri");
4606 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
4607 checkGLcall("glReadBuffer(GL_BACK)");
4609 if (texture_target
!= GL_TEXTURE_2D
)
4611 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4612 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
4613 texture_target
= GL_TEXTURE_2D
;
4616 checkGLcall("glEnd and previous");
4618 left
= src_rect
->left
;
4619 right
= src_rect
->right
;
4623 top
= src_surface
->resource
.height
- src_rect
->top
;
4624 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
4628 top
= src_surface
->resource
.height
- src_rect
->bottom
;
4629 bottom
= src_surface
->resource
.height
- src_rect
->top
;
4632 if (src_surface
->flags
& SFLAG_NORMCOORD
)
4634 left
/= src_surface
->pow2Width
;
4635 right
/= src_surface
->pow2Width
;
4636 top
/= src_surface
->pow2Height
;
4637 bottom
/= src_surface
->pow2Height
;
4640 /* draw the source texture stretched and upside down. The correct surface is bound already */
4641 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
4642 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
4644 context_set_draw_buffer(context
, drawBuffer
);
4645 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
4647 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
4649 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
4650 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
4653 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
4654 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
4657 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
4658 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
4661 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
4662 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
4663 gl_info
->gl_ops
.gl
.p_glEnd();
4664 checkGLcall("glEnd and previous");
4666 if (texture_target
!= dst_surface
->texture_target
)
4668 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4669 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
4670 texture_target
= dst_surface
->texture_target
;
4673 /* Now read the stretched and upside down image into the destination texture */
4674 context_bind_texture(context
, texture_target
, dst_surface
->texture_name
);
4675 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
4677 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
4678 0, 0, /* We blitted the image to the origin */
4679 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
4680 checkGLcall("glCopyTexSubImage2D");
4682 if (drawBuffer
== GL_BACK
)
4684 /* Write the back buffer backup back. */
4687 if (texture_target
!= GL_TEXTURE_2D
)
4689 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4690 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
4691 texture_target
= GL_TEXTURE_2D
;
4693 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
4697 if (texture_target
!= src_surface
->texture_target
)
4699 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4700 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
4701 texture_target
= src_surface
->texture_target
;
4703 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->texture_name
);
4706 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
4708 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
4709 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
4712 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
4713 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
4716 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
4717 (float)fbheight
/ (float)src_surface
->pow2Height
);
4718 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
4721 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
4722 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
4723 gl_info
->gl_ops
.gl
.p_glEnd();
4725 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
4726 checkGLcall("glDisable(texture_target)");
4729 if (src
!= src_surface
->texture_name
&& src
!= backup
)
4731 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
4732 checkGLcall("glDeleteTextures(1, &src)");
4736 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
4737 checkGLcall("glDeleteTextures(1, &backup)");
4740 if (wined3d_settings
.strict_draw_ordering
)
4741 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4743 context_release(context
);
4745 /* The texture is now most up to date - If the surface is a render target
4746 * and has a drawable, this path is never entered. */
4747 surface_validate_location(dst_surface
, SFLAG_INTEXTURE
);
4748 surface_invalidate_location(dst_surface
, ~SFLAG_INTEXTURE
);
4751 /* Front buffer coordinates are always full screen coordinates, but our GL
4752 * drawable is limited to the window's client area. The sysmem and texture
4753 * copies do have the full screen size. Note that GL has a bottom-left
4754 * origin, while D3D has a top-left origin. */
4755 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
4757 UINT drawable_height
;
4759 if (surface
->swapchain
&& surface
== surface
->swapchain
->front_buffer
)
4761 POINT offset
= {0, 0};
4764 ScreenToClient(window
, &offset
);
4765 OffsetRect(rect
, offset
.x
, offset
.y
);
4767 GetClientRect(window
, &windowsize
);
4768 drawable_height
= windowsize
.bottom
- windowsize
.top
;
4772 drawable_height
= surface
->resource
.height
;
4775 rect
->top
= drawable_height
- rect
->top
;
4776 rect
->bottom
= drawable_height
- rect
->bottom
;
4779 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
4780 enum wined3d_texture_filter_type filter
, BOOL color_key
,
4781 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
4782 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
4784 const struct wined3d_gl_info
*gl_info
;
4785 struct wined3d_context
*context
;
4786 RECT src_rect
, dst_rect
;
4788 src_rect
= *src_rect_in
;
4789 dst_rect
= *dst_rect_in
;
4791 context
= context_acquire(device
, dst_surface
);
4792 gl_info
= context
->gl_info
;
4794 /* Make sure the surface is up-to-date. This should probably use
4795 * surface_load_location() and worry about the destination surface too,
4796 * unless we're overwriting it completely. */
4797 surface_internal_preload(src_surface
, context
, SRGB_RGB
);
4799 /* Activate the destination context, set it up for blitting */
4800 context_apply_blit_state(context
, device
);
4802 if (!surface_is_offscreen(dst_surface
))
4803 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
4805 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
4809 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
4810 checkGLcall("glEnable(GL_ALPHA_TEST)");
4812 /* When the primary render target uses P8, the alpha component
4813 * contains the palette index. Which means that the colorkey is one of
4814 * the palette entries. In other cases pixels that should be masked
4815 * away have alpha set to 0. */
4816 if (swapchain_is_p8(context
->swapchain
))
4817 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
4818 (float)src_surface
->src_blt_color_key
.color_space_low_value
/ 256.0f
);
4820 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
4821 checkGLcall("glAlphaFunc");
4825 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4826 checkGLcall("glDisable(GL_ALPHA_TEST)");
4829 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
4833 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4834 checkGLcall("glDisable(GL_ALPHA_TEST)");
4837 /* Leave the opengl state valid for blitting */
4838 device
->blitter
->unset_shader(context
->gl_info
);
4840 if (wined3d_settings
.strict_draw_ordering
4841 || (dst_surface
->swapchain
&& dst_surface
->swapchain
->front_buffer
== dst_surface
))
4842 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4844 context_release(context
);
4847 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
4849 struct wined3d_device
*device
= s
->resource
.device
;
4850 const struct blit_shader
*blitter
;
4852 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
4853 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
4856 FIXME("No blitter is capable of performing the requested color fill operation.\n");
4857 return WINED3DERR_INVALIDCALL
;
4860 return blitter
->color_fill(device
, s
, rect
, color
);
4863 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4864 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
4865 enum wined3d_texture_filter_type filter
)
4867 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4868 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4869 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
4871 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
4872 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
4873 flags
, DDBltFx
, debug_d3dtexturefiltertype(filter
));
4875 /* Get the swapchain. One of the surfaces has to be a primary surface */
4876 if (dst_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
4878 WARN("Destination is in sysmem, rejecting gl blt\n");
4879 return WINED3DERR_INVALIDCALL
;
4882 dst_swapchain
= dst_surface
->swapchain
;
4886 if (src_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
4888 WARN("Src is in sysmem, rejecting gl blt\n");
4889 return WINED3DERR_INVALIDCALL
;
4892 src_swapchain
= src_surface
->swapchain
;
4896 src_swapchain
= NULL
;
4899 /* Early sort out of cases where no render target is used */
4900 if (!dst_swapchain
&& !src_swapchain
4901 && src_surface
!= device
->fb
.render_targets
[0]
4902 && dst_surface
!= device
->fb
.render_targets
[0])
4904 TRACE("No surface is render target, not using hardware blit.\n");
4905 return WINED3DERR_INVALIDCALL
;
4908 /* No destination color keying supported */
4909 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
4911 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
4912 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
4913 return WINED3DERR_INVALIDCALL
;
4916 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
4918 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
4919 return WINED3DERR_INVALIDCALL
;
4922 if (dst_swapchain
&& src_swapchain
)
4924 FIXME("Implement hardware blit between two different swapchains\n");
4925 return WINED3DERR_INVALIDCALL
;
4930 /* Handled with regular texture -> swapchain blit */
4931 if (src_surface
== device
->fb
.render_targets
[0])
4932 TRACE("Blit from active render target to a swapchain\n");
4934 else if (src_swapchain
&& dst_surface
== device
->fb
.render_targets
[0])
4936 FIXME("Implement blit from a swapchain to the active render target\n");
4937 return WINED3DERR_INVALIDCALL
;
4940 if ((src_swapchain
|| src_surface
== device
->fb
.render_targets
[0]) && !dst_swapchain
)
4942 /* Blit from render target to texture */
4945 /* P8 read back is not implemented */
4946 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
4947 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
4949 TRACE("P8 read back not supported by frame buffer to texture blit\n");
4950 return WINED3DERR_INVALIDCALL
;
4953 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
4955 TRACE("Color keying not supported by frame buffer to texture blit\n");
4956 return WINED3DERR_INVALIDCALL
;
4957 /* Destination color key is checked above */
4960 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
4965 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
4966 * flip the image nor scale it.
4968 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
4969 * -> If the app wants a image width an unscaled width, copy it line per line
4970 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
4971 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
4972 * back buffer. This is slower than reading line per line, thus not used for flipping
4973 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
4974 * pixel by pixel. */
4975 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
4976 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
4978 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
4979 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4983 TRACE("Using hardware stretching to flip / stretch the texture.\n");
4984 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4987 surface_evict_sysmem(dst_surface
);
4991 else if (src_surface
)
4993 /* Blit from offscreen surface to render target */
4994 struct wined3d_color_key old_blt_key
= src_surface
->src_blt_color_key
;
4995 DWORD oldCKeyFlags
= src_surface
->CKeyFlags
;
4997 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
4999 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5000 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5001 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5003 FIXME("Unsupported blit operation falling back to software\n");
5004 return WINED3DERR_INVALIDCALL
;
5007 /* Color keying: Check if we have to do a color keyed blt,
5008 * and if not check if a color key is activated.
5010 * Just modify the color keying parameters in the surface and restore them afterwards
5011 * The surface keeps track of the color key last used to load the opengl surface.
5012 * PreLoad will catch the change to the flags and color key and reload if necessary.
5014 if (flags
& WINEDDBLT_KEYSRC
)
5016 /* Use color key from surface */
5018 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5020 /* Use color key from DDBltFx */
5021 src_surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
5022 src_surface
->src_blt_color_key
= DDBltFx
->ddckSrcColorkey
;
5026 /* Do not use color key */
5027 src_surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
5030 surface_blt_to_drawable(device
, filter
, flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
),
5031 src_surface
, src_rect
, dst_surface
, dst_rect
);
5033 /* Restore the color key parameters */
5034 src_surface
->CKeyFlags
= oldCKeyFlags
;
5035 src_surface
->src_blt_color_key
= old_blt_key
;
5037 surface_validate_location(dst_surface
, dst_surface
->draw_binding
);
5038 surface_invalidate_location(dst_surface
, ~dst_surface
->draw_binding
);
5043 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5044 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5045 return WINED3DERR_INVALIDCALL
;
5048 /* Context activation is done by the caller. */
5049 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
5050 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
5052 struct wined3d_device
*device
= surface
->resource
.device
;
5053 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
5054 GLint compare_mode
= GL_NONE
;
5055 struct blt_info info
;
5056 GLint old_binding
= 0;
5059 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
5061 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
5062 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
5063 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
5064 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
5065 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
5066 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
5067 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
5068 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
5069 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
5070 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
5071 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
5073 SetRect(&rect
, 0, h
, w
, 0);
5074 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
5075 context_active_texture(context
, context
->gl_info
, 0);
5076 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
5077 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
5078 if (gl_info
->supported
[ARB_SHADOW
])
5080 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
5081 if (compare_mode
!= GL_NONE
)
5082 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
5085 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
5086 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
5088 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
5089 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
5090 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
5091 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
5092 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
5093 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
5094 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
5095 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
5096 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
5097 gl_info
->gl_ops
.gl
.p_glEnd();
5099 if (compare_mode
!= GL_NONE
)
5100 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
5101 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
5103 gl_info
->gl_ops
.gl
.p_glPopAttrib();
5105 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
5108 void surface_modify_ds_location(struct wined3d_surface
*surface
,
5109 DWORD location
, UINT w
, UINT h
)
5111 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
5113 if (location
& ~(SFLAG_LOCATIONS
| SFLAG_DISCARDED
))
5114 FIXME("Invalid location (%#x) specified.\n", location
);
5116 if (((surface
->flags
& SFLAG_INTEXTURE
) && !(location
& SFLAG_INTEXTURE
))
5117 || (!(surface
->flags
& SFLAG_INTEXTURE
) && (location
& SFLAG_INTEXTURE
)))
5119 if (surface
->container
)
5121 TRACE("Passing to container.\n");
5122 wined3d_texture_set_dirty(surface
->container
);
5126 surface
->ds_current_size
.cx
= w
;
5127 surface
->ds_current_size
.cy
= h
;
5128 surface
->flags
&= ~(SFLAG_LOCATIONS
| SFLAG_DISCARDED
);
5129 surface
->flags
|= location
;
5132 /* Context activation is done by the caller. */
5133 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
5135 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
5136 struct wined3d_device
*device
= surface
->resource
.device
;
5139 TRACE("surface %p, new location %#x.\n", surface
, location
);
5141 /* TODO: Make this work for modes other than FBO */
5142 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
5144 if (!(surface
->flags
& location
))
5146 w
= surface
->ds_current_size
.cx
;
5147 h
= surface
->ds_current_size
.cy
;
5148 surface
->ds_current_size
.cx
= 0;
5149 surface
->ds_current_size
.cy
= 0;
5153 w
= surface
->resource
.width
;
5154 h
= surface
->resource
.height
;
5157 if (surface
->ds_current_size
.cx
== surface
->resource
.width
5158 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
5160 TRACE("Location (%#x) is already up to date.\n", location
);
5164 if (surface
->current_renderbuffer
)
5166 FIXME("Not supported with fixed up depth stencil.\n");
5170 if (surface
->flags
& SFLAG_DISCARDED
)
5172 TRACE("Surface was discarded, no need copy data.\n");
5175 case SFLAG_INTEXTURE
:
5176 surface_prepare_texture(surface
, context
, FALSE
);
5178 case SFLAG_INRB_MULTISAMPLE
:
5179 surface_prepare_rb(surface
, gl_info
, TRUE
);
5181 case SFLAG_INDRAWABLE
:
5185 FIXME("Unhandled location %#x\n", location
);
5187 surface
->flags
&= ~SFLAG_DISCARDED
;
5188 surface
->flags
|= location
;
5189 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5190 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5194 if (!(surface
->flags
& SFLAG_LOCATIONS
))
5196 FIXME("No up to date depth stencil location.\n");
5197 surface
->flags
|= location
;
5198 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5199 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5203 if (location
== SFLAG_INTEXTURE
)
5205 GLint old_binding
= 0;
5208 /* The render target is allowed to be smaller than the depth/stencil
5209 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5210 * than the offscreen surface. Don't overwrite the offscreen surface
5211 * with undefined data. */
5212 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
5213 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
5215 TRACE("Copying onscreen depth buffer to depth texture.\n");
5217 if (!device
->depth_blt_texture
)
5218 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
5220 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5221 * directly on the FBO texture. That's because we need to flip. */
5222 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5223 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5224 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
5226 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
5227 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
5231 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
5232 bind_target
= GL_TEXTURE_2D
;
5234 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
5235 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5236 * internal format, because the internal format might include stencil
5237 * data. In principle we should copy stencil data as well, but unless
5238 * the driver supports stencil export it's hard to do, and doesn't
5239 * seem to be needed in practice. If the hardware doesn't support
5240 * writing stencil data, the glCopyTexImage2D() call might trigger
5241 * software fallbacks. */
5242 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
5243 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5244 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5245 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
5246 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
5247 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
5248 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
5249 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
5251 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5252 NULL
, surface
, SFLAG_INTEXTURE
);
5253 context_set_draw_buffer(context
, GL_NONE
);
5255 /* Do the actual blit */
5256 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
5257 checkGLcall("depth_blt");
5259 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5261 if (wined3d_settings
.strict_draw_ordering
)
5262 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
5264 else if (location
== SFLAG_INDRAWABLE
)
5266 TRACE("Copying depth texture to onscreen depth buffer.\n");
5268 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5269 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5270 surface_depth_blt(surface
, context
, surface
->texture_name
,
5271 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
5272 checkGLcall("depth_blt");
5274 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5276 if (wined3d_settings
.strict_draw_ordering
)
5277 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
5281 ERR("Invalid location (%#x) specified.\n", location
);
5284 surface
->flags
|= location
;
5285 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5286 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5289 void surface_validate_location(struct wined3d_surface
*surface
, DWORD location
)
5291 struct wined3d_surface
*overlay
;
5293 TRACE("surface %p, location %s.\n", surface
, debug_surflocation(location
& SFLAG_LOCATIONS
));
5295 surface
->flags
|= (location
& SFLAG_LOCATIONS
);
5297 /* Redraw emulated overlays, if any. */
5298 if (location
& SFLAG_INDRAWABLE
&& !list_empty(&surface
->overlays
))
5300 LIST_FOR_EACH_ENTRY(overlay
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
5302 surface_draw_overlay(overlay
);
5307 void surface_invalidate_location(struct wined3d_surface
*surface
, DWORD location
)
5309 TRACE("surface %p, location %s.\n", surface
, debug_surflocation(location
& SFLAG_LOCATIONS
));
5311 if ((location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)) && surface
->container
)
5312 wined3d_texture_set_dirty(surface
->container
);
5313 surface
->flags
&= ~(location
& SFLAG_LOCATIONS
);
5315 if (!(surface
->flags
& SFLAG_LOCATIONS
))
5316 ERR("Surface %p does not have any up to date location.\n", surface
);
5319 static DWORD
resource_access_from_location(DWORD location
)
5323 case SFLAG_INSYSMEM
:
5324 return WINED3D_RESOURCE_ACCESS_CPU
;
5326 case SFLAG_INDRAWABLE
:
5327 case SFLAG_INSRGBTEX
:
5328 case SFLAG_INTEXTURE
:
5329 case SFLAG_INRB_MULTISAMPLE
:
5330 case SFLAG_INRB_RESOLVED
:
5331 return WINED3D_RESOURCE_ACCESS_GPU
;
5334 FIXME("Unhandled location %#x.\n", location
);
5339 static void surface_load_sysmem(struct wined3d_surface
*surface
,
5340 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5342 surface_prepare_system_memory(surface
);
5344 if (surface
->flags
& (SFLAG_INRB_MULTISAMPLE
| SFLAG_INRB_RESOLVED
))
5345 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
5347 /* Download the surface to system memory. */
5348 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
))
5350 struct wined3d_device
*device
= surface
->resource
.device
;
5351 struct wined3d_context
*context
;
5353 /* TODO: Use already acquired context when possible. */
5354 context
= context_acquire(device
, NULL
);
5356 surface_bind_and_dirtify(surface
, context
, !(surface
->flags
& SFLAG_INTEXTURE
));
5357 surface_download_data(surface
, gl_info
);
5359 context_release(context
);
5364 if (surface
->flags
& SFLAG_INDRAWABLE
)
5366 read_from_framebuffer(surface
, rect
, surface
->resource
.allocatedMemory
,
5367 wined3d_surface_get_pitch(surface
));
5371 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
5372 surface
, surface
->flags
& SFLAG_LOCATIONS
);
5375 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
5376 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5380 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
))
5382 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5383 return WINED3DERR_INVALIDCALL
;
5386 surface_get_rect(surface
, rect
, &r
);
5387 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
5388 surface_blt_to_drawable(surface
->resource
.device
,
5389 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
5394 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
5395 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
, BOOL srgb
)
5397 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5398 struct wined3d_device
*device
= surface
->resource
.device
;
5399 enum wined3d_conversion_type convert
;
5400 struct wined3d_context
*context
;
5401 UINT width
, src_pitch
, dst_pitch
;
5402 struct wined3d_bo_address data
;
5403 struct wined3d_format format
;
5404 POINT dst_point
= {0, 0};
5407 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
5408 && surface_is_offscreen(surface
)
5409 && (surface
->flags
& SFLAG_INDRAWABLE
))
5411 surface_load_fb_texture(surface
, srgb
);
5416 if (surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INTEXTURE
)
5417 && (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
5418 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5419 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
5420 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
5423 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, SFLAG_INTEXTURE
,
5424 &src_rect
, surface
, SFLAG_INSRGBTEX
, &src_rect
);
5426 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, SFLAG_INSRGBTEX
,
5427 &src_rect
, surface
, SFLAG_INTEXTURE
, &src_rect
);
5432 if (surface
->flags
& (SFLAG_INRB_MULTISAMPLE
| SFLAG_INRB_RESOLVED
)
5433 && (!srgb
|| (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
5434 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5435 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
5436 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
5438 DWORD src_location
= surface
->flags
& SFLAG_INRB_RESOLVED
? SFLAG_INRB_RESOLVED
: SFLAG_INRB_MULTISAMPLE
;
5439 DWORD dst_location
= srgb
? SFLAG_INSRGBTEX
: SFLAG_INTEXTURE
;
5440 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5442 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, src_location
,
5443 &rect
, surface
, dst_location
, &rect
);
5448 /* Upload from system memory */
5450 d3dfmt_get_conv(surface
, TRUE
/* We need color keying */,
5451 TRUE
/* We will use textures */, &format
, &convert
);
5455 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSYSMEM
)) == SFLAG_INTEXTURE
)
5457 /* Performance warning... */
5458 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
5459 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5464 if ((surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INSYSMEM
)) == SFLAG_INSRGBTEX
)
5466 /* Performance warning... */
5467 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
5468 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5472 if (!(surface
->flags
& SFLAG_INSYSMEM
))
5474 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
5475 /* Lets hope we get it from somewhere... */
5476 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5479 /* TODO: Use already acquired context when possible. */
5480 context
= context_acquire(device
, NULL
);
5482 surface_prepare_texture(surface
, context
, srgb
);
5483 surface_bind_and_dirtify(surface
, context
, srgb
);
5485 if (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
5487 surface
->flags
|= SFLAG_GLCKEY
;
5488 surface
->gl_color_key
= surface
->src_blt_color_key
;
5490 else surface
->flags
&= ~SFLAG_GLCKEY
;
5492 width
= surface
->resource
.width
;
5493 src_pitch
= wined3d_surface_get_pitch(surface
);
5495 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
5496 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
5498 if ((convert
!= WINED3D_CT_NONE
|| format
.convert
) && (surface
->flags
& SFLAG_PBO
))
5500 TRACE("Removing the pbo attached to surface %p.\n", surface
);
5501 surface_remove_pbo(surface
, gl_info
);
5506 /* This code is entered for texture formats which need a fixup. */
5507 UINT height
= surface
->resource
.height
;
5509 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
5510 dst_pitch
= width
* format
.conv_byte_count
;
5511 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
5513 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
5515 ERR("Out of memory (%u).\n", dst_pitch
* height
);
5516 context_release(context
);
5517 return E_OUTOFMEMORY
;
5519 format
.convert(surface
->resource
.allocatedMemory
, mem
, src_pitch
, src_pitch
* height
,
5520 dst_pitch
, dst_pitch
* height
, width
, height
, 1);
5521 format
.byte_count
= format
.conv_byte_count
;
5522 src_pitch
= dst_pitch
;
5524 else if (convert
!= WINED3D_CT_NONE
&& surface
->resource
.allocatedMemory
)
5526 /* This code is only entered for color keying fixups */
5527 UINT height
= surface
->resource
.height
;
5529 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
5530 dst_pitch
= width
* format
.conv_byte_count
;
5531 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
5533 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
5535 ERR("Out of memory (%u).\n", dst_pitch
* height
);
5536 context_release(context
);
5537 return E_OUTOFMEMORY
;
5539 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
, src_pitch
,
5540 width
, height
, dst_pitch
, convert
, surface
);
5541 format
.byte_count
= format
.conv_byte_count
;
5542 src_pitch
= dst_pitch
;
5546 mem
= surface
->resource
.allocatedMemory
;
5549 data
.buffer_object
= surface
->pbo
;
5551 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, src_pitch
, &dst_point
, srgb
, &data
);
5553 context_release(context
);
5555 /* Don't delete PBO memory. */
5556 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
5557 HeapFree(GetProcessHeap(), 0, mem
);
5562 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
5564 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5566 if (!(surface
->flags
& SFLAG_INRB_MULTISAMPLE
))
5567 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface
);
5569 surface_blt_fbo(surface
->resource
.device
, WINED3D_TEXF_POINT
,
5570 surface
, SFLAG_INRB_MULTISAMPLE
, &rect
, surface
, SFLAG_INRB_RESOLVED
, &rect
);
5573 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
, const RECT
*rect
)
5575 struct wined3d_device
*device
= surface
->resource
.device
;
5576 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5579 TRACE("surface %p, location %s, rect %s.\n", surface
, debug_surflocation(location
), wine_dbgstr_rect(rect
));
5581 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
5583 if (location
== SFLAG_INTEXTURE
&& surface
->flags
& SFLAG_INDRAWABLE
)
5585 struct wined3d_context
*context
= context_acquire(device
, NULL
);
5586 surface_load_ds_location(surface
, context
, location
);
5587 context_release(context
);
5590 else if (location
& surface
->flags
&& surface
->draw_binding
!= SFLAG_INDRAWABLE
)
5592 /* Already up to date, nothing to do. */
5597 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
5598 debug_surflocation(surface
->flags
& SFLAG_LOCATIONS
), debug_surflocation(location
));
5599 return WINED3DERR_INVALIDCALL
;
5603 if (surface
->flags
& location
)
5605 TRACE("Location already up to date.\n");
5607 if (location
== SFLAG_INSYSMEM
&& !(surface
->flags
& SFLAG_PBO
)
5608 && surface_need_pbo(surface
, gl_info
))
5609 surface_load_pbo(surface
, gl_info
);
5614 if (WARN_ON(d3d_surface
))
5616 DWORD required_access
= resource_access_from_location(location
);
5617 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
5618 WARN("Operation requires %#x access, but surface only has %#x.\n",
5619 required_access
, surface
->resource
.access_flags
);
5622 if (!(surface
->flags
& SFLAG_LOCATIONS
))
5624 ERR("Surface %p does not have any up to date location.\n", surface
);
5625 surface
->flags
|= SFLAG_LOST
;
5626 return WINED3DERR_DEVICELOST
;
5631 case SFLAG_INSYSMEM
:
5632 surface_load_sysmem(surface
, gl_info
, rect
);
5635 case SFLAG_INDRAWABLE
:
5636 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
, rect
)))
5640 case SFLAG_INRB_RESOLVED
:
5641 surface_multisample_resolve(surface
);
5644 case SFLAG_INTEXTURE
:
5645 case SFLAG_INSRGBTEX
:
5646 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, rect
, location
== SFLAG_INSRGBTEX
)))
5651 ERR("Don't know how to handle location %#x.\n", location
);
5657 surface
->flags
|= location
;
5659 if (location
!= SFLAG_INSYSMEM
&& (surface
->flags
& SFLAG_INSYSMEM
))
5660 surface_evict_sysmem(surface
);
5666 BOOL
surface_is_offscreen(const struct wined3d_surface
*surface
)
5668 struct wined3d_swapchain
*swapchain
;
5670 /* Not on a swapchain - must be offscreen */
5671 if (!(swapchain
= surface
->swapchain
))
5674 /* The front buffer is always onscreen */
5675 if (surface
== swapchain
->front_buffer
) return FALSE
;
5677 /* If the swapchain is rendered to an FBO, the backbuffer is
5678 * offscreen, otherwise onscreen */
5679 return swapchain
->render_to_fbo
;
5682 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
5683 /* Context activation is done by the caller. */
5684 static void ffp_blit_free(struct wined3d_device
*device
) { }
5686 /* Context activation is done by the caller. */
5687 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
5689 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
5692 if (surface
->container
)
5693 target
= surface
->container
->target
;
5695 target
= surface
->texture_target
;
5697 gl_info
->gl_ops
.gl
.p_glEnable(target
);
5698 checkGLcall("glEnable(target)");
5703 /* Context activation is done by the caller. */
5704 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
5706 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
5707 checkGLcall("glDisable(GL_TEXTURE_2D)");
5708 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
5710 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
5711 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
5713 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
5715 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
5716 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
5720 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
5721 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
5722 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
5726 case WINED3D_BLIT_OP_COLOR_BLIT
:
5727 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
5730 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
5732 TRACE("Checking support for fixup:\n");
5733 dump_color_fixup_desc(src_format
->color_fixup
);
5736 /* We only support identity conversions. */
5737 if (!is_identity_fixup(src_format
->color_fixup
)
5738 || !is_identity_fixup(dst_format
->color_fixup
))
5740 TRACE("Fixups are not supported.\n");
5746 case WINED3D_BLIT_OP_COLOR_FILL
:
5747 if (dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
5750 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
5752 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
5755 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
5757 TRACE("Color fill not supported\n");
5761 /* FIXME: We should reject color fills on formats with fixups,
5762 * but this would break P8 color fills for example. */
5766 case WINED3D_BLIT_OP_DEPTH_FILL
:
5770 TRACE("Unsupported blit_op=%d\n", blit_op
);
5775 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
5776 const RECT
*dst_rect
, const struct wined3d_color
*color
)
5778 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
5779 struct wined3d_fb_state fb
= {&dst_surface
, NULL
};
5781 device_clear_render_targets(device
, 1, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
5786 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
5787 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
5789 const RECT draw_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5790 struct wined3d_fb_state fb
= {NULL
, surface
};
5792 device_clear_render_targets(device
, 0, &fb
, 1, rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
5797 const struct blit_shader ffp_blit
= {
5803 ffp_blit_color_fill
,
5804 ffp_blit_depth_fill
,
5807 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
5812 /* Context activation is done by the caller. */
5813 static void cpu_blit_free(struct wined3d_device
*device
)
5817 /* Context activation is done by the caller. */
5818 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
5823 /* Context activation is done by the caller. */
5824 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
5828 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
5829 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
5830 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
5832 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
5840 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
5841 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
5842 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
5844 UINT row_block_count
;
5845 const BYTE
*src_row
;
5852 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
5856 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5858 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
5859 src_row
+= src_pitch
;
5860 dst_row
+= dst_pitch
;
5866 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
5868 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
5872 case WINED3DFMT_DXT1
:
5873 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5878 BYTE control_row
[4];
5881 const struct block
*s
= (const struct block
*)src_row
;
5882 struct block
*d
= (struct block
*)dst_row
;
5884 for (x
= 0; x
< row_block_count
; ++x
)
5886 d
[x
].color
[0] = s
[x
].color
[0];
5887 d
[x
].color
[1] = s
[x
].color
[1];
5888 d
[x
].control_row
[0] = s
[x
].control_row
[3];
5889 d
[x
].control_row
[1] = s
[x
].control_row
[2];
5890 d
[x
].control_row
[2] = s
[x
].control_row
[1];
5891 d
[x
].control_row
[3] = s
[x
].control_row
[0];
5893 src_row
-= src_pitch
;
5894 dst_row
+= dst_pitch
;
5898 case WINED3DFMT_DXT3
:
5899 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5905 BYTE control_row
[4];
5908 const struct block
*s
= (const struct block
*)src_row
;
5909 struct block
*d
= (struct block
*)dst_row
;
5911 for (x
= 0; x
< row_block_count
; ++x
)
5913 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
5914 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
5915 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
5916 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
5917 d
[x
].color
[0] = s
[x
].color
[0];
5918 d
[x
].color
[1] = s
[x
].color
[1];
5919 d
[x
].control_row
[0] = s
[x
].control_row
[3];
5920 d
[x
].control_row
[1] = s
[x
].control_row
[2];
5921 d
[x
].control_row
[2] = s
[x
].control_row
[1];
5922 d
[x
].control_row
[3] = s
[x
].control_row
[0];
5924 src_row
-= src_pitch
;
5925 dst_row
+= dst_pitch
;
5930 FIXME("Compressed flip not implemented for format %s.\n",
5931 debug_d3dformat(format
->id
));
5936 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
5937 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
5942 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5943 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
5944 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5946 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
5947 const struct wined3d_format
*src_format
, *dst_format
;
5948 struct wined3d_surface
*orig_src
= src_surface
;
5949 struct wined3d_map_desc dst_map
, src_map
;
5950 const BYTE
*sbase
= NULL
;
5951 HRESULT hr
= WINED3D_OK
;
5956 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5957 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5958 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5960 if (src_surface
== dst_surface
)
5962 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
5964 src_format
= dst_surface
->resource
.format
;
5965 dst_format
= src_format
;
5969 dst_format
= dst_surface
->resource
.format
;
5972 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
5974 src_surface
= surface_convert_format(src_surface
, dst_format
->id
);
5977 /* The conv function writes a FIXME */
5978 WARN("Cannot convert source surface format to dest format.\n");
5982 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
5983 src_format
= src_surface
->resource
.format
;
5987 src_format
= dst_format
;
5990 wined3d_surface_map(dst_surface
, &dst_map
, dst_rect
, 0);
5993 bpp
= dst_surface
->resource
.format
->byte_count
;
5994 srcheight
= src_rect
->bottom
- src_rect
->top
;
5995 srcwidth
= src_rect
->right
- src_rect
->left
;
5996 dstheight
= dst_rect
->bottom
- dst_rect
->top
;
5997 dstwidth
= dst_rect
->right
- dst_rect
->left
;
5998 width
= (dst_rect
->right
- dst_rect
->left
) * bpp
;
6001 sbase
= (BYTE
*)src_map
.data
6002 + ((src_rect
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
6003 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
6004 if (src_surface
!= dst_surface
)
6005 dbuf
= dst_map
.data
;
6007 dbuf
= (BYTE
*)dst_map
.data
6008 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
6009 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
6011 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
6013 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
6015 if (src_surface
== dst_surface
)
6017 FIXME("Only plain blits supported on compressed surfaces.\n");
6022 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
6024 WARN("Stretching not supported on compressed surfaces.\n");
6025 hr
= WINED3DERR_INVALIDCALL
;
6029 if (!surface_check_block_align(src_surface
, src_rect
))
6031 WARN("Source rectangle not block-aligned.\n");
6032 hr
= WINED3DERR_INVALIDCALL
;
6036 if (!surface_check_block_align(dst_surface
, dst_rect
))
6038 WARN("Destination rectangle not block-aligned.\n");
6039 hr
= WINED3DERR_INVALIDCALL
;
6043 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
6044 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
6045 src_format
, flags
, fx
);
6049 /* First, all the 'source-less' blits */
6050 if (flags
& WINEDDBLT_COLORFILL
)
6052 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->u5
.dwFillColor
);
6053 flags
&= ~WINEDDBLT_COLORFILL
;
6056 if (flags
& WINEDDBLT_DEPTHFILL
)
6058 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6060 if (flags
& WINEDDBLT_ROP
)
6062 /* Catch some degenerate cases here. */
6066 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, 0);
6068 case 0xaa0029: /* No-op */
6071 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, ~0U);
6073 case SRCCOPY
: /* Well, we do that below? */
6076 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
6079 flags
&= ~WINEDDBLT_ROP
;
6081 if (flags
& WINEDDBLT_DDROPS
)
6083 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
6085 /* Now the 'with source' blits. */
6088 int sx
, xinc
, sy
, yinc
;
6090 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
6093 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
6094 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
6096 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6097 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
6100 xinc
= (srcwidth
<< 16) / dstwidth
;
6101 yinc
= (srcheight
<< 16) / dstheight
;
6105 /* No effects, we can cheat here. */
6106 if (dstwidth
== srcwidth
)
6108 if (dstheight
== srcheight
)
6110 /* No stretching in either direction. This needs to be as
6111 * fast as possible. */
6114 /* Check for overlapping surfaces. */
6115 if (src_surface
!= dst_surface
|| dst_rect
->top
< src_rect
->top
6116 || dst_rect
->right
<= src_rect
->left
|| src_rect
->right
<= dst_rect
->left
)
6118 /* No overlap, or dst above src, so copy from top downwards. */
6119 for (y
= 0; y
< dstheight
; ++y
)
6121 memcpy(dbuf
, sbuf
, width
);
6122 sbuf
+= src_map
.row_pitch
;
6123 dbuf
+= dst_map
.row_pitch
;
6126 else if (dst_rect
->top
> src_rect
->top
)
6128 /* Copy from bottom upwards. */
6129 sbuf
+= src_map
.row_pitch
* dstheight
;
6130 dbuf
+= dst_map
.row_pitch
* dstheight
;
6131 for (y
= 0; y
< dstheight
; ++y
)
6133 sbuf
-= src_map
.row_pitch
;
6134 dbuf
-= dst_map
.row_pitch
;
6135 memcpy(dbuf
, sbuf
, width
);
6140 /* Src and dst overlapping on the same line, use memmove. */
6141 for (y
= 0; y
< dstheight
; ++y
)
6143 memmove(dbuf
, sbuf
, width
);
6144 sbuf
+= src_map
.row_pitch
;
6145 dbuf
+= dst_map
.row_pitch
;
6151 /* Stretching in y direction only. */
6152 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6154 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
6155 memcpy(dbuf
, sbuf
, width
);
6156 dbuf
+= dst_map
.row_pitch
;
6162 /* Stretching in X direction. */
6164 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6166 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
6168 if ((sy
>> 16) == (last_sy
>> 16))
6170 /* This source row is the same as last source row -
6171 * Copy the already stretched row. */
6172 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
6176 #define STRETCH_ROW(type) \
6178 const type *s = (const type *)sbuf; \
6179 type *d = (type *)dbuf; \
6180 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6181 d[x] = s[sx >> 16]; \
6199 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
6203 s
= sbuf
+ 3 * (sx
>> 16);
6204 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
6205 d
[0] = (pixel
) & 0xff;
6206 d
[1] = (pixel
>> 8) & 0xff;
6207 d
[2] = (pixel
>> 16) & 0xff;
6213 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
6214 hr
= WINED3DERR_NOTAVAILABLE
;
6219 dbuf
+= dst_map
.row_pitch
;
6226 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
6227 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
6228 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
6229 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
6231 /* The color keying flags are checked for correctness in ddraw */
6232 if (flags
& WINEDDBLT_KEYSRC
)
6234 keylow
= src_surface
->src_blt_color_key
.color_space_low_value
;
6235 keyhigh
= src_surface
->src_blt_color_key
.color_space_high_value
;
6237 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
6239 keylow
= fx
->ddckSrcColorkey
.color_space_low_value
;
6240 keyhigh
= fx
->ddckSrcColorkey
.color_space_high_value
;
6243 if (flags
& WINEDDBLT_KEYDEST
)
6245 /* Destination color keys are taken from the source surface! */
6246 destkeylow
= src_surface
->dst_blt_color_key
.color_space_low_value
;
6247 destkeyhigh
= src_surface
->dst_blt_color_key
.color_space_high_value
;
6249 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
6251 destkeylow
= fx
->ddckDestColorkey
.color_space_low_value
;
6252 destkeyhigh
= fx
->ddckDestColorkey
.color_space_high_value
;
6262 get_color_masks(src_format
, masks
);
6267 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
6270 if (flags
& WINEDDBLT_DDFX
)
6272 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
6275 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
6276 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
6277 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
6279 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
6281 /* I don't think we need to do anything about this flag */
6282 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6284 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
6287 dTopRight
= dTopLeft
;
6290 dBottomRight
= dBottomLeft
;
6292 dstxinc
= dstxinc
* -1;
6294 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
6297 dTopLeft
= dBottomLeft
;
6300 dTopRight
= dBottomRight
;
6302 dstyinc
= dstyinc
* -1;
6304 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
6306 /* I don't think we need to do anything about this flag */
6307 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
6309 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
6312 dBottomRight
= dTopLeft
;
6315 dBottomLeft
= dTopRight
;
6317 dstxinc
= dstxinc
* -1;
6318 dstyinc
= dstyinc
* -1;
6320 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
6323 dTopLeft
= dBottomLeft
;
6324 dBottomLeft
= dBottomRight
;
6325 dBottomRight
= dTopRight
;
6330 dstxinc
= dstxinc
* -1;
6332 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
6335 dTopLeft
= dTopRight
;
6336 dTopRight
= dBottomRight
;
6337 dBottomRight
= dBottomLeft
;
6342 dstyinc
= dstyinc
* -1;
6344 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
6346 /* I don't think we need to do anything about this flag */
6347 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
6350 flags
&= ~(WINEDDBLT_DDFX
);
6353 #define COPY_COLORKEY_FX(type) \
6356 type *d = (type *)dbuf, *dx, tmp; \
6357 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
6359 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
6361 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6363 tmp = s[sx >> 16]; \
6364 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
6365 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
6369 dx = (type *)(((BYTE *)dx) + dstxinc); \
6371 d = (type *)(((BYTE *)d) + dstyinc); \
6378 COPY_COLORKEY_FX(BYTE
);
6381 COPY_COLORKEY_FX(WORD
);
6384 COPY_COLORKEY_FX(DWORD
);
6389 BYTE
*d
= dbuf
, *dx
;
6390 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6392 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
6394 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
6396 DWORD pixel
, dpixel
= 0;
6397 s
= sbuf
+ 3 * (sx
>>16);
6398 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
6399 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
6400 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
6401 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
6403 dx
[0] = (pixel
) & 0xff;
6404 dx
[1] = (pixel
>> 8) & 0xff;
6405 dx
[2] = (pixel
>> 16) & 0xff;
6414 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
6415 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
6416 hr
= WINED3DERR_NOTAVAILABLE
;
6418 #undef COPY_COLORKEY_FX
6424 if (flags
&& FIXME_ON(d3d_surface
))
6426 FIXME("\tUnsupported flags: %#x.\n", flags
);
6430 wined3d_surface_unmap(dst_surface
);
6431 if (src_surface
&& src_surface
!= dst_surface
)
6432 wined3d_surface_unmap(src_surface
);
6433 /* Release the converted surface, if any. */
6434 if (src_surface
&& src_surface
!= orig_src
)
6435 wined3d_surface_decref(src_surface
);
6440 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
6441 const RECT
*dst_rect
, const struct wined3d_color
*color
)
6443 static const RECT src_rect
;
6446 memset(&BltFx
, 0, sizeof(BltFx
));
6447 BltFx
.dwSize
= sizeof(BltFx
);
6448 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
6449 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
6450 WINEDDBLT_COLORFILL
, &BltFx
, WINED3D_TEXF_POINT
);
6453 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
6454 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
6456 FIXME("Depth filling not implemented by cpu_blit.\n");
6457 return WINED3DERR_INVALIDCALL
;
6460 const struct blit_shader cpu_blit
= {
6466 cpu_blit_color_fill
,
6467 cpu_blit_depth_fill
,
6470 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
6471 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
6472 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
6474 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
6475 struct wined3d_device
*device
= dst_surface
->resource
.device
;
6476 DWORD src_ds_flags
, dst_ds_flags
;
6477 RECT src_rect
, dst_rect
;
6478 BOOL scale
, convert
;
6480 static const DWORD simple_blit
= WINEDDBLT_ASYNC
6481 | WINEDDBLT_COLORFILL
6483 | WINEDDBLT_DEPTHFILL
6484 | WINEDDBLT_DONOTWAIT
;
6486 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6487 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
6488 flags
, fx
, debug_d3dtexturefiltertype(filter
));
6489 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
6493 TRACE("dwSize %#x.\n", fx
->dwSize
);
6494 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
6495 TRACE("dwROP %#x.\n", fx
->dwROP
);
6496 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
6497 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
6498 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
6499 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
6500 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
6501 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
6502 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
6503 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
6504 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
6505 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
6506 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
6507 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
6508 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
6509 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
6510 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
6511 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
6512 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
6513 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
6514 TRACE("ddckDestColorkey {%#x, %#x}.\n",
6515 fx
->ddckDestColorkey
.color_space_low_value
,
6516 fx
->ddckDestColorkey
.color_space_high_value
);
6517 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
6518 fx
->ddckSrcColorkey
.color_space_low_value
,
6519 fx
->ddckSrcColorkey
.color_space_high_value
);
6522 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
6524 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
6525 return WINEDDERR_SURFACEBUSY
;
6528 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
6530 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
6531 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
6532 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
6533 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
6534 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
6536 WARN("The application gave us a bad destination rectangle.\n");
6537 return WINEDDERR_INVALIDRECT
;
6542 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
6544 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
6545 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
6546 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
6547 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
6548 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
6550 WARN("Application gave us bad source rectangle for Blt.\n");
6551 return WINEDDERR_INVALIDRECT
;
6556 memset(&src_rect
, 0, sizeof(src_rect
));
6559 if (!fx
|| !(fx
->dwDDFX
))
6560 flags
&= ~WINEDDBLT_DDFX
;
6562 if (flags
& WINEDDBLT_WAIT
)
6563 flags
&= ~WINEDDBLT_WAIT
;
6565 if (flags
& WINEDDBLT_ASYNC
)
6567 static unsigned int once
;
6570 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
6571 flags
&= ~WINEDDBLT_ASYNC
;
6574 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
6575 if (flags
& WINEDDBLT_DONOTWAIT
)
6577 static unsigned int once
;
6580 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
6581 flags
&= ~WINEDDBLT_DONOTWAIT
;
6584 if (!device
->d3d_initialized
)
6586 WARN("D3D not initialized, using fallback.\n");
6590 /* We want to avoid invalidating the sysmem location for converted
6591 * surfaces, since otherwise we'd have to convert the data back when
6593 if (dst_surface
->flags
& SFLAG_CONVERTED
)
6595 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
6599 if (flags
& ~simple_blit
)
6601 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
6606 src_swapchain
= src_surface
->swapchain
;
6608 src_swapchain
= NULL
;
6610 dst_swapchain
= dst_surface
->swapchain
;
6612 /* This isn't strictly needed. FBO blits for example could deal with
6613 * cross-swapchain blits by first downloading the source to a texture
6614 * before switching to the destination context. We just have this here to
6615 * not have to deal with the issue, since cross-swapchain blits should be
6617 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
6619 FIXME("Using fallback for cross-swapchain blit.\n");
6624 && (src_rect
.right
- src_rect
.left
!= dst_rect
.right
- dst_rect
.left
6625 || src_rect
.bottom
- src_rect
.top
!= dst_rect
.bottom
- dst_rect
.top
);
6626 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
6628 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
6630 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
6634 if (src_ds_flags
|| dst_ds_flags
)
6636 if (flags
& WINEDDBLT_DEPTHFILL
)
6640 TRACE("Depth fill.\n");
6642 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
6643 return WINED3DERR_INVALIDCALL
;
6645 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
6650 if (src_ds_flags
!= dst_ds_flags
)
6652 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
6653 return WINED3DERR_INVALIDCALL
;
6656 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->draw_binding
, &src_rect
,
6657 dst_surface
, dst_surface
->draw_binding
, &dst_rect
)))
6663 /* In principle this would apply to depth blits as well, but we don't
6664 * implement those in the CPU blitter at the moment. */
6665 if ((dst_surface
->flags
& SFLAG_INSYSMEM
)
6666 && (!src_surface
|| (src_surface
->flags
& SFLAG_INSYSMEM
)))
6669 TRACE("Not doing sysmem blit because of scaling.\n");
6671 TRACE("Not doing sysmem blit because of format conversion.\n");
6676 if (flags
& WINEDDBLT_COLORFILL
)
6678 struct wined3d_color color
;
6680 TRACE("Color fill.\n");
6682 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
6685 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
6690 TRACE("Color blit.\n");
6693 if ((src_surface
->flags
& SFLAG_INSYSMEM
) && !(dst_surface
->flags
& SFLAG_INSYSMEM
))
6696 TRACE("Not doing upload because of scaling.\n");
6698 TRACE("Not doing upload because of format conversion.\n");
6701 POINT dst_point
= {dst_rect
.left
, dst_rect
.top
};
6703 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, &src_rect
)))
6705 if (!surface_is_offscreen(dst_surface
))
6706 surface_load_location(dst_surface
, dst_surface
->draw_binding
, NULL
);
6712 /* Use present for back -> front blits. The idea behind this is
6713 * that present is potentially faster than a blit, in particular
6714 * when FBO blits aren't available. Some ddraw applications like
6715 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
6716 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
6717 * applications can't blit directly to the frontbuffer. */
6718 if (dst_swapchain
&& dst_swapchain
->back_buffers
6719 && dst_surface
== dst_swapchain
->front_buffer
6720 && src_surface
== dst_swapchain
->back_buffers
[0])
6722 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
6724 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
6726 /* Set the swap effect to COPY, we don't want the backbuffer
6727 * to become undefined. */
6728 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
6729 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
6730 dst_swapchain
->desc
.swap_effect
= swap_effect
;
6735 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
6736 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
6737 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
6739 TRACE("Using FBO blit.\n");
6741 surface_blt_fbo(device
, filter
,
6742 src_surface
, src_surface
->draw_binding
, &src_rect
,
6743 dst_surface
, dst_surface
->draw_binding
, &dst_rect
);
6744 surface_validate_location(dst_surface
, dst_surface
->draw_binding
);
6745 surface_invalidate_location(dst_surface
, ~dst_surface
->draw_binding
);
6750 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
6751 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
6752 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
6754 TRACE("Using arbfp blit.\n");
6756 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
6763 /* Special cases for render targets. */
6764 if (SUCCEEDED(surface_blt_special(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
)))
6769 /* For the rest call the X11 surface implementation. For render targets
6770 * this should be implemented OpenGL accelerated in surface_blt_special(),
6771 * other blits are rather rare. */
6772 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
6775 static HRESULT
surface_init(struct wined3d_surface
*surface
, UINT alignment
, UINT width
, UINT height
,
6776 enum wined3d_multisample_type multisample_type
, UINT multisample_quality
,
6777 struct wined3d_device
*device
, DWORD usage
, enum wined3d_format_id format_id
,
6778 enum wined3d_pool pool
, DWORD flags
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
6780 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6781 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
6782 BOOL lockable
= flags
& WINED3D_SURFACE_MAPPABLE
;
6783 unsigned int resource_size
;
6786 if (multisample_quality
> 0)
6788 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
6789 multisample_quality
= 0;
6792 /* Quick lockable sanity check.
6793 * TODO: remove this after surfaces, usage and lockability have been debugged properly
6794 * this function is too deep to need to care about things like this.
6795 * Levels need to be checked too, since they all affect what can be done. */
6798 case WINED3D_POOL_SCRATCH
:
6801 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
6802 "which are mutually exclusive, setting lockable to TRUE.\n");
6807 case WINED3D_POOL_SYSTEM_MEM
:
6809 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
6812 case WINED3D_POOL_MANAGED
:
6813 if (usage
& WINED3DUSAGE_DYNAMIC
)
6814 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
6817 case WINED3D_POOL_DEFAULT
:
6818 if (lockable
&& !(usage
& (WINED3DUSAGE_DYNAMIC
| WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
6819 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
6823 FIXME("Unknown pool %#x.\n", pool
);
6827 if (usage
& WINED3DUSAGE_RENDERTARGET
&& pool
!= WINED3D_POOL_DEFAULT
)
6828 FIXME("Trying to create a render target that isn't in the default pool.\n");
6830 /* FIXME: Check that the format is supported by the device. */
6832 resource_size
= wined3d_format_calculate_size(format
, alignment
, width
, height
, 1);
6834 return WINED3DERR_INVALIDCALL
;
6836 if (device
->wined3d
->flags
& WINED3D_NO3D
)
6837 surface
->surface_ops
= &gdi_surface_ops
;
6839 surface
->surface_ops
= &surface_ops
;
6841 hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
, format
,
6842 multisample_type
, multisample_quality
, usage
, pool
, width
, height
, 1,
6843 resource_size
, parent
, parent_ops
, &surface_resource_ops
);
6846 WARN("Failed to initialize resource, returning %#x.\n", hr
);
6850 /* "Standalone" surface. */
6851 surface_set_container(surface
, NULL
);
6853 list_init(&surface
->overlays
);
6856 surface
->flags
= SFLAG_NORMCOORD
; /* Default to normalized coords. */
6857 if (flags
& WINED3D_SURFACE_DISCARD
)
6858 surface
->flags
|= SFLAG_DISCARD
;
6859 if (flags
& WINED3D_SURFACE_PIN_SYSMEM
)
6860 surface
->flags
|= SFLAG_PIN_SYSMEM
;
6861 if (lockable
|| format_id
== WINED3DFMT_D16_LOCKABLE
)
6862 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
6864 /* I'm not sure if this qualifies as a hack or as an optimization. It
6865 * seems reasonable to assume that lockable render targets will get
6866 * locked, so we might as well set SFLAG_DYNLOCK right at surface
6867 * creation. However, the other reason we want to do this is that several
6868 * ddraw applications access surface memory while the surface isn't
6869 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
6870 * future locks prevents these from crashing. */
6871 if (lockable
&& (usage
& WINED3DUSAGE_RENDERTARGET
))
6872 surface
->flags
|= SFLAG_DYNLOCK
;
6874 /* Mark the texture as dirty so that it gets loaded first time around. */
6875 surface_add_dirty_rect(surface
, NULL
);
6876 list_init(&surface
->renderbuffers
);
6878 TRACE("surface %p, memory %p, size %u\n",
6879 surface
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
6881 /* Call the private setup routine */
6882 hr
= surface
->surface_ops
->surface_private_setup(surface
);
6885 ERR("Private setup failed, returning %#x\n", hr
);
6886 surface_cleanup(surface
);
6890 /* Similar to lockable rendertargets above, creating the DIB section
6891 * during surface initialization prevents the sysmem pointer from changing
6892 * after a wined3d_surface_getdc() call. */
6893 if ((usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
6894 && SUCCEEDED(surface_create_dib_section(surface
)))
6896 wined3d_resource_free_sysmem(&surface
->resource
);
6897 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
6903 HRESULT CDECL
wined3d_surface_create(struct wined3d_device
*device
, UINT width
, UINT height
,
6904 enum wined3d_format_id format_id
, DWORD usage
, enum wined3d_pool pool
,
6905 enum wined3d_multisample_type multisample_type
, DWORD multisample_quality
, DWORD flags
,
6906 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_surface
**surface
)
6908 struct wined3d_surface
*object
;
6911 TRACE("device %p, width %u, height %u, format %s\n",
6912 device
, width
, height
, debug_d3dformat(format_id
));
6913 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
6914 surface
, debug_d3dusage(usage
), usage
, debug_d3dpool(pool
), multisample_type
, multisample_quality
);
6915 TRACE("flags %#x, parent %p, parent_ops %p.\n", flags
, parent
, parent_ops
);
6917 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
6919 return WINED3DERR_OUTOFVIDEOMEMORY
;
6921 if (FAILED(hr
= surface_init(object
, device
->surface_alignment
, width
, height
, multisample_type
,
6922 multisample_quality
, device
, usage
, format_id
, pool
, flags
, parent
, parent_ops
)))
6924 WARN("Failed to initialize surface, returning %#x.\n", hr
);
6925 HeapFree(GetProcessHeap(), 0, object
);
6929 TRACE("Created surface %p.\n", object
);