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-2014 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
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
32 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
33 WINE_DECLARE_DEBUG_CHANNEL(d3d
);
35 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
37 #if defined(STAGING_CSMT)
39 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
40 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
41 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
);
43 void wined3d_surface_cleanup_cs(struct wined3d_surface
*surface
)
45 if (surface
->rb_multisample
|| surface
->rb_resolved
|| !list_empty(&surface
->renderbuffers
))
46 #else /* STAGING_CSMT */
47 static const DWORD surface_simple_locations
=
48 WINED3D_LOCATION_SYSMEM
| WINED3D_LOCATION_USER_MEMORY
49 | WINED3D_LOCATION_DIB
| WINED3D_LOCATION_BUFFER
;
51 static void surface_cleanup(struct wined3d_surface
*surface
)
53 struct wined3d_surface
*overlay
, *cur
;
55 TRACE("surface %p.\n", surface
);
57 if (surface
->pbo
|| surface
->rb_multisample
58 || surface
->rb_resolved
|| !list_empty(&surface
->renderbuffers
))
59 #endif /* STAGING_CSMT */
61 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
62 const struct wined3d_gl_info
*gl_info
;
63 struct wined3d_context
*context
;
65 context
= context_acquire(surface
->resource
.device
, NULL
);
66 gl_info
= context
->gl_info
;
68 #if !defined(STAGING_CSMT)
71 TRACE("Deleting PBO %u.\n", surface
->pbo
);
72 GL_EXTCALL(glDeleteBuffers(1, &surface
->pbo
));
75 #endif /* STAGING_CSMT */
76 if (surface
->rb_multisample
)
78 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
79 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
82 if (surface
->rb_resolved
)
84 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
85 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
88 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
90 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
91 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
92 HeapFree(GetProcessHeap(), 0, entry
);
95 context_release(context
);
98 if (surface
->flags
& SFLAG_DIBSECTION
)
100 DeleteDC(surface
->hDC
);
101 DeleteObject(surface
->dib
.DIBsection
);
102 #if defined(STAGING_CSMT)
103 surface
->resource
.bitmap_data
= NULL
;
106 TRACE("Destroyed surface %p.\n", surface
);
107 HeapFree(GetProcessHeap(), 0, surface
);
110 static void surface_cleanup(struct wined3d_surface
*surface
)
112 struct wined3d_surface
*overlay
, *cur
;
113 struct wined3d_cs
*cs
= surface
->resource
.device
->cs
;
114 BOOL user_mem
= surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
;
116 TRACE("surface %p.\n", surface
);
117 #else /* STAGING_CSMT */
118 surface
->dib
.bitmap_data
= NULL
;
120 #endif /* STAGING_CSMT */
122 if (surface
->overlay_dest
)
123 list_remove(&surface
->overlay_entry
);
125 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
127 list_remove(&overlay
->overlay_entry
);
128 overlay
->overlay_dest
= NULL
;
131 resource_cleanup(&surface
->resource
);
132 #if defined(STAGING_CSMT)
133 wined3d_cs_emit_surface_cleanup(cs
, surface
);
135 /* Wait for the CS to finish operations on this surface when user memory was in use.
136 * The application is allowed to free the memory after texture / surface destruction
139 wined3d_resource_wait_fence(&surface
->container
->resource
);
142 void wined3d_surface_destroy(struct wined3d_surface
*surface
)
144 TRACE("surface %p.\n", surface
);
146 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
147 surface_cleanup(surface
);
148 #else /* STAGING_CSMT */
151 void wined3d_surface_destroy(struct wined3d_surface
*surface
)
153 TRACE("surface %p.\n", surface
);
155 surface_cleanup(surface
);
156 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
157 HeapFree(GetProcessHeap(), 0, surface
);
158 #endif /* STAGING_CSMT */
161 void surface_get_drawable_size(const struct wined3d_surface
*surface
, const struct wined3d_context
*context
,
162 unsigned int *width
, unsigned int *height
)
164 if (surface
->container
->swapchain
)
166 /* The drawable size of an onscreen drawable is the surface size.
167 * (Actually: The window size, but the surface is created in window
169 *width
= context
->current_rt
->resource
.width
;
170 *height
= context
->current_rt
->resource
.height
;
172 else if (wined3d_settings
.offscreen_rendering_mode
== ORM_BACKBUFFER
)
174 const struct wined3d_swapchain
*swapchain
= context
->swapchain
;
176 /* The drawable size of a backbuffer / aux buffer offscreen target is
177 * the size of the current context's drawable, which is the size of
178 * the back buffer of the swapchain the active context belongs to. */
179 *width
= swapchain
->desc
.backbuffer_width
;
180 *height
= swapchain
->desc
.backbuffer_height
;
184 /* The drawable size of an FBO target is the OpenGL texture size,
185 * which is the power of two size. */
186 *width
= context
->current_rt
->pow2Width
;
187 *height
= context
->current_rt
->pow2Height
;
195 enum wined3d_gl_resource_type tex_type
;
196 GLfloat coords
[4][3];
207 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
209 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
210 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
211 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
212 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
215 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
217 GLfloat (*coords
)[3] = info
->coords
;
223 FIXME("Unsupported texture target %#x\n", target
);
224 /* Fall back to GL_TEXTURE_2D */
226 info
->binding
= GL_TEXTURE_BINDING_2D
;
227 info
->bind_target
= GL_TEXTURE_2D
;
228 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_2D
;
229 coords
[0][0] = (float)rect
->left
/ w
;
230 coords
[0][1] = (float)rect
->top
/ h
;
233 coords
[1][0] = (float)rect
->right
/ w
;
234 coords
[1][1] = (float)rect
->top
/ h
;
237 coords
[2][0] = (float)rect
->left
/ w
;
238 coords
[2][1] = (float)rect
->bottom
/ h
;
241 coords
[3][0] = (float)rect
->right
/ w
;
242 coords
[3][1] = (float)rect
->bottom
/ h
;
246 case GL_TEXTURE_RECTANGLE_ARB
:
247 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
248 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
249 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_RECT
;
250 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
251 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
252 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
253 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
256 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
257 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
258 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
259 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
260 cube_coords_float(rect
, w
, h
, &f
);
262 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
263 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
264 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
265 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
268 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
269 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
270 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
271 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
272 cube_coords_float(rect
, w
, h
, &f
);
274 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
275 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
276 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
277 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
280 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
281 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
282 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
283 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
284 cube_coords_float(rect
, w
, h
, &f
);
286 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
287 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
288 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
289 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
292 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
293 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
294 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
295 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
296 cube_coords_float(rect
, w
, h
, &f
);
298 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
299 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
300 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
301 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
304 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
305 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
306 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
307 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
308 cube_coords_float(rect
, w
, h
, &f
);
310 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
311 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
312 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
313 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
316 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
317 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
318 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
319 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
320 cube_coords_float(rect
, w
, h
, &f
);
322 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
323 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
324 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
325 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
330 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
333 *rect_out
= *rect_in
;
338 rect_out
->right
= surface
->resource
.width
;
339 rect_out
->bottom
= surface
->resource
.height
;
343 /* Context activation is done by the caller. */
344 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
345 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
347 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
348 struct wined3d_texture
*texture
= src_surface
->container
;
349 struct blt_info info
;
351 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
353 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
354 checkGLcall("glEnable(bind_target)");
356 context_bind_texture(context
, info
.bind_target
, texture
->texture_rgb
.name
);
358 /* Filtering for StretchRect */
359 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
360 checkGLcall("glTexParameteri");
361 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
362 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
363 checkGLcall("glTexParameteri");
364 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
365 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
366 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
367 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
368 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
369 checkGLcall("glTexEnvi");
372 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
373 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
374 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
376 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
377 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
379 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
380 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
382 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
383 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
384 gl_info
->gl_ops
.gl
.p_glEnd();
386 /* Unbind the texture */
387 context_bind_texture(context
, info
.bind_target
, 0);
389 /* We changed the filtering settings on the texture. Inform the
390 * container about this to get the filters reset properly next draw. */
391 texture
->texture_rgb
.sampler_desc
.mag_filter
= WINED3D_TEXF_POINT
;
392 texture
->texture_rgb
.sampler_desc
.min_filter
= WINED3D_TEXF_POINT
;
393 texture
->texture_rgb
.sampler_desc
.mip_filter
= WINED3D_TEXF_NONE
;
394 texture
->texture_rgb
.sampler_desc
.srgb_decode
= FALSE
;
397 /* Works correctly only for <= 4 bpp formats. */
398 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
400 masks
[0] = ((1u << format
->red_size
) - 1) << format
->red_offset
;
401 masks
[1] = ((1u << format
->green_size
) - 1) << format
->green_offset
;
402 masks
[2] = ((1u << format
->blue_size
) - 1) << format
->blue_offset
;
405 HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
407 const struct wined3d_format
*format
= surface
->resource
.format
;
408 unsigned int format_flags
= surface
->container
->resource
.format_flags
;
409 unsigned int row_pitch
, slice_pitch
;
413 TRACE("surface %p.\n", surface
);
415 if (!(format_flags
& WINED3DFMT_FLAG_GETDC
))
417 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
418 return WINED3DERR_INVALIDCALL
;
421 switch (format
->byte_count
)
425 /* Allocate extra space to store the RGB bit masks. */
426 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3]));
430 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[0]));
434 /* Allocate extra space for a palette. */
435 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
436 FIELD_OFFSET(BITMAPINFO
, bmiColors
[1u << (format
->byte_count
* 8)]));
441 return E_OUTOFMEMORY
;
443 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
444 #if defined(STAGING_CSMT)
445 wined3d_resource_get_pitch(&surface
->resource
, &row_pitch
, &slice_pitch
);
446 #else /* STAGING_CSMT */
447 wined3d_texture_get_pitch(surface
->container
, surface
->texture_level
, &row_pitch
, &slice_pitch
);
448 #endif /* STAGING_CSMT */
449 b_info
->bmiHeader
.biWidth
= row_pitch
/ format
->byte_count
;
450 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
;
451 b_info
->bmiHeader
.biSizeImage
= slice_pitch
;
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 #if defined(STAGING_CSMT)
494 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->resource
.bitmap_data
, 0, 0);
495 #else /* STAGING_CSMT */
496 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->dib
.bitmap_data
, 0, 0);
497 #endif /* STAGING_CSMT */
499 if (!surface
->dib
.DIBsection
)
501 ERR("Failed to create DIB section.\n");
502 HeapFree(GetProcessHeap(), 0, b_info
);
503 return HRESULT_FROM_WIN32(GetLastError());
506 #if defined(STAGING_CSMT)
507 TRACE("DIBSection at %p.\n", surface
->resource
.bitmap_data
);
508 #else /* STAGING_CSMT */
509 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
510 #endif /* STAGING_CSMT */
511 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
513 HeapFree(GetProcessHeap(), 0, b_info
);
515 /* Now allocate a DC. */
516 surface
->hDC
= CreateCompatibleDC(0);
517 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
519 surface
->flags
|= SFLAG_DIBSECTION
;
524 #if !defined(STAGING_CSMT)
525 static void surface_get_memory(const struct wined3d_surface
*surface
, struct wined3d_bo_address
*data
,
528 if (location
& WINED3D_LOCATION_BUFFER
)
531 data
->buffer_object
= surface
->pbo
;
534 if (location
& WINED3D_LOCATION_USER_MEMORY
)
536 data
->addr
= surface
->container
->user_memory
;
537 data
->buffer_object
= 0;
540 if (location
& WINED3D_LOCATION_DIB
)
542 data
->addr
= surface
->dib
.bitmap_data
;
543 data
->buffer_object
= 0;
546 if (location
& WINED3D_LOCATION_SYSMEM
)
548 data
->addr
= surface
->resource
.heap_memory
;
549 data
->buffer_object
= 0;
553 ERR("Unexpected locations %s.\n", wined3d_debug_location(location
));
555 data
->buffer_object
= 0;
558 static void surface_prepare_buffer(struct wined3d_surface
*surface
)
560 struct wined3d_context
*context
;
562 const struct wined3d_gl_info
*gl_info
;
567 context
= context_acquire(surface
->resource
.device
, NULL
);
568 gl_info
= context
->gl_info
;
570 GL_EXTCALL(glGenBuffers(1, &surface
->pbo
));
571 error
= gl_info
->gl_ops
.gl
.p_glGetError();
572 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
573 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
575 TRACE("Binding PBO %u.\n", surface
->pbo
);
577 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
578 checkGLcall("glBindBuffer");
580 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER
, surface
->resource
.size
+ 4,
581 NULL
, GL_STREAM_DRAW
));
582 checkGLcall("glBufferData");
584 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
585 checkGLcall("glBindBuffer");
587 context_release(context
);
590 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
592 TRACE("surface %p.\n", surface
);
594 if (surface
->resource
.heap_memory
)
597 /* Whatever surface we have, make sure that there is memory allocated
598 * for the downloaded copy, or a PBO to map. */
599 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
600 ERR("Failed to allocate system memory.\n");
602 if (surface
->locations
& WINED3D_LOCATION_SYSMEM
)
603 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
606 void surface_prepare_map_memory(struct wined3d_surface
*surface
)
608 switch (surface
->resource
.map_binding
)
610 case WINED3D_LOCATION_SYSMEM
:
611 surface_prepare_system_memory(surface
);
614 case WINED3D_LOCATION_USER_MEMORY
:
615 if (!surface
->container
->user_memory
)
616 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
619 case WINED3D_LOCATION_DIB
:
620 if (!surface
->dib
.bitmap_data
)
621 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
624 case WINED3D_LOCATION_BUFFER
:
625 surface_prepare_buffer(surface
);
629 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
633 #endif /* STAGING_CSMT */
634 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
636 /* In some conditions the surface memory must not be freed:
637 * WINED3D_TEXTURE_CONVERTED: Converting the data back would take too long
638 * WINED3D_TEXTURE_DYNAMIC_MAP: Avoid freeing the data for performance */
639 if (surface
->resource
.map_count
|| surface
->container
->flags
& (WINED3D_TEXTURE_CONVERTED
640 | WINED3D_TEXTURE_PIN_SYSMEM
| WINED3D_TEXTURE_DYNAMIC_MAP
))
643 wined3d_resource_free_sysmem(&surface
->resource
);
644 #if defined(STAGING_CSMT)
645 surface
->resource
.map_heap_memory
= NULL
;
646 wined3d_resource_invalidate_location(&surface
->resource
, WINED3D_LOCATION_SYSMEM
);
647 #else /* STAGING_CSMT */
648 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
649 #endif /* STAGING_CSMT */
652 static BOOL
surface_use_pbo(const struct wined3d_surface
*surface
)
654 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
655 struct wined3d_texture
*texture
= surface
->container
;
657 return texture
->resource
.pool
== WINED3D_POOL_DEFAULT
658 && surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
659 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
660 && !texture
->resource
.format
->convert
661 && !(texture
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
)
662 && !(texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
);
665 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
667 /* TODO: Check against the maximum texture sizes supported by the video card. */
668 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
669 unsigned int pow2Width
, pow2Height
;
671 TRACE("surface %p.\n", surface
);
673 /* Non-power2 support */
674 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
]
675 || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
677 pow2Width
= surface
->resource
.width
;
678 pow2Height
= surface
->resource
.height
;
682 /* Find the nearest pow2 match */
683 pow2Width
= pow2Height
= 1;
684 while (pow2Width
< surface
->resource
.width
)
686 while (pow2Height
< surface
->resource
.height
)
689 surface
->pow2Width
= pow2Width
;
690 surface
->pow2Height
= pow2Height
;
692 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
694 /* TODO: Add support for non power two compressed textures. */
695 if (surface
->container
->resource
.format_flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_HEIGHT_SCALE
))
697 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
698 surface
, surface
->resource
.width
, surface
->resource
.height
);
699 return WINED3DERR_NOTAVAILABLE
;
703 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
704 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
706 /* One of three options:
707 * 1: Do the same as we do with NPOT and scale the texture, (any
708 * texture ops would require the texture to be scaled which is
710 * 2: Set the texture to the maximum size (bad idea).
711 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
712 * 4: Create the surface, but allow it to be used only for DirectDraw
713 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
714 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
715 * the render target. */
716 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
|| surface
->resource
.pool
== WINED3D_POOL_MANAGED
)
718 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
719 return WINED3DERR_NOTAVAILABLE
;
722 /* We should never use this surface in combination with OpenGL! */
723 TRACE("Creating an oversized surface: %ux%u.\n",
724 surface
->pow2Width
, surface
->pow2Height
);
727 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
728 #if defined(STAGING_CSMT)
729 surface
->resource
.locations
= WINED3D_LOCATION_DISCARDED
;
730 #else /* STAGING_CSMT */
731 surface
->locations
= WINED3D_LOCATION_DISCARDED
;
732 #endif /* STAGING_CSMT */
734 if (surface_use_pbo(surface
))
735 surface
->resource
.map_binding
= WINED3D_LOCATION_BUFFER
;
740 #if defined(STAGING_CSMT)
741 static void surface_frontbuffer_updated(struct wined3d_surface
*surface
)
743 struct wined3d_context
*context
= NULL
;
744 struct wined3d_device
*device
= surface
->resource
.device
;
746 if (surface
->resource
.locations
& WINED3D_LOCATION_DRAWABLE
)
748 TRACE("Not dirtified, nothing to do.\n");
752 if (device
->d3d_initialized
)
753 context
= context_acquire(surface
->resource
.device
, NULL
);
754 wined3d_resource_load_location(&surface
->resource
, context
, surface
->container
->resource
.draw_binding
);
756 context_release(context
);
757 #else /* STAGING_CSMT */
758 static void surface_unmap(struct wined3d_surface
*surface
)
760 struct wined3d_device
*device
= surface
->resource
.device
;
761 const struct wined3d_gl_info
*gl_info
;
762 struct wined3d_context
*context
;
764 TRACE("surface %p.\n", surface
);
766 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
768 switch (surface
->resource
.map_binding
)
770 case WINED3D_LOCATION_SYSMEM
:
771 case WINED3D_LOCATION_USER_MEMORY
:
772 case WINED3D_LOCATION_DIB
:
775 case WINED3D_LOCATION_BUFFER
:
776 context
= context_acquire(device
, NULL
);
777 gl_info
= context
->gl_info
;
779 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
780 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER
));
781 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
782 checkGLcall("glUnmapBuffer");
783 context_release(context
);
787 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
790 if (surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_TEXTURE_RGB
))
792 TRACE("Not dirtified, nothing to do.\n");
796 if (surface
->container
->swapchain
&& surface
->container
->swapchain
->front_buffer
== surface
->container
)
798 context
= context_acquire(device
, surface
);
799 surface_load_location(surface
, context
, surface
->container
->resource
.draw_binding
);
800 context_release(context
);
802 else if (surface
->container
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
803 FIXME("Depth / stencil buffer locking is not implemented.\n");
804 #endif /* STAGING_CSMT */
807 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
809 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
811 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
816 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
817 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
818 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
820 const struct wined3d_gl_info
*gl_info
;
821 struct wined3d_context
*context
;
822 DWORD src_mask
, dst_mask
;
825 TRACE("device %p\n", device
);
826 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
827 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
828 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
829 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
831 src_mask
= src_surface
->container
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
832 dst_mask
= dst_surface
->container
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
834 if (src_mask
!= dst_mask
)
836 ERR("Incompatible formats %s and %s.\n",
837 debug_d3dformat(src_surface
->resource
.format
->id
),
838 debug_d3dformat(dst_surface
->resource
.format
->id
));
844 ERR("Not a depth / stencil format: %s.\n",
845 debug_d3dformat(src_surface
->resource
.format
->id
));
850 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
851 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
852 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
853 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
855 context
= context_acquire(device
, NULL
);
858 context_release(context
);
859 WARN("Invalid context, skipping blit.\n");
863 /* Make sure the locations are up-to-date. Loading the destination
864 * surface isn't required if the entire surface is overwritten. */
865 #if defined(STAGING_CSMT)
866 wined3d_resource_load_location(&src_surface
->resource
, context
, src_location
);
867 if (!surface_is_full_rect(dst_surface
, dst_rect
))
868 wined3d_resource_load_location(&dst_surface
->resource
, context
, dst_location
);
869 #else /* STAGING_CSMT */
870 surface_load_location(src_surface
, context
, src_location
);
871 if (!surface_is_full_rect(dst_surface
, dst_rect
))
872 surface_load_location(dst_surface
, context
, dst_location
);
873 #endif /* STAGING_CSMT */
875 wined3d_surface_prepare(dst_surface
, context
, dst_location
);
877 gl_info
= context
->gl_info
;
879 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
880 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
882 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
883 context_set_draw_buffer(context
, GL_NONE
);
884 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
885 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
887 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
889 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
890 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
892 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
894 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
896 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
897 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
899 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
900 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
903 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
904 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
906 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
907 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
908 checkGLcall("glBlitFramebuffer()");
910 if (wined3d_settings
.strict_draw_ordering
)
911 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
913 context_release(context
);
916 /* Blit between surface locations. Onscreen on different swapchains is not supported.
917 * Depth / stencil is not supported. Context activation is done by the caller. */
918 static void surface_blt_fbo(const struct wined3d_device
*device
,
919 struct wined3d_context
*old_ctx
, enum wined3d_texture_filter_type filter
,
920 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
921 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
923 const struct wined3d_gl_info
*gl_info
;
924 struct wined3d_context
*context
= old_ctx
;
925 struct wined3d_surface
*required_rt
, *restore_rt
= NULL
;
926 RECT src_rect
, dst_rect
;
930 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
931 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
932 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
933 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
934 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
936 src_rect
= *src_rect_in
;
937 dst_rect
= *dst_rect_in
;
941 case WINED3D_TEXF_LINEAR
:
942 gl_filter
= GL_LINEAR
;
946 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
947 case WINED3D_TEXF_NONE
:
948 case WINED3D_TEXF_POINT
:
949 gl_filter
= GL_NEAREST
;
953 /* Resolve the source surface first if needed. */
954 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
955 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
956 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
957 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
958 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
960 /* Make sure the locations are up-to-date. Loading the destination
961 * surface isn't required if the entire surface is overwritten. (And is
962 * in fact harmful if we're being called by surface_load_location() with
963 * the purpose of loading the destination surface.) */
964 #if defined(STAGING_CSMT)
965 wined3d_resource_load_location(&src_surface
->resource
, old_ctx
, src_location
);
966 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
967 wined3d_resource_load_location(&dst_surface
->resource
, old_ctx
, dst_location
);
968 #else /* STAGING_CSMT */
969 surface_load_location(src_surface
, old_ctx
, src_location
);
970 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
971 surface_load_location(dst_surface
, old_ctx
, dst_location
);
972 #endif /* STAGING_CSMT */
974 wined3d_surface_prepare(dst_surface
, old_ctx
, dst_location
);
977 if (src_location
== WINED3D_LOCATION_DRAWABLE
) required_rt
= src_surface
;
978 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) required_rt
= dst_surface
;
979 else required_rt
= NULL
;
981 if (required_rt
&& required_rt
!= old_ctx
->current_rt
)
983 restore_rt
= old_ctx
->current_rt
;
984 context
= context_acquire(device
, required_rt
);
989 context_release(context
);
990 WARN("Invalid context, skipping blit.\n");
994 gl_info
= context
->gl_info
;
996 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
998 TRACE("Source surface %p is onscreen.\n", src_surface
);
999 buffer
= surface_get_gl_buffer(src_surface
);
1000 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
1004 TRACE("Source surface %p is offscreen.\n", src_surface
);
1005 buffer
= GL_COLOR_ATTACHMENT0
;
1008 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
1009 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
1010 checkGLcall("glReadBuffer()");
1011 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1013 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
1015 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
1016 buffer
= surface_get_gl_buffer(dst_surface
);
1017 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
1021 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
1022 buffer
= GL_COLOR_ATTACHMENT0
;
1025 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
1026 context_set_draw_buffer(context
, buffer
);
1027 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1028 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
1030 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
1031 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
1032 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
1033 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
1034 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
1036 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
1037 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
1039 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
1040 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
1041 checkGLcall("glBlitFramebuffer()");
1043 if (wined3d_settings
.strict_draw_ordering
1044 || (dst_location
== WINED3D_LOCATION_DRAWABLE
1045 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
1046 gl_info
->gl_ops
.gl
.p_glFlush();
1049 context_restore(context
, restore_rt
);
1052 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
1053 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
1054 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
1056 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
1059 /* Source and/or destination need to be on the GL side */
1060 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
1065 case WINED3D_BLIT_OP_COLOR_BLIT
:
1066 if (!((src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
1067 || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
1069 if (!((dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
1070 || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1072 if (!(src_format
->id
== dst_format
->id
1073 || (is_identity_fixup(src_format
->color_fixup
)
1074 && is_identity_fixup(dst_format
->color_fixup
))))
1078 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1079 if (!(src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1081 if (!(dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1083 /* Accept pure swizzle fixups for depth formats. In general we
1084 * ignore the stencil component (if present) at the moment and the
1085 * swizzle is not relevant with just the depth component. */
1086 if (is_complex_fixup(src_format
->color_fixup
) || is_complex_fixup(dst_format
->color_fixup
)
1087 || is_scaling_fixup(src_format
->color_fixup
) || is_scaling_fixup(dst_format
->color_fixup
))
1098 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1100 const struct wined3d_format
*format
= surface
->resource
.format
;
1104 case WINED3DFMT_S1_UINT_D15_UNORM
:
1105 *float_depth
= depth
/ (float)0x00007fff;
1108 case WINED3DFMT_D16_UNORM
:
1109 *float_depth
= depth
/ (float)0x0000ffff;
1112 case WINED3DFMT_D24_UNORM_S8_UINT
:
1113 case WINED3DFMT_X8D24_UNORM
:
1114 *float_depth
= depth
/ (float)0x00ffffff;
1117 case WINED3DFMT_D32_UNORM
:
1118 *float_depth
= depth
/ (float)0xffffffff;
1122 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1129 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1131 struct wined3d_resource
*resource
= &surface
->container
->resource
;
1132 struct wined3d_device
*device
= resource
->device
;
1133 #if defined(STAGING_CSMT)
1134 struct wined3d_rendertarget_view view
;
1135 struct wined3d_texture
*texture
= surface
->container
;
1136 #else /* STAGING_CSMT */
1137 struct wined3d_rendertarget_view_desc view_desc
;
1138 struct wined3d_rendertarget_view
*view
;
1139 #endif /* STAGING_CSMT */
1140 const struct blit_shader
*blitter
;
1143 if (!(blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
,
1144 WINED3D_BLIT_OP_DEPTH_FILL
, NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
)))
1146 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1147 return WINED3DERR_INVALIDCALL
;
1150 #if defined(STAGING_CSMT)
1151 view
.resource
= &surface
->container
->resource
;
1153 view
.parent_ops
= &wined3d_null_parent_ops
;
1154 view
.format
= surface
->resource
.format
;
1155 view
.buffer_offset
= 0;
1156 view
.width
= surface
->resource
.width
;
1157 view
.height
= surface
->resource
.height
;
1159 view
.sub_resource_idx
= surface
->texture_layer
* texture
->level_count
+ surface
->texture_level
;
1161 hr
= blitter
->depth_fill(device
, &view
, rect
, depth
);
1162 #else /* STAGING_CSMT */
1163 view_desc
.format_id
= resource
->format
->id
;
1164 view_desc
.u
.texture
.level_idx
= surface
->texture_level
;
1165 view_desc
.u
.texture
.layer_idx
= surface
->texture_layer
;
1166 view_desc
.u
.texture
.layer_count
= 1;
1167 if (FAILED(hr
= wined3d_rendertarget_view_create(&view_desc
,
1168 resource
, NULL
, &wined3d_null_parent_ops
, &view
)))
1170 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
1174 hr
= blitter
->depth_fill(device
, view
, rect
, depth
);
1175 wined3d_rendertarget_view_decref(view
);
1176 #endif /* STAGING_CSMT */
1181 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1182 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1184 struct wined3d_device
*device
= src_surface
->resource
.device
;
1186 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1187 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1188 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1189 return WINED3DERR_INVALIDCALL
;
1191 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
1193 surface_modify_ds_location(dst_surface
, dst_location
,
1194 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1199 #if !defined(STAGING_CSMT)
1200 /* Context activation is done by the caller. */
1201 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1203 GL_EXTCALL(glDeleteBuffers(1, &surface
->pbo
));
1204 checkGLcall("glDeleteBuffers(1, &surface->pbo)");
1207 surface_invalidate_location(surface
, WINED3D_LOCATION_BUFFER
);
1210 #endif /* STAGING_CSMT */
1211 static ULONG
surface_resource_incref(struct wined3d_resource
*resource
)
1213 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1215 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
1217 return wined3d_texture_incref(surface
->container
);
1220 static ULONG
surface_resource_decref(struct wined3d_resource
*resource
)
1222 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1224 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
1226 return wined3d_texture_decref(surface
->container
);
1229 static void surface_unload(struct wined3d_resource
*resource
)
1231 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1232 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1233 struct wined3d_device
*device
= resource
->device
;
1234 const struct wined3d_gl_info
*gl_info
;
1235 struct wined3d_context
*context
;
1237 TRACE("surface %p.\n", surface
);
1239 context
= context_acquire(device
, NULL
);
1240 gl_info
= context
->gl_info
;
1242 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
1244 #if defined(STAGING_CSMT)
1245 /* Default pool resources are supposed to be destroyed before Reset is called.
1246 * Implicit resources stay however. So this means we have an implicit render target
1247 * or depth stencil. The content may be destroyed, but we still have to tear down
1248 * opengl resources, so we cannot leave early. */
1249 wined3d_resource_validate_location(&surface
->resource
, WINED3D_LOCATION_DISCARDED
);
1250 wined3d_resource_invalidate_location(&surface
->resource
, ~WINED3D_LOCATION_DISCARDED
);
1254 wined3d_resource_prepare_map_memory(&surface
->resource
, context
);
1255 wined3d_resource_load_location(&surface
->resource
, context
, surface
->resource
.map_binding
);
1256 wined3d_resource_invalidate_location(&surface
->resource
, ~surface
->resource
.map_binding
);
1258 #else /* STAGING_CSMT */
1259 /* Default pool resources are supposed to be destroyed before Reset is called.
1260 * Implicit resources stay however. So this means we have an implicit render target
1261 * or depth stencil. The content may be destroyed, but we still have to tear down
1262 * opengl resources, so we cannot leave early.
1264 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1265 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1266 * or the depth stencil into an FBO the texture or render buffer will be removed
1267 * and all flags get lost */
1268 if (resource
->usage
& WINED3DUSAGE_DEPTHSTENCIL
)
1270 surface_validate_location(surface
, WINED3D_LOCATION_DISCARDED
);
1271 surface_invalidate_location(surface
, ~WINED3D_LOCATION_DISCARDED
);
1275 surface_prepare_system_memory(surface
);
1276 memset(surface
->resource
.heap_memory
, 0, surface
->resource
.size
);
1277 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
1278 surface_invalidate_location(surface
, ~WINED3D_LOCATION_SYSMEM
);
1283 surface_prepare_map_memory(surface
);
1284 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
1285 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
1288 /* Destroy PBOs, but load them into real sysmem before */
1290 surface_remove_pbo(surface
, gl_info
);
1291 #endif /* STAGING_CSMT */
1293 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1294 * all application-created targets the application has to release the surface
1295 * before calling _Reset
1297 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1299 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1300 list_remove(&entry
->entry
);
1301 HeapFree(GetProcessHeap(), 0, entry
);
1303 list_init(&surface
->renderbuffers
);
1304 surface
->current_renderbuffer
= NULL
;
1306 if (surface
->rb_multisample
)
1308 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1309 surface
->rb_multisample
= 0;
1311 if (surface
->rb_resolved
)
1313 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1314 surface
->rb_resolved
= 0;
1317 context_release(context
);
1319 resource_unload(resource
);
1322 static HRESULT
surface_resource_sub_resource_map(struct wined3d_resource
*resource
, unsigned int sub_resource_idx
,
1323 struct wined3d_map_desc
*map_desc
, const struct wined3d_box
*box
, DWORD flags
)
1325 ERR("Not supported on sub-resources.\n");
1326 return WINED3DERR_INVALIDCALL
;
1329 static HRESULT
surface_resource_sub_resource_unmap(struct wined3d_resource
*resource
, unsigned int sub_resource_idx
)
1331 ERR("Not supported on sub-resources.\n");
1332 return WINED3DERR_INVALIDCALL
;
1335 #if defined(STAGING_CSMT)
1336 static void wined3d_surface_location_invalidated(struct wined3d_resource
*resource
, DWORD location
)
1338 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1340 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
1341 wined3d_texture_set_dirty(surface
->container
);
1343 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
1344 surface
->surface_ops
->surface_frontbuffer_updated(surface
);
1347 static const struct wined3d_surface_ops surface_ops
=
1349 surface_private_setup
,
1350 surface_frontbuffer_updated
,
1351 #else /* STAGING_CSMT */
1352 static const struct wined3d_resource_ops surface_resource_ops
=
1354 surface_resource_incref
,
1355 surface_resource_decref
,
1357 surface_resource_sub_resource_map
,
1358 surface_resource_sub_resource_unmap
,
1361 static const struct wined3d_surface_ops surface_ops
=
1363 surface_private_setup
,
1365 #endif /* STAGING_CSMT */
1368 /*****************************************************************************
1369 * Initializes the GDI surface, aka creates the DIB section we render to
1370 * The DIB section creation is done by calling GetDC, which will create the
1371 * section and releasing the dc to allow the app to use it. The dib section
1372 * will stay until the surface is released
1374 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1375 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1376 * avoid confusion in the shared surface code.
1379 * WINED3D_OK on success
1380 * The return values of called methods on failure
1382 *****************************************************************************/
1383 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1387 TRACE("surface %p.\n", surface
);
1389 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1391 ERR("Overlays not yet supported by GDI surfaces.\n");
1392 return WINED3DERR_INVALIDCALL
;
1395 /* Sysmem textures have memory already allocated - release it,
1396 * this avoids an unnecessary memcpy. */
1397 hr
= surface_create_dib_section(surface
);
1400 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
1402 /* We don't mind the nonpow2 stuff in GDI. */
1403 surface
->pow2Width
= surface
->resource
.width
;
1404 surface
->pow2Height
= surface
->resource
.height
;
1409 #if defined(STAGING_CSMT)
1410 static void gdi_surface_frontbuffer_updated(struct wined3d_surface
*surface
)
1412 x11_copy_to_screen(surface
->container
->swapchain
, &surface
->lockedRect
);
1415 static const struct wined3d_surface_ops gdi_surface_ops
=
1417 gdi_surface_private_setup
,
1418 gdi_surface_frontbuffer_updated
,
1419 #else /* STAGING_CSMT */
1420 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1422 TRACE("surface %p.\n", surface
);
1424 /* Tell the swapchain to update the screen. */
1425 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
1426 x11_copy_to_screen(surface
->container
->swapchain
, &surface
->lockedRect
);
1428 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
1431 static const struct wined3d_surface_ops gdi_surface_ops
=
1433 gdi_surface_private_setup
,
1435 #endif /* STAGING_CSMT */
1438 /* This call just downloads data, the caller is responsible for binding the
1439 * correct texture. */
1440 /* Context activation is done by the caller. */
1441 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1444 const struct wined3d_format
*format
= surface
->resource
.format
;
1445 struct wined3d_bo_address data
;
1447 /* Only support read back of converted P8 surfaces. */
1448 if (surface
->container
->flags
& WINED3D_TEXTURE_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1450 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1454 #if defined(STAGING_CSMT)
1455 wined3d_resource_get_memory(&surface
->resource
, dst_location
, &data
);
1456 #else /* STAGING_CSMT */
1457 surface_get_memory(surface
, &data
, dst_location
);
1458 #endif /* STAGING_CSMT */
1460 if (surface
->container
->resource
.format_flags
& WINED3DFMT_FLAG_COMPRESSED
)
1462 TRACE("(%p) : Calling glGetCompressedTexImage level %d, format %#x, type %#x, data %p.\n",
1463 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, data
.addr
);
1465 if (data
.buffer_object
)
1467 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1468 checkGLcall("glBindBuffer");
1469 GL_EXTCALL(glGetCompressedTexImage(surface
->texture_target
, surface
->texture_level
, NULL
));
1470 checkGLcall("glGetCompressedTexImage");
1471 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1472 checkGLcall("glBindBuffer");
1476 GL_EXTCALL(glGetCompressedTexImage(surface
->texture_target
,
1477 surface
->texture_level
, data
.addr
));
1478 checkGLcall("glGetCompressedTexImage");
1483 unsigned int dst_row_pitch
, dst_slice_pitch
;
1484 #if defined(STAGING_CSMT)
1485 unsigned int src_pitch
;
1486 GLenum gl_format
= format
->glFormat
;
1487 GLenum gl_type
= format
->glType
;
1490 if (surface
->container
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
1492 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
1493 src_pitch
= format
->byte_count
* surface
->pow2Width
;
1494 wined3d_resource_get_pitch(&surface
->resource
, &dst_row_pitch
, &dst_slice_pitch
);
1495 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
1496 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
1497 #else /* STAGING_CSMT */
1498 unsigned int src_row_pitch
, src_slice_pitch
;
1499 GLenum gl_format
= format
->glFormat
;
1500 GLenum gl_type
= format
->glType
;
1503 if (surface
->container
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
1505 wined3d_texture_get_pitch(surface
->container
, surface
->texture_level
, &dst_row_pitch
, &dst_slice_pitch
);
1506 wined3d_format_calculate_pitch(format
, surface
->resource
.device
->surface_alignment
,
1507 surface
->pow2Width
, surface
->pow2Height
, &src_row_pitch
, &src_slice_pitch
);
1508 mem
= HeapAlloc(GetProcessHeap(), 0, src_slice_pitch
);
1509 #endif /* STAGING_CSMT */
1516 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1517 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1519 if (data
.buffer_object
)
1521 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1522 checkGLcall("glBindBuffer");
1524 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1525 gl_format
, gl_type
, NULL
);
1526 checkGLcall("glGetTexImage");
1528 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1529 checkGLcall("glBindBuffer");
1533 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1534 gl_format
, gl_type
, mem
);
1535 checkGLcall("glGetTexImage");
1538 if (surface
->container
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
1540 const BYTE
*src_data
;
1544 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1545 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1546 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1548 * We're doing this...
1550 * instead of boxing the texture :
1551 * |<-texture width ->| -->pow2width| /\
1552 * |111111111111111111| | |
1553 * |222 Texture 222222| boxed empty | texture height
1554 * |3333 Data 33333333| | |
1555 * |444444444444444444| | \/
1556 * ----------------------------------- |
1557 * | boxed empty | boxed empty | pow2height
1559 * -----------------------------------
1562 * we're repacking the data to the expected texture width
1564 * |<-texture width ->| -->pow2width| /\
1565 * |111111111111111111222222222222222| |
1566 * |222333333333333333333444444444444| texture height
1570 * | empty | pow2height
1572 * -----------------------------------
1576 * |<-texture width ->| /\
1577 * |111111111111111111|
1578 * |222222222222222222|texture height
1579 * |333333333333333333|
1580 * |444444444444444444| \/
1581 * --------------------
1583 * This also means that any references to surface memory should work with the data as if it were a
1584 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1586 * internally the texture is still stored in a boxed format so any references to textureName will
1587 * get a boxed texture with width pow2width and not a texture of width resource.width.
1589 * Performance should not be an issue, because applications normally do not lock the surfaces when
1590 * rendering. If an app does, the WINED3D_TEXTURE_DYNAMIC_MAP flag will kick in and the memory copy
1591 * won't be released, and doesn't have to be re-read. */
1593 dst_data
= data
.addr
;
1594 #if defined(STAGING_CSMT)
1595 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_row_pitch
);
1596 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1598 memcpy(dst_data
, src_data
, dst_row_pitch
);
1599 src_data
+= src_pitch
;
1600 #else /* STAGING_CSMT */
1601 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch
, dst_row_pitch
);
1602 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1604 memcpy(dst_data
, src_data
, dst_row_pitch
);
1605 src_data
+= src_row_pitch
;
1606 #endif /* STAGING_CSMT */
1607 dst_data
+= dst_row_pitch
;
1610 HeapFree(GetProcessHeap(), 0, mem
);
1615 /* This call just uploads data, the caller is responsible for binding the
1616 * correct texture. */
1617 /* Context activation is done by the caller. */
1618 void wined3d_surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1619 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1620 BOOL srgb
, const struct wined3d_const_bo_address
*data
)
1622 UINT update_w
= src_rect
->right
- src_rect
->left
;
1623 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1625 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1626 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1627 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1629 if (surface
->resource
.map_count
)
1631 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1632 surface
->container
->flags
|= WINED3D_TEXTURE_PIN_SYSMEM
;
1635 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_HEIGHT_SCALE
)
1637 update_h
*= format
->height_scale
.numerator
;
1638 update_h
/= format
->height_scale
.denominator
;
1641 if (data
->buffer_object
)
1643 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, data
->buffer_object
));
1644 checkGLcall("glBindBuffer");
1647 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_COMPRESSED
)
1649 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1650 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1651 const BYTE
*addr
= data
->addr
;
1654 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1655 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1658 internal
= format
->glGammaInternal
;
1659 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1660 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
1661 internal
= format
->rtInternal
;
1663 internal
= format
->glInternal
;
1665 TRACE("glCompressedTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, "
1666 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1667 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1669 if (row_length
== src_pitch
)
1671 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1672 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1678 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1679 * can't use the unpack row length like for glTexSubImage2D. */
1680 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1682 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1683 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1684 y
+= format
->block_height
;
1688 checkGLcall("glCompressedTexSubImage2D");
1692 const BYTE
*addr
= data
->addr
;
1694 addr
+= src_rect
->top
* src_pitch
;
1695 addr
+= src_rect
->left
* format
->byte_count
;
1697 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1698 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1699 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1701 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1702 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1703 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1704 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1705 checkGLcall("glTexSubImage2D");
1708 if (data
->buffer_object
)
1710 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
1711 checkGLcall("glBindBuffer");
1714 if (wined3d_settings
.strict_draw_ordering
)
1715 gl_info
->gl_ops
.gl
.p_glFlush();
1717 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1719 struct wined3d_device
*device
= surface
->resource
.device
;
1722 for (i
= 0; i
< device
->context_count
; ++i
)
1724 context_surface_update(device
->contexts
[i
], surface
);
1729 #if defined(STAGING_CSMT)
1730 static BOOL
surface_check_block_align(struct wined3d_surface
*surface
, const struct wined3d_box
*box
)
1732 if ((box
->left
>= box
->right
)
1733 || (box
->top
>= box
->bottom
)
1734 || (box
->right
> surface
->resource
.width
)
1735 || (box
->bottom
> surface
->resource
.height
))
1738 return wined3d_resource_check_block_align(&surface
->resource
, box
);
1741 static BOOL
surface_check_block_align_rect(struct wined3d_surface
*surface
, const RECT
*rect
)
1743 struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
1745 return surface_check_block_align(surface
, &box
);
1746 #else /* STAGING_CSMT */
1747 static BOOL
surface_check_block_align_rect(struct wined3d_surface
*surface
, const RECT
*rect
)
1749 struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
1751 return wined3d_texture_check_block_align(surface
->container
, surface
->texture_level
, &box
);
1752 #endif /* STAGING_CSMT */
1755 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1756 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1758 unsigned int src_row_pitch
, src_slice_pitch
;
1759 const struct wined3d_format
*src_format
;
1760 const struct wined3d_format
*dst_format
;
1761 unsigned int src_fmt_flags
, dst_fmt_flags
;
1762 const struct wined3d_gl_info
*gl_info
;
1763 struct wined3d_context
*context
;
1764 struct wined3d_bo_address data
;
1765 UINT update_w
, update_h
;
1770 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1771 dst_surface
, wine_dbgstr_point(dst_point
),
1772 src_surface
, wine_dbgstr_rect(src_rect
));
1774 src_format
= src_surface
->resource
.format
;
1775 dst_format
= dst_surface
->resource
.format
;
1776 src_fmt_flags
= src_surface
->container
->resource
.format_flags
;
1777 dst_fmt_flags
= dst_surface
->container
->resource
.format_flags
;
1779 if (src_format
->id
!= dst_format
->id
)
1781 WARN("Source and destination surfaces should have the same format.\n");
1782 return WINED3DERR_INVALIDCALL
;
1791 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1793 WARN("Invalid destination point.\n");
1794 return WINED3DERR_INVALIDCALL
;
1801 r
.right
= src_surface
->resource
.width
;
1802 r
.bottom
= src_surface
->resource
.height
;
1805 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
1806 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
1808 WARN("Invalid source rectangle.\n");
1809 return WINED3DERR_INVALIDCALL
;
1812 dst_w
= dst_surface
->resource
.width
;
1813 dst_h
= dst_surface
->resource
.height
;
1815 update_w
= src_rect
->right
- src_rect
->left
;
1816 update_h
= src_rect
->bottom
- src_rect
->top
;
1818 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1819 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1821 WARN("Destination out of bounds.\n");
1822 return WINED3DERR_INVALIDCALL
;
1825 if ((src_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align_rect(src_surface
, src_rect
))
1827 WARN("Source rectangle not block-aligned.\n");
1828 return WINED3DERR_INVALIDCALL
;
1831 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1832 if ((dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align_rect(dst_surface
, &dst_rect
))
1834 WARN("Destination rectangle not block-aligned.\n");
1835 return WINED3DERR_INVALIDCALL
;
1838 #if defined(STAGING_CSMT)
1839 /* Use surface_cpu_blt() instead of uploading directly if we need
1840 * conversion. Avoid calling wined3d_surface_blt() since that goes
1841 * through the CS. */
1842 if (dst_format
->convert
|| wined3d_format_get_color_key_conversion(dst_surface
->container
, FALSE
))
1843 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1844 #else /* STAGING_CSMT */
1845 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1846 if (dst_format
->convert
|| wined3d_format_get_color_key_conversion(dst_surface
->container
, FALSE
))
1847 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1848 #endif /* STAGING_CSMT */
1850 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
1851 gl_info
= context
->gl_info
;
1853 /* Only load the surface for partial updates. For newly allocated texture
1854 * the texture wouldn't be the current location, and we'd upload zeroes
1855 * just to overwrite them again. */
1856 if (update_w
== dst_w
&& update_h
== dst_h
)
1857 wined3d_texture_prepare_texture(dst_surface
->container
, context
, FALSE
);
1859 #if defined(STAGING_CSMT)
1860 wined3d_resource_load_location(&dst_surface
->resource
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
1861 wined3d_texture_bind_and_dirtify(dst_surface
->container
, context
, FALSE
);
1863 wined3d_resource_get_memory(&src_surface
->resource
, src_surface
->resource
.locations
, &data
);
1864 wined3d_resource_get_pitch(&src_surface
->resource
, &src_row_pitch
, &src_slice_pitch
);
1866 wined3d_surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
,
1867 src_row_pitch
, dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1869 context_release(context
);
1871 wined3d_resource_validate_location(&dst_surface
->resource
, WINED3D_LOCATION_TEXTURE_RGB
);
1872 wined3d_resource_invalidate_location(&dst_surface
->resource
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1873 #else /* STAGING_CSMT */
1874 surface_load_location(dst_surface
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
1875 wined3d_texture_bind_and_dirtify(dst_surface
->container
, context
, FALSE
);
1877 surface_get_memory(src_surface
, &data
, src_surface
->locations
);
1878 wined3d_texture_get_pitch(src_surface
->container
, src_surface
->texture_level
, &src_row_pitch
, &src_slice_pitch
);
1880 wined3d_surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
,
1881 src_row_pitch
, dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1883 context_release(context
);
1885 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1886 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1887 #endif /* STAGING_CSMT */
1892 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1893 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1894 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1895 /* Context activation is done by the caller. */
1896 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1898 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
1899 struct wined3d_renderbuffer_entry
*entry
;
1900 GLuint renderbuffer
= 0;
1901 unsigned int src_width
, src_height
;
1902 unsigned int width
, height
;
1904 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
1906 width
= rt
->pow2Width
;
1907 height
= rt
->pow2Height
;
1911 width
= surface
->pow2Width
;
1912 height
= surface
->pow2Height
;
1915 src_width
= surface
->pow2Width
;
1916 src_height
= surface
->pow2Height
;
1918 /* A depth stencil smaller than the render target is not valid */
1919 if (width
> src_width
|| height
> src_height
) return;
1921 /* Remove any renderbuffer set if the sizes match */
1922 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1923 || (width
== src_width
&& height
== src_height
))
1925 surface
->current_renderbuffer
= NULL
;
1929 /* Look if we've already got a renderbuffer of the correct dimensions */
1930 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1932 if (entry
->width
== width
&& entry
->height
== height
)
1934 renderbuffer
= entry
->id
;
1935 surface
->current_renderbuffer
= entry
;
1942 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
1943 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
1944 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
1945 surface
->resource
.format
->glInternal
, width
, height
);
1947 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
1948 entry
->width
= width
;
1949 entry
->height
= height
;
1950 entry
->id
= renderbuffer
;
1951 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
1953 surface
->current_renderbuffer
= entry
;
1956 checkGLcall("set_compatible_renderbuffer");
1959 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
1961 const struct wined3d_swapchain
*swapchain
= surface
->container
->swapchain
;
1963 TRACE("surface %p.\n", surface
);
1967 ERR("Surface %p is not on a swapchain.\n", surface
);
1971 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
->container
)
1973 if (swapchain
->render_to_fbo
)
1975 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1976 return GL_COLOR_ATTACHMENT0
;
1978 TRACE("Returning GL_BACK\n");
1981 else if (surface
->container
== swapchain
->front_buffer
)
1983 TRACE("Returning GL_FRONT\n");
1987 FIXME("Higher back buffer, returning GL_BACK\n");
1991 /* Context activation is done by the caller. */
1992 void surface_load(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
1994 DWORD location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
1996 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
1998 if (surface
->resource
.pool
== WINED3D_POOL_SCRATCH
)
1999 ERR("Not supported on scratch surfaces.\n");
2001 #if defined(STAGING_CSMT)
2002 if (surface
->resource
.locations
& location
)
2004 TRACE("surface is already in texture\n");
2007 TRACE("Reloading because surface is dirty.\n");
2009 wined3d_resource_load_location(&surface
->resource
, context
, location
);
2010 #else /* STAGING_CSMT */
2011 if (surface
->locations
& location
)
2013 TRACE("surface is already in texture\n");
2016 TRACE("Reloading because surface is dirty.\n");
2018 surface_load_location(surface
, context
, location
);
2019 #endif /* STAGING_CSMT */
2020 surface_evict_sysmem(surface
);
2023 /* See also float_16_to_32() in wined3d_private.h */
2024 static inline unsigned short float_32_to_16(const float *in
)
2027 float tmp
= fabsf(*in
);
2028 unsigned int mantissa
;
2031 /* Deal with special numbers */
2037 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2039 if (tmp
< (float)(1u << 10))
2045 } while (tmp
< (float)(1u << 10));
2047 else if (tmp
>= (float)(1u << 11))
2053 } while (tmp
>= (float)(1u << 11));
2056 mantissa
= (unsigned int)tmp
;
2057 if (tmp
- mantissa
>= 0.5f
)
2058 ++mantissa
; /* Round to nearest, away from zero. */
2060 exp
+= 10; /* Normalize the mantissa. */
2061 exp
+= 15; /* Exponent is encoded with excess 15. */
2063 if (exp
> 30) /* too big */
2065 ret
= 0x7c00; /* INF */
2069 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2072 mantissa
= mantissa
>> 1;
2075 ret
= mantissa
& 0x3ff;
2079 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2082 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2086 #if defined(STAGING_CSMT)
2087 HRESULT
wined3d_surface_update_desc(struct wined3d_surface
*surface
,
2088 const struct wined3d_gl_info
*gl_info
, void *mem
, unsigned int pitch
)
2089 #else /* STAGING_CSMT */
2090 HRESULT
wined3d_surface_update_desc(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
2091 #endif /* STAGING_CSMT */
2093 struct wined3d_resource
*texture_resource
= &surface
->container
->resource
;
2094 unsigned int width
, height
;
2095 BOOL create_dib
= FALSE
;
2096 DWORD valid_location
= 0;
2099 if (surface
->flags
& SFLAG_DIBSECTION
)
2101 DeleteDC(surface
->hDC
);
2102 DeleteObject(surface
->dib
.DIBsection
);
2103 #if defined(STAGING_CSMT)
2104 surface
->resource
.bitmap_data
= NULL
;
2105 surface
->flags
&= ~SFLAG_DIBSECTION
;
2109 surface
->resource
.locations
= 0;
2110 wined3d_resource_free_sysmem(&surface
->resource
);
2111 surface
->resource
.map_heap_memory
= NULL
;
2112 #else /* STAGING_CSMT */
2113 surface
->dib
.bitmap_data
= NULL
;
2114 surface
->flags
&= ~SFLAG_DIBSECTION
;
2118 surface
->locations
= 0;
2119 wined3d_resource_free_sysmem(&surface
->resource
);
2120 #endif /* STAGING_CSMT */
2122 width
= texture_resource
->width
;
2123 height
= texture_resource
->height
;
2124 surface
->resource
.width
= width
;
2125 surface
->resource
.height
= height
;
2126 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
2127 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
2129 surface
->pow2Width
= width
;
2130 surface
->pow2Height
= height
;
2134 surface
->pow2Width
= surface
->pow2Height
= 1;
2135 while (surface
->pow2Width
< width
)
2136 surface
->pow2Width
<<= 1;
2137 while (surface
->pow2Height
< height
)
2138 surface
->pow2Height
<<= 1;
2141 #if defined(STAGING_CSMT)
2142 if ((surface
->resource
.user_memory
= mem
))
2144 surface
->resource
.map_binding
= WINED3D_LOCATION_USER_MEMORY
;
2145 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
2147 surface
->resource
.custom_row_pitch
= pitch
;
2148 surface
->resource
.custom_slice_pitch
= pitch
* surface
->resource
.height
;
2149 surface
->resource
.format
= texture_resource
->format
;
2150 surface
->resource
.multisample_type
= texture_resource
->multisample_type
;
2151 surface
->resource
.multisample_quality
= texture_resource
->multisample_quality
;
2152 if (surface
->resource
.custom_row_pitch
)
2154 surface
->resource
.size
= height
* surface
->resource
.custom_row_pitch
;
2158 /* User memory surfaces don't have the regular surface alignment. */
2159 surface
->resource
.size
= wined3d_format_calculate_size(texture_resource
->format
,
2160 1, width
, height
, 1);
2161 surface
->resource
.custom_row_pitch
= wined3d_format_calculate_pitch(texture_resource
->format
, width
);
2163 #else /* STAGING_CSMT */
2164 if (surface
->container
->user_memory
)
2166 surface
->resource
.map_binding
= WINED3D_LOCATION_USER_MEMORY
;
2167 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
2169 surface
->resource
.format
= texture_resource
->format
;
2170 surface
->resource
.multisample_type
= texture_resource
->multisample_type
;
2171 surface
->resource
.multisample_quality
= texture_resource
->multisample_quality
;
2172 surface
->resource
.size
= surface
->container
->slice_pitch
;
2173 #endif /* STAGING_CSMT */
2175 /* The format might be changed to a format that needs conversion.
2176 * If the surface didn't use PBOs previously but could now, don't
2177 * change it - whatever made us not use PBOs might come back, e.g.
2179 if (surface
->resource
.map_binding
== WINED3D_LOCATION_BUFFER
&& !surface_use_pbo(surface
))
2180 surface
->resource
.map_binding
= create_dib
? WINED3D_LOCATION_DIB
: WINED3D_LOCATION_SYSMEM
;
2184 if (FAILED(hr
= surface_create_dib_section(surface
)))
2186 ERR("Failed to create dib section, hr %#x.\n", hr
);
2189 if (!valid_location
)
2190 valid_location
= WINED3D_LOCATION_DIB
;
2193 if (!valid_location
)
2195 #if defined(STAGING_CSMT)
2196 wined3d_resource_prepare_system_memory(&surface
->resource
);
2197 valid_location
= WINED3D_LOCATION_SYSMEM
;
2200 wined3d_resource_validate_location(&surface
->resource
, valid_location
);
2201 #else /* STAGING_CSMT */
2202 surface_prepare_system_memory(surface
);
2203 valid_location
= WINED3D_LOCATION_SYSMEM
;
2206 surface_validate_location(surface
, valid_location
);
2207 #endif /* STAGING_CSMT */
2212 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
2213 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2215 unsigned short *dst_s
;
2219 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2221 for (y
= 0; y
< h
; ++y
)
2223 src_f
= (const float *)(src
+ y
* pitch_in
);
2224 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
2225 for (x
= 0; x
< w
; ++x
)
2227 dst_s
[x
] = float_32_to_16(src_f
+ x
);
2232 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2233 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2235 static const unsigned char convert_5to8
[] =
2237 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2238 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2239 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2240 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2242 static const unsigned char convert_6to8
[] =
2244 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2245 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2246 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2247 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2248 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2249 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2250 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2251 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2255 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2257 for (y
= 0; y
< h
; ++y
)
2259 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
2260 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2261 for (x
= 0; x
< w
; ++x
)
2263 WORD pixel
= src_line
[x
];
2264 dst_line
[x
] = 0xff000000u
2265 | convert_5to8
[(pixel
& 0xf800u
) >> 11] << 16
2266 | convert_6to8
[(pixel
& 0x07e0u
) >> 5] << 8
2267 | convert_5to8
[(pixel
& 0x001fu
)];
2272 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2273 * in both cases we're just setting the X / Alpha channel to 0xff. */
2274 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2275 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2279 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2281 for (y
= 0; y
< h
; ++y
)
2283 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
2284 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2286 for (x
= 0; x
< w
; ++x
)
2288 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
2293 static inline BYTE
cliptobyte(int x
)
2295 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
2298 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2299 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2301 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2304 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2306 for (y
= 0; y
< h
; ++y
)
2308 const BYTE
*src_line
= src
+ y
* pitch_in
;
2309 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2310 for (x
= 0; x
< w
; ++x
)
2312 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2313 * C = Y - 16; D = U - 128; E = V - 128;
2314 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2315 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2316 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2317 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2318 * U and V are shared between the pixels. */
2319 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2321 d
= (int) src_line
[1] - 128;
2322 e
= (int) src_line
[3] - 128;
2324 g2
= - 100 * d
- 208 * e
+ 128;
2327 c2
= 298 * ((int) src_line
[0] - 16);
2328 dst_line
[x
] = 0xff000000
2329 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
2330 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
2331 | cliptobyte((c2
+ b2
) >> 8); /* blue */
2332 /* Scale RGB values to 0..255 range,
2333 * then clip them if still not in range (may be negative),
2334 * then shift them within DWORD if necessary. */
2340 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
2341 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2344 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2346 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
2348 for (y
= 0; y
< h
; ++y
)
2350 const BYTE
*src_line
= src
+ y
* pitch_in
;
2351 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
2352 for (x
= 0; x
< w
; ++x
)
2354 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2355 * C = Y - 16; D = U - 128; E = V - 128;
2356 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2357 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2358 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2359 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2360 * U and V are shared between the pixels. */
2361 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2363 d
= (int) src_line
[1] - 128;
2364 e
= (int) src_line
[3] - 128;
2366 g2
= - 100 * d
- 208 * e
+ 128;
2369 c2
= 298 * ((int) src_line
[0] - 16);
2370 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
2371 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
2372 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
2373 /* Scale RGB values to 0..255 range,
2374 * then clip them if still not in range (may be negative),
2375 * then shift them within DWORD if necessary. */
2381 static void convert_dxt1_a8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2382 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2384 wined3d_dxt1_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8A8_UNORM
, w
, h
);
2387 static void convert_dxt1_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2388 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2390 wined3d_dxt1_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8X8_UNORM
, w
, h
);
2393 static void convert_dxt1_a4r4g4b4(const BYTE
*src
, BYTE
*dst
,
2394 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2396 wined3d_dxt1_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B4G4R4A4_UNORM
, w
, h
);
2399 static void convert_dxt1_x4r4g4b4(const BYTE
*src
, BYTE
*dst
,
2400 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2402 wined3d_dxt1_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B4G4R4X4_UNORM
, w
, h
);
2405 static void convert_dxt1_a1r5g5b5(const BYTE
*src
, BYTE
*dst
,
2406 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2408 wined3d_dxt1_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B5G5R5A1_UNORM
, w
, h
);
2411 static void convert_dxt1_x1r5g5b5(const BYTE
*src
, BYTE
*dst
,
2412 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2414 wined3d_dxt1_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B5G5R5X1_UNORM
, w
, h
);
2417 static void convert_dxt3_a8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2418 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2420 wined3d_dxt3_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8A8_UNORM
, w
, h
);
2423 static void convert_dxt3_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2424 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2426 wined3d_dxt3_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8X8_UNORM
, w
, h
);
2429 static void convert_dxt3_a4r4g4b4(const BYTE
*src
, BYTE
*dst
,
2430 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2432 wined3d_dxt3_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B4G4R4A4_UNORM
, w
, h
);
2435 static void convert_dxt3_x4r4g4b4(const BYTE
*src
, BYTE
*dst
,
2436 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2438 wined3d_dxt3_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B4G4R4X4_UNORM
, w
, h
);
2441 static void convert_dxt5_a8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2442 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2444 wined3d_dxt5_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8A8_UNORM
, w
, h
);
2447 static void convert_dxt5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2448 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2450 wined3d_dxt5_decode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8X8_UNORM
, w
, h
);
2453 static void convert_a8r8g8b8_dxt1(const BYTE
*src
, BYTE
*dst
,
2454 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2456 wined3d_dxt1_encode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8A8_UNORM
, w
, h
);
2459 static void convert_x8r8g8b8_dxt1(const BYTE
*src
, BYTE
*dst
,
2460 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2462 wined3d_dxt1_encode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8X8_UNORM
, w
, h
);
2465 static void convert_a1r5g5b5_dxt1(const BYTE
*src
, BYTE
*dst
,
2466 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2468 wined3d_dxt1_encode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B5G5R5A1_UNORM
, w
, h
);
2471 static void convert_x1r5g5b5_dxt1(const BYTE
*src
, BYTE
*dst
,
2472 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2474 wined3d_dxt1_encode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B5G5R5X1_UNORM
, w
, h
);
2477 static void convert_a8r8g8b8_dxt3(const BYTE
*src
, BYTE
*dst
,
2478 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2480 wined3d_dxt3_encode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8A8_UNORM
, w
, h
);
2483 static void convert_x8r8g8b8_dxt3(const BYTE
*src
, BYTE
*dst
,
2484 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2486 wined3d_dxt3_encode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8X8_UNORM
, w
, h
);
2489 static void convert_a8r8g8b8_dxt5(const BYTE
*src
, BYTE
*dst
,
2490 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2492 wined3d_dxt5_encode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8A8_UNORM
, w
, h
);
2495 static void convert_x8r8g8b8_dxt5(const BYTE
*src
, BYTE
*dst
,
2496 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2498 wined3d_dxt5_encode(src
, dst
, pitch_in
, pitch_out
, WINED3DFMT_B8G8R8X8_UNORM
, w
, h
);
2501 struct d3dfmt_converter_desc
2503 enum wined3d_format_id from
, to
;
2504 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
2507 static const struct d3dfmt_converter_desc converters
[] =
2509 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
2510 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
2511 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2512 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2513 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
2514 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
2517 static const struct d3dfmt_converter_desc dxtn_converters
[] =
2520 {WINED3DFMT_DXT1
, WINED3DFMT_B8G8R8A8_UNORM
, convert_dxt1_a8r8g8b8
},
2521 {WINED3DFMT_DXT1
, WINED3DFMT_B8G8R8X8_UNORM
, convert_dxt1_x8r8g8b8
},
2522 {WINED3DFMT_DXT1
, WINED3DFMT_B4G4R4A4_UNORM
, convert_dxt1_a4r4g4b4
},
2523 {WINED3DFMT_DXT1
, WINED3DFMT_B4G4R4X4_UNORM
, convert_dxt1_x4r4g4b4
},
2524 {WINED3DFMT_DXT1
, WINED3DFMT_B5G5R5A1_UNORM
, convert_dxt1_a1r5g5b5
},
2525 {WINED3DFMT_DXT1
, WINED3DFMT_B5G5R5X1_UNORM
, convert_dxt1_x1r5g5b5
},
2526 {WINED3DFMT_DXT3
, WINED3DFMT_B8G8R8A8_UNORM
, convert_dxt3_a8r8g8b8
},
2527 {WINED3DFMT_DXT3
, WINED3DFMT_B8G8R8X8_UNORM
, convert_dxt3_x8r8g8b8
},
2528 {WINED3DFMT_DXT3
, WINED3DFMT_B4G4R4A4_UNORM
, convert_dxt3_a4r4g4b4
},
2529 {WINED3DFMT_DXT3
, WINED3DFMT_B4G4R4X4_UNORM
, convert_dxt3_x4r4g4b4
},
2530 {WINED3DFMT_DXT5
, WINED3DFMT_B8G8R8A8_UNORM
, convert_dxt5_a8r8g8b8
},
2531 {WINED3DFMT_DXT5
, WINED3DFMT_B8G8R8X8_UNORM
, convert_dxt5_x8r8g8b8
},
2534 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_DXT1
, convert_a8r8g8b8_dxt1
},
2535 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_DXT1
, convert_x8r8g8b8_dxt1
},
2536 {WINED3DFMT_B5G5R5A1_UNORM
, WINED3DFMT_DXT1
, convert_a1r5g5b5_dxt1
},
2537 {WINED3DFMT_B5G5R5X1_UNORM
, WINED3DFMT_DXT1
, convert_x1r5g5b5_dxt1
},
2538 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_DXT3
, convert_a8r8g8b8_dxt3
},
2539 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_DXT3
, convert_x8r8g8b8_dxt3
},
2540 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_DXT5
, convert_a8r8g8b8_dxt5
},
2541 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_DXT5
, convert_x8r8g8b8_dxt5
}
2544 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
2545 enum wined3d_format_id to
)
2549 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
2551 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
2552 return &converters
[i
];
2555 for (i
= 0; i
< (sizeof(dxtn_converters
) / sizeof(*dxtn_converters
)); ++i
)
2557 if (dxtn_converters
[i
].from
== from
&& dxtn_converters
[i
].to
== to
)
2558 return wined3d_dxtn_supported() ? &dxtn_converters
[i
] : NULL
;
2564 static struct wined3d_texture
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
2566 #if defined(STAGING_CSMT)
2567 void *dst_data
= NULL
, *src_data
= NULL
;
2568 UINT src_row_pitch
, src_slice_pitch
, dst_row_pitch
, dst_slice_pitch
;
2569 const struct d3dfmt_converter_desc
*conv
;
2570 struct wined3d_texture
*ret
= NULL
;
2571 struct wined3d_resource_desc desc
;
2572 struct wined3d_surface
*dst
;
2573 struct wined3d_context
*context
= NULL
;
2574 struct wined3d_device
*device
= source
->resource
.device
;
2575 #else /* STAGING_CSMT */
2576 struct wined3d_map_desc src_map
, dst_map
;
2577 const struct d3dfmt_converter_desc
*conv
;
2578 struct wined3d_texture
*ret
= NULL
;
2579 struct wined3d_resource_desc desc
;
2580 struct wined3d_surface
*dst
;
2581 #endif /* STAGING_CSMT */
2583 conv
= find_converter(source
->resource
.format
->id
, to_fmt
);
2586 FIXME("Cannot find a conversion function from format %s to %s.\n",
2587 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
2591 /* FIXME: Multisampled conversion? */
2592 wined3d_resource_get_desc(&source
->resource
, &desc
);
2593 desc
.resource_type
= WINED3D_RTYPE_TEXTURE_2D
;
2594 desc
.format
= to_fmt
;
2596 desc
.pool
= WINED3D_POOL_SCRATCH
;
2597 if (FAILED(wined3d_texture_create(source
->resource
.device
, &desc
, 1,
2598 WINED3D_TEXTURE_CREATE_MAPPABLE
| WINED3D_TEXTURE_CREATE_DISCARD
,
2599 NULL
, NULL
, &wined3d_null_parent_ops
, &ret
)))
2601 ERR("Failed to create a destination surface for conversion.\n");
2604 dst
= surface_from_resource(wined3d_texture_get_sub_resource(ret
, 0));
2606 #if defined(STAGING_CSMT)
2607 wined3d_resource_get_pitch(&source
->resource
, &src_row_pitch
, &src_slice_pitch
);
2608 wined3d_resource_get_pitch(&ret
->resource
, &dst_row_pitch
, &dst_slice_pitch
);
2610 if (device
->d3d_initialized
)
2611 context
= context_acquire(device
, NULL
);
2613 wined3d_resource_load_location(&source
->resource
, context
, source
->resource
.map_binding
);
2614 src_data
= wined3d_resource_get_map_ptr(&source
->resource
, context
, WINED3D_MAP_READONLY
);
2618 if (!wined3d_resource_prepare_map_memory(&dst
->resource
, context
))
2620 dst_data
= wined3d_resource_get_map_ptr(&dst
->resource
, context
, 0);
2624 conv
->convert(src_data
, dst_data
, src_row_pitch
, dst_row_pitch
,
2625 source
->resource
.width
, source
->resource
.height
);
2627 wined3d_resource_release_map_ptr(&dst
->resource
, context
);
2628 wined3d_resource_release_map_ptr(&source
->resource
, context
);
2631 context_release(context
);
2636 ERR("Surface conversion failed.\n");
2639 wined3d_resource_release_map_ptr(&source
->resource
, context
);
2641 wined3d_resource_release_map_ptr(&ret
->resource
, context
);
2643 wined3d_texture_decref(ret
);
2645 context_release(context
);
2647 #else /* STAGING_CSMT */
2648 memset(&src_map
, 0, sizeof(src_map
));
2649 memset(&dst_map
, 0, sizeof(dst_map
));
2651 if (FAILED(wined3d_surface_map(source
, &src_map
, NULL
, WINED3D_MAP_READONLY
)))
2653 ERR("Failed to lock the source surface.\n");
2654 wined3d_texture_decref(ret
);
2657 if (FAILED(wined3d_surface_map(dst
, &dst_map
, NULL
, 0)))
2659 ERR("Failed to lock the destination surface.\n");
2660 wined3d_surface_unmap(source
);
2661 wined3d_texture_decref(ret
);
2665 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
2666 source
->resource
.width
, source
->resource
.height
);
2668 wined3d_surface_unmap(dst
);
2669 wined3d_surface_unmap(source
);
2672 #endif /* STAGING_CSMT */
2675 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
2676 unsigned int bpp
, UINT pitch
, DWORD color
)
2683 #define COLORFILL_ROW(type) \
2685 type *d = (type *)buf; \
2686 for (x = 0; x < width; ++x) \
2687 d[x] = (type)color; \
2693 COLORFILL_ROW(BYTE
);
2697 COLORFILL_ROW(WORD
);
2703 for (x
= 0; x
< width
; ++x
, d
+= 3)
2705 d
[0] = (color
) & 0xff;
2706 d
[1] = (color
>> 8) & 0xff;
2707 d
[2] = (color
>> 16) & 0xff;
2712 COLORFILL_ROW(DWORD
);
2716 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
2717 return WINED3DERR_NOTAVAILABLE
;
2720 #undef COLORFILL_ROW
2722 /* Now copy first row. */
2724 for (y
= 1; y
< height
; ++y
)
2727 memcpy(buf
, first
, width
* bpp
);
2733 HRESULT
wined3d_surface_unmap(struct wined3d_surface
*surface
)
2735 #if defined(STAGING_CSMT)
2737 TRACE("surface %p.\n", surface
);
2739 hr
= wined3d_resource_unmap(&surface
->resource
);
2743 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
2746 #else /* STAGING_CSMT */
2747 TRACE("surface %p.\n", surface
);
2749 if (!surface
->resource
.map_count
)
2751 WARN("Trying to unmap unmapped surface.\n");
2752 return WINEDDERR_NOTLOCKED
;
2754 --surface
->resource
.map_count
;
2756 surface
->surface_ops
->surface_unmap(surface
);
2759 #endif /* STAGING_CSMT */
2762 HRESULT
wined3d_surface_map(struct wined3d_surface
*surface
, struct wined3d_map_desc
*map_desc
,
2763 const struct wined3d_box
*box
, DWORD flags
)
2765 const struct wined3d_format
*format
= surface
->resource
.format
;
2766 unsigned int fmt_flags
= surface
->container
->resource
.format_flags
;
2767 #if defined(STAGING_CSMT)
2769 if ((fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && box
2770 && !surface_check_block_align(surface
, box
))
2771 #else /* STAGING_CSMT */
2772 struct wined3d_device
*device
= surface
->resource
.device
;
2773 struct wined3d_context
*context
;
2774 const struct wined3d_gl_info
*gl_info
;
2777 TRACE("surface %p, map_desc %p, box %s, flags %#x.\n",
2778 surface
, map_desc
, debug_box(box
), flags
);
2780 if (surface
->resource
.map_count
)
2782 WARN("Surface is already mapped.\n");
2783 return WINED3DERR_INVALIDCALL
;
2786 if ((fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && box
2787 && !wined3d_texture_check_block_align(surface
->container
, surface
->texture_level
, box
))
2788 #endif /* STAGING_CSMT */
2790 WARN("Map box %s is misaligned for %ux%u blocks.\n",
2791 debug_box(box
), format
->block_width
, format
->block_height
);
2793 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
2794 return WINED3DERR_INVALIDCALL
;
2797 #if !defined(STAGING_CSMT)
2798 ++surface
->resource
.map_count
;
2800 if (!(surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
2801 WARN("Trying to lock unlockable surface.\n");
2803 #endif /* STAGING_CSMT */
2804 /* Performance optimization: Count how often a surface is mapped, if it is
2805 * mapped regularly do not throw away the system memory copy. This avoids
2806 * the need to download the surface from OpenGL all the time. The surface
2807 * is still downloaded if the OpenGL texture is changed. Note that this
2808 * only really makes sense for managed textures.*/
2809 if (!(surface
->container
->flags
& WINED3D_TEXTURE_DYNAMIC_MAP
)
2810 && surface
->resource
.map_binding
== WINED3D_LOCATION_SYSMEM
)
2812 if (++surface
->lockCount
> MAXLOCKCOUNT
)
2814 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
2815 surface
->container
->flags
|= WINED3D_TEXTURE_DYNAMIC_MAP
;
2819 #if defined(STAGING_CSMT)
2822 surface
->lockedRect
.left
= box
->left
;
2823 surface
->lockedRect
.top
= box
->top
;
2824 surface
->lockedRect
.right
= box
->right
;
2825 surface
->lockedRect
.bottom
= box
->bottom
;
2829 surface
->lockedRect
.left
= 0;
2830 surface
->lockedRect
.top
= 0;
2831 surface
->lockedRect
.right
= surface
->resource
.width
;
2832 surface
->lockedRect
.bottom
= surface
->resource
.height
;
2835 return wined3d_resource_map(&surface
->resource
, map_desc
, box
, flags
);
2838 void wined3d_surface_getdc_cs(struct wined3d_surface
*surface
)
2841 struct wined3d_device
*device
= surface
->resource
.device
;
2842 struct wined3d_context
*context
= NULL
;
2844 if (device
->d3d_initialized
)
2845 context
= context_acquire(device
, NULL
);
2847 /* Create a DIB section if there isn't a dc yet. */
2850 if (FAILED(hr
= surface_create_dib_section(surface
)))
2853 context_release(context
);
2856 if (!(surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
2857 || surface
->container
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
2858 || surface
->resource
.buffer
))
2859 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
2862 wined3d_resource_load_location(&surface
->resource
, context
, WINED3D_LOCATION_DIB
);
2863 wined3d_resource_invalidate_location(&surface
->resource
, ~WINED3D_LOCATION_DIB
);
2866 context_release(context
);
2869 void wined3d_surface_releasedc_cs(struct wined3d_surface
*surface
)
2871 if (surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
|| (surface
->container
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
2872 && surface
->resource
.map_binding
!= WINED3D_LOCATION_DIB
))
2874 /* The game Salammbo modifies the surface contents without mapping the surface between
2875 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
2876 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
2877 * Do not only copy the DIB to the map location, but also make sure the map location is
2878 * copied back to the DIB in the next getdc call.
2880 * The same consideration applies to user memory surfaces. */
2881 struct wined3d_device
*device
= surface
->resource
.device
;
2882 struct wined3d_context
*context
= NULL
;
2884 if (device
->d3d_initialized
)
2885 context
= context_acquire(device
, NULL
);
2887 wined3d_resource_load_location(&surface
->resource
, context
, surface
->resource
.map_binding
);
2888 wined3d_resource_invalidate_location(&surface
->resource
, WINED3D_LOCATION_DIB
);
2890 context_release(context
);
2894 static void read_from_framebuffer(struct wined3d_surface
*surface
,
2895 struct wined3d_context
*old_ctx
, DWORD dst_location
)
2897 struct wined3d_device
*device
= surface
->resource
.device
;
2898 const struct wined3d_gl_info
*gl_info
;
2899 struct wined3d_context
*context
= old_ctx
;
2900 struct wined3d_surface
*restore_rt
= NULL
;
2901 unsigned int row_pitch
, slice_pitch
;
2903 BYTE
*row
, *top
, *bottom
;
2905 BOOL srcIsUpsideDown
;
2906 struct wined3d_bo_address data
;
2908 wined3d_resource_get_memory(&surface
->resource
, dst_location
, &data
);
2909 #else /* STAGING_CSMT */
2910 surface_prepare_map_memory(surface
);
2911 if (flags
& WINED3D_MAP_DISCARD
)
2913 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2914 wined3d_debug_location(surface
->resource
.map_binding
));
2915 surface_validate_location(surface
, surface
->resource
.map_binding
);
2919 struct wined3d_context
*context
= NULL
;
2921 if (surface
->resource
.usage
& WINED3DUSAGE_DYNAMIC
)
2922 WARN_(d3d_perf
)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
2924 if (surface
->resource
.device
->d3d_initialized
)
2925 context
= context_acquire(surface
->resource
.device
, NULL
);
2926 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
2928 context_release(context
);
2931 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
2932 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
2934 switch (surface
->resource
.map_binding
)
2936 case WINED3D_LOCATION_SYSMEM
:
2937 base_memory
= surface
->resource
.heap_memory
;
2940 case WINED3D_LOCATION_USER_MEMORY
:
2941 base_memory
= surface
->container
->user_memory
;
2944 case WINED3D_LOCATION_DIB
:
2945 base_memory
= surface
->dib
.bitmap_data
;
2948 case WINED3D_LOCATION_BUFFER
:
2949 context
= context_acquire(device
, NULL
);
2950 gl_info
= context
->gl_info
;
2952 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
2953 base_memory
= GL_EXTCALL(glMapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_READ_WRITE
));
2954 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
2955 checkGLcall("map PBO");
2957 context_release(context
);
2961 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
2965 if (fmt_flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
2967 map_desc
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
2968 map_desc
->slice_pitch
= surface
->resource
.height
* map_desc
->row_pitch
;
2972 wined3d_texture_get_pitch(surface
->container
, surface
->texture_level
,
2973 &map_desc
->row_pitch
, &map_desc
->slice_pitch
);
2978 map_desc
->data
= base_memory
;
2979 surface
->lockedRect
.left
= 0;
2980 surface
->lockedRect
.top
= 0;
2981 surface
->lockedRect
.right
= surface
->resource
.width
;
2982 surface
->lockedRect
.bottom
= surface
->resource
.height
;
2986 if ((fmt_flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
2988 /* Compressed textures are block based, so calculate the offset of
2989 * the block that contains the top-left pixel of the locked rectangle. */
2990 map_desc
->data
= base_memory
2991 + ((box
->top
/ format
->block_height
) * map_desc
->row_pitch
)
2992 + ((box
->left
/ format
->block_width
) * format
->block_byte_count
);
2996 map_desc
->data
= base_memory
2997 + (map_desc
->row_pitch
* box
->top
)
2998 + (box
->left
* format
->byte_count
);
3000 surface
->lockedRect
.left
= box
->left
;
3001 surface
->lockedRect
.top
= box
->top
;
3002 surface
->lockedRect
.right
= box
->right
;
3003 surface
->lockedRect
.bottom
= box
->bottom
;
3006 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
3007 TRACE("Returning memory %p, pitch %u.\n", map_desc
->data
, map_desc
->row_pitch
);
3012 static void read_from_framebuffer(struct wined3d_surface
*surface
,
3013 struct wined3d_context
*old_ctx
, DWORD dst_location
)
3015 struct wined3d_device
*device
= surface
->resource
.device
;
3016 const struct wined3d_gl_info
*gl_info
;
3017 struct wined3d_context
*context
= old_ctx
;
3018 struct wined3d_surface
*restore_rt
= NULL
;
3019 unsigned int row_pitch
, slice_pitch
;
3021 BYTE
*row
, *top
, *bottom
;
3023 BOOL srcIsUpsideDown
;
3024 struct wined3d_bo_address data
;
3026 surface_get_memory(surface
, &data
, dst_location
);
3027 #endif /* STAGING_CSMT */
3029 if (surface
!= old_ctx
->current_rt
)
3031 restore_rt
= old_ctx
->current_rt
;
3032 context
= context_acquire(device
, surface
);
3035 context_apply_blit_state(context
, device
);
3036 gl_info
= context
->gl_info
;
3038 /* Select the correct read buffer, and give some debug output.
3039 * There is no need to keep track of the current read buffer or reset it, every part of the code
3040 * that reads sets the read buffer as desired.
3042 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
3044 /* Mapping the primary render target which is not on a swapchain.
3045 * Read from the back buffer. */
3046 TRACE("Mapping offscreen render target.\n");
3047 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3048 srcIsUpsideDown
= TRUE
;
3052 /* Onscreen surfaces are always part of a swapchain */
3053 GLenum buffer
= surface_get_gl_buffer(surface
);
3054 TRACE("Mapping %#x buffer.\n", buffer
);
3055 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
3056 checkGLcall("glReadBuffer");
3057 srcIsUpsideDown
= FALSE
;
3060 if (data
.buffer_object
)
3062 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
3063 checkGLcall("glBindBuffer");
3066 #if defined(STAGING_CSMT)
3067 wined3d_resource_get_pitch(&surface
->resource
, &row_pitch
, &slice_pitch
);
3068 #else /* STAGING_CSMT */
3069 wined3d_texture_get_pitch(surface
->container
, surface
->texture_level
, &row_pitch
, &slice_pitch
);
3070 #endif /* STAGING_CSMT */
3072 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3073 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, row_pitch
/ surface
->resource
.format
->byte_count
);
3074 checkGLcall("glPixelStorei");
3076 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0,
3077 surface
->resource
.width
, surface
->resource
.height
,
3078 surface
->resource
.format
->glFormat
,
3079 surface
->resource
.format
->glType
, data
.addr
);
3080 checkGLcall("glReadPixels");
3082 /* Reset previous pixel store pack state */
3083 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
3084 checkGLcall("glPixelStorei");
3086 if (!srcIsUpsideDown
)
3088 /* glReadPixels returns the image upside down, and there is no way to
3089 * prevent this. Flip the lines in software. */
3091 if (!(row
= HeapAlloc(GetProcessHeap(), 0, row_pitch
)))
3094 if (data
.buffer_object
)
3096 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
3097 checkGLcall("glMapBuffer");
3103 bottom
= mem
+ row_pitch
* (surface
->resource
.height
- 1);
3104 for (i
= 0; i
< surface
->resource
.height
/ 2; i
++)
3106 memcpy(row
, top
, row_pitch
);
3107 memcpy(top
, bottom
, row_pitch
);
3108 memcpy(bottom
, row
, row_pitch
);
3110 bottom
-= row_pitch
;
3112 HeapFree(GetProcessHeap(), 0, row
);
3114 if (data
.buffer_object
)
3115 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
3119 if (data
.buffer_object
)
3121 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
3122 checkGLcall("glBindBuffer");
3126 context_restore(context
, restore_rt
);
3129 /* Read the framebuffer contents into a texture. Note that this function
3130 * doesn't do any kind of flipping. Using this on an onscreen surface will
3131 * result in a flipped D3D texture.
3133 * Context activation is done by the caller. This function may temporarily
3134 * switch to a different context and restore the original one before return. */
3135 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
, struct wined3d_context
*old_ctx
)
3137 struct wined3d_device
*device
= surface
->resource
.device
;
3138 const struct wined3d_gl_info
*gl_info
;
3139 struct wined3d_context
*context
= old_ctx
;
3140 struct wined3d_surface
*restore_rt
= NULL
;
3142 if (old_ctx
->current_rt
!= surface
)
3144 restore_rt
= old_ctx
->current_rt
;
3145 context
= context_acquire(device
, surface
);
3148 gl_info
= context
->gl_info
;
3149 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
3151 wined3d_texture_prepare_texture(surface
->container
, context
, srgb
);
3152 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3154 TRACE("Reading back offscreen render target %p.\n", surface
);
3156 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
3157 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3159 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(surface
));
3160 checkGLcall("glReadBuffer");
3162 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
3163 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
3164 checkGLcall("glCopyTexSubImage2D");
3167 context_restore(context
, restore_rt
);
3170 static void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
3176 if (surface
->rb_multisample
)
3179 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
3180 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
3181 * to GL_NV_framebuffer_multisample_coverage.
3183 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
3184 * but it does not have an equivalent OpenGL extension. */
3186 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
3187 * as the count of advertised multisample types for the surface format. */
3188 if (surface
->resource
.multisample_type
== WINED3D_MULTISAMPLE_NON_MASKABLE
)
3190 const struct wined3d_format
*format
= surface
->resource
.format
;
3191 unsigned int i
, count
= 0;
3193 for (i
= 0; i
< sizeof(format
->multisample_types
) * 8; ++i
)
3195 if (format
->multisample_types
& 1u << i
)
3197 if (surface
->resource
.multisample_quality
== count
++)
3205 samples
= surface
->resource
.multisample_type
;
3208 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
3209 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
3210 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, samples
,
3211 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
3212 checkGLcall("glRenderbufferStorageMultisample()");
3213 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
3217 if (surface
->rb_resolved
)
3220 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
3221 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
3222 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
3223 surface
->pow2Width
, surface
->pow2Height
);
3224 checkGLcall("glRenderbufferStorage()");
3225 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
3229 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3230 * pixel copy calls. */
3231 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3232 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3234 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3235 const struct wined3d_gl_info
*gl_info
;
3237 struct wined3d_context
*context
;
3238 BOOL upsidedown
= FALSE
;
3239 RECT dst_rect
= *dst_rect_in
;
3241 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3242 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3244 if(dst_rect
.top
> dst_rect
.bottom
) {
3245 UINT tmp
= dst_rect
.bottom
;
3246 dst_rect
.bottom
= dst_rect
.top
;
3251 context
= context_acquire(device
, src_surface
);
3252 gl_info
= context
->gl_info
;
3253 context_apply_blit_state(context
, device
);
3254 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3256 /* Bind the target texture */
3257 context_bind_texture(context
, dst_surface
->container
->target
, dst_surface
->container
->texture_rgb
.name
);
3258 if (wined3d_resource_is_offscreen(&src_surface
->container
->resource
))
3260 TRACE("Reading from an offscreen target\n");
3261 upsidedown
= !upsidedown
;
3262 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3266 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3268 checkGLcall("glReadBuffer");
3270 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
3271 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
3273 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3275 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3277 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3278 ERR("Texture filtering not supported in direct blit.\n");
3280 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3281 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3283 ERR("Texture filtering not supported in direct blit\n");
3287 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3288 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3290 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3291 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3292 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
3293 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
3294 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3299 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
3300 /* I have to process this row by row to swap the image,
3301 * otherwise it would be upside down, so stretching in y direction
3302 * doesn't cost extra time
3304 * However, stretching in x direction can be avoided if not necessary
3306 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
3307 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3309 /* Well, that stuff works, but it's very slow.
3310 * find a better way instead
3314 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
3316 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3317 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
3318 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
3323 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3324 dst_rect
.left
/* x offset */, row
/* y offset */,
3325 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
3329 checkGLcall("glCopyTexSubImage2D");
3331 context_release(context
);
3333 /* The texture is now most up to date - If the surface is a render target
3334 * and has a drawable, this path is never entered. */
3335 #if defined(STAGING_CSMT)
3336 wined3d_resource_validate_location(&dst_surface
->resource
, WINED3D_LOCATION_TEXTURE_RGB
);
3337 wined3d_resource_invalidate_location(&dst_surface
->resource
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3338 #else /* STAGING_CSMT */
3339 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3340 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3341 #endif /* STAGING_CSMT */
3344 /* Uses the hardware to stretch and flip the image */
3345 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3346 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3348 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3349 GLuint src
, backup
= 0;
3350 float left
, right
, top
, bottom
; /* Texture coordinates */
3351 UINT fbwidth
= src_surface
->resource
.width
;
3352 UINT fbheight
= src_surface
->resource
.height
;
3353 const struct wined3d_gl_info
*gl_info
;
3354 struct wined3d_context
*context
;
3355 GLenum drawBuffer
= GL_BACK
;
3356 GLenum texture_target
;
3357 BOOL noBackBufferBackup
;
3359 BOOL upsidedown
= FALSE
;
3360 RECT dst_rect
= *dst_rect_in
;
3362 TRACE("Using hwstretch blit\n");
3363 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3364 context
= context_acquire(device
, src_surface
);
3365 gl_info
= context
->gl_info
;
3366 context_apply_blit_state(context
, device
);
3367 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3369 src_offscreen
= wined3d_resource_is_offscreen(&src_surface
->container
->resource
);
3370 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
3371 if (!noBackBufferBackup
&& !src_surface
->container
->texture_rgb
.name
)
3373 /* Get it a description */
3374 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3377 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3378 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3380 if (context
->aux_buffers
>= 2)
3382 /* Got more than one aux buffer? Use the 2nd aux buffer */
3383 drawBuffer
= GL_AUX1
;
3385 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
3387 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3388 drawBuffer
= GL_AUX0
;
3391 if (noBackBufferBackup
)
3393 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
3394 checkGLcall("glGenTextures");
3395 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3396 texture_target
= GL_TEXTURE_2D
;
3400 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3401 * we are reading from the back buffer, the backup can be used as source texture
3403 texture_target
= src_surface
->texture_target
;
3404 context_bind_texture(context
, texture_target
, src_surface
->container
->texture_rgb
.name
);
3405 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
3406 checkGLcall("glEnable(texture_target)");
3408 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3409 #if defined(STAGING_CSMT)
3410 wined3d_resource_invalidate_location(&src_surface
->resource
, WINED3D_LOCATION_TEXTURE_RGB
);
3411 #else /* STAGING_CSMT */
3412 src_surface
->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
3413 #endif /* STAGING_CSMT */
3416 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3417 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3419 if(dst_rect
.top
> dst_rect
.bottom
) {
3420 UINT tmp
= dst_rect
.bottom
;
3421 dst_rect
.bottom
= dst_rect
.top
;
3428 TRACE("Reading from an offscreen target\n");
3429 upsidedown
= !upsidedown
;
3430 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3434 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3437 /* TODO: Only back up the part that will be overwritten */
3438 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3440 checkGLcall("glCopyTexSubImage2D");
3442 /* No issue with overriding these - the sampler is dirty due to blit usage */
3443 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
3444 checkGLcall("glTexParameteri");
3445 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
3446 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
3447 checkGLcall("glTexParameteri");
3449 if (!src_surface
->container
->swapchain
3450 || src_surface
->container
== src_surface
->container
->swapchain
->back_buffers
[0])
3452 src
= backup
? backup
: src_surface
->container
->texture_rgb
.name
;
3456 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
3457 checkGLcall("glReadBuffer(GL_FRONT)");
3459 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
3460 checkGLcall("glGenTextures(1, &src)");
3461 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
3463 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3464 * out for power of 2 sizes
3466 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
3467 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
3468 checkGLcall("glTexImage2D");
3469 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3471 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3472 checkGLcall("glTexParameteri");
3473 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3474 checkGLcall("glTexParameteri");
3476 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
3477 checkGLcall("glReadBuffer(GL_BACK)");
3479 if (texture_target
!= GL_TEXTURE_2D
)
3481 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3482 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3483 texture_target
= GL_TEXTURE_2D
;
3486 checkGLcall("glEnd and previous");
3488 left
= src_rect
->left
;
3489 right
= src_rect
->right
;
3493 top
= src_surface
->resource
.height
- src_rect
->top
;
3494 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
3498 top
= src_surface
->resource
.height
- src_rect
->bottom
;
3499 bottom
= src_surface
->resource
.height
- src_rect
->top
;
3502 if (src_surface
->container
->flags
& WINED3D_TEXTURE_NORMALIZED_COORDS
)
3504 left
/= src_surface
->pow2Width
;
3505 right
/= src_surface
->pow2Width
;
3506 top
/= src_surface
->pow2Height
;
3507 bottom
/= src_surface
->pow2Height
;
3510 /* draw the source texture stretched and upside down. The correct surface is bound already */
3511 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
3512 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
3514 context_set_draw_buffer(context
, drawBuffer
);
3515 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
3517 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3519 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
3520 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3523 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
3524 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
3527 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
3528 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3531 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
3532 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
3533 gl_info
->gl_ops
.gl
.p_glEnd();
3534 checkGLcall("glEnd and previous");
3536 if (texture_target
!= dst_surface
->texture_target
)
3538 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3539 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
3540 texture_target
= dst_surface
->texture_target
;
3543 /* Now read the stretched and upside down image into the destination texture */
3544 context_bind_texture(context
, texture_target
, dst_surface
->container
->texture_rgb
.name
);
3545 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
3547 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
3548 0, 0, /* We blitted the image to the origin */
3549 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3550 checkGLcall("glCopyTexSubImage2D");
3552 if (drawBuffer
== GL_BACK
)
3554 /* Write the back buffer backup back. */
3557 if (texture_target
!= GL_TEXTURE_2D
)
3559 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3560 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3561 texture_target
= GL_TEXTURE_2D
;
3563 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3567 if (texture_target
!= src_surface
->texture_target
)
3569 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3570 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
3571 texture_target
= src_surface
->texture_target
;
3573 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->container
->texture_rgb
.name
);
3576 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3578 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
3579 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
3582 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
3583 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3586 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
3587 (float)fbheight
/ (float)src_surface
->pow2Height
);
3588 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
3591 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
3592 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
3593 gl_info
->gl_ops
.gl
.p_glEnd();
3595 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3596 checkGLcall("glDisable(texture_target)");
3599 if (src
!= src_surface
->container
->texture_rgb
.name
&& src
!= backup
)
3601 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
3602 checkGLcall("glDeleteTextures(1, &src)");
3606 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
3607 checkGLcall("glDeleteTextures(1, &backup)");
3610 #if defined(STAGING_CSMT)
3611 if (wined3d_settings
.cs_multithreaded
)
3612 gl_info
->gl_ops
.gl
.p_glFinish();
3613 else if (wined3d_settings
.strict_draw_ordering
)
3614 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3616 context_release(context
);
3618 /* The texture is now most up to date - If the surface is a render target
3619 * and has a drawable, this path is never entered. */
3620 wined3d_resource_validate_location(&dst_surface
->resource
, WINED3D_LOCATION_TEXTURE_RGB
);
3621 wined3d_resource_invalidate_location(&dst_surface
->resource
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3622 #else /* STAGING_CSMT */
3623 if (wined3d_settings
.strict_draw_ordering
)
3624 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3626 context_release(context
);
3628 /* The texture is now most up to date - If the surface is a render target
3629 * and has a drawable, this path is never entered. */
3630 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3631 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3632 #endif /* STAGING_CSMT */
3635 /* Front buffer coordinates are always full screen coordinates, but our GL
3636 * drawable is limited to the window's client area. The sysmem and texture
3637 * copies do have the full screen size. Note that GL has a bottom-left
3638 * origin, while D3D has a top-left origin. */
3639 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
3641 UINT drawable_height
;
3643 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
3645 POINT offset
= {0, 0};
3648 ScreenToClient(window
, &offset
);
3649 OffsetRect(rect
, offset
.x
, offset
.y
);
3651 GetClientRect(window
, &windowsize
);
3652 drawable_height
= windowsize
.bottom
- windowsize
.top
;
3656 drawable_height
= surface
->resource
.height
;
3659 rect
->top
= drawable_height
- rect
->top
;
3660 rect
->bottom
= drawable_height
- rect
->bottom
;
3663 /* Context activation is done by the caller. */
3664 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
3665 struct wined3d_context
*old_ctx
,
3666 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
3667 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
3668 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
3670 const struct wined3d_gl_info
*gl_info
;
3671 struct wined3d_context
*context
= old_ctx
;
3672 struct wined3d_surface
*restore_rt
= NULL
;
3673 RECT src_rect
, dst_rect
;
3675 src_rect
= *src_rect_in
;
3676 dst_rect
= *dst_rect_in
;
3679 if (old_ctx
->current_rt
!= dst_surface
)
3681 restore_rt
= old_ctx
->current_rt
;
3682 context
= context_acquire(device
, dst_surface
);
3685 gl_info
= context
->gl_info
;
3687 #if defined(STAGING_CSMT)
3688 /* Make sure the surface is up-to-date. This should probably use
3689 * wined3d_resource_load_location() and worry about the destination
3690 * surface too, unless we're overwriting it completely. */
3691 #else /* STAGING_CSMT */
3692 /* Make sure the surface is up-to-date. This should probably use
3693 * surface_load_location() and worry about the destination surface too,
3694 * unless we're overwriting it completely. */
3695 #endif /* STAGING_CSMT */
3696 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3698 /* Activate the destination context, set it up for blitting */
3699 context_apply_blit_state(context
, device
);
3701 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
3702 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
3704 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
, NULL
);
3708 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
3709 checkGLcall("glEnable(GL_ALPHA_TEST)");
3711 /* For P8 surfaces, the alpha component contains the palette index.
3712 * Which means that the colorkey is one of the palette entries. In
3713 * other cases pixels that should be masked away have alpha set to 0. */
3714 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3715 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
3716 (float)src_surface
->container
->async
.src_blt_color_key
.color_space_low_value
/ 255.0f
);
3718 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
3719 checkGLcall("glAlphaFunc");
3723 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3724 checkGLcall("glDisable(GL_ALPHA_TEST)");
3727 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
3731 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3732 checkGLcall("glDisable(GL_ALPHA_TEST)");
3735 /* Leave the opengl state valid for blitting */
3736 device
->blitter
->unset_shader(context
->gl_info
);
3738 #if defined(STAGING_CSMT)
3739 if (wined3d_settings
.cs_multithreaded
)
3740 gl_info
->gl_ops
.gl
.p_glFinish();
3741 else if (wined3d_settings
.strict_draw_ordering
3742 #else /* STAGING_CSMT */
3743 if (wined3d_settings
.strict_draw_ordering
3744 #endif /* STAGING_CSMT */
3745 || (dst_surface
->container
->swapchain
3746 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
3747 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3750 context_restore(context
, restore_rt
);
3753 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
3755 struct wined3d_resource
*resource
= &s
->container
->resource
;
3756 struct wined3d_device
*device
= resource
->device
;
3757 #if defined(STAGING_CSMT)
3758 struct wined3d_rendertarget_view view
;
3759 struct wined3d_texture
*texture
= s
->container
;
3760 #else /* STAGING_CSMT */
3761 struct wined3d_rendertarget_view_desc view_desc
;
3762 struct wined3d_rendertarget_view
*view
;
3763 #endif /* STAGING_CSMT */
3764 const struct blit_shader
*blitter
;
3767 if (!(blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
,
3768 WINED3D_BLIT_OP_COLOR_FILL
, NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
)))
3770 FIXME("No blitter is capable of performing the requested color fill operation.\n");
3771 return WINED3DERR_INVALIDCALL
;
3774 #if defined(STAGING_CSMT)
3775 /* Can't incref / decref the resource here. This is executed inside the worker
3776 * thread. Playing with the refcount here makes the worker thread visible to
3777 * the client lib. Problems occur when the worker thread happens to hold the
3778 * last reference and the resource destruction callbacks are called from the
3780 view
.resource
= &texture
->resource
;
3782 view
.parent_ops
= &wined3d_null_parent_ops
;
3783 view
.format
= s
->resource
.format
;
3784 view
.buffer_offset
= 0;
3785 view
.width
= s
->resource
.width
;
3786 view
.height
= s
->resource
.height
;
3788 view
.sub_resource_idx
= s
->texture_layer
* texture
->level_count
+ s
->texture_level
;
3790 hr
= blitter
->color_fill(device
, &view
, rect
, color
);
3791 #else /* STAGING_CSMT */
3792 view_desc
.format_id
= resource
->format
->id
;
3793 view_desc
.u
.texture
.level_idx
= s
->texture_level
;
3794 view_desc
.u
.texture
.layer_idx
= s
->texture_layer
;
3795 view_desc
.u
.texture
.layer_count
= 1;
3796 if (FAILED(hr
= wined3d_rendertarget_view_create(&view_desc
,
3797 resource
, NULL
, &wined3d_null_parent_ops
, &view
)))
3799 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
3803 hr
= blitter
->color_fill(device
, view
, rect
, color
);
3804 wined3d_rendertarget_view_decref(view
);
3805 #endif /* STAGING_CSMT */
3810 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3811 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
3812 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
3814 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3815 #if defined(STAGING_CSMT)
3816 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
3817 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->state
.fb
.render_targets
[0]);
3818 #else /* STAGING_CSMT */
3819 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->fb
.render_targets
[0]);
3820 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
3821 #endif /* STAGING_CSMT */
3823 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
3824 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
3825 flags
, fx
, debug_d3dtexturefiltertype(filter
));
3827 /* Get the swapchain. One of the surfaces has to be a primary surface */
3828 if (dst_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3830 WARN("Destination is in sysmem, rejecting gl blt\n");
3831 return WINED3DERR_INVALIDCALL
;
3834 dst_swapchain
= dst_surface
->container
->swapchain
;
3838 if (src_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3840 WARN("Src is in sysmem, rejecting gl blt\n");
3841 return WINED3DERR_INVALIDCALL
;
3844 src_swapchain
= src_surface
->container
->swapchain
;
3848 src_swapchain
= NULL
;
3851 /* Early sort out of cases where no render target is used */
3852 if (!dst_swapchain
&& !src_swapchain
&& src_surface
!= rt
&& dst_surface
!= rt
)
3854 TRACE("No surface is render target, not using hardware blit.\n");
3855 return WINED3DERR_INVALIDCALL
;
3858 /* No destination color keying supported */
3859 if (flags
& (WINED3D_BLT_DST_CKEY
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
3861 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3862 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3863 return WINED3DERR_INVALIDCALL
;
3866 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
3868 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3869 return WINED3DERR_INVALIDCALL
;
3872 if (dst_swapchain
&& src_swapchain
)
3874 FIXME("Implement hardware blit between two different swapchains\n");
3875 return WINED3DERR_INVALIDCALL
;
3880 /* Handled with regular texture -> swapchain blit */
3881 if (src_surface
== rt
)
3882 TRACE("Blit from active render target to a swapchain\n");
3884 else if (src_swapchain
&& dst_surface
== rt
)
3886 FIXME("Implement blit from a swapchain to the active render target\n");
3887 return WINED3DERR_INVALIDCALL
;
3890 if ((src_swapchain
|| src_surface
== rt
) && !dst_swapchain
)
3892 /* Blit from render target to texture */
3895 /* P8 read back is not implemented */
3896 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3897 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3899 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3900 return WINED3DERR_INVALIDCALL
;
3903 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_SRC_CKEY_OVERRIDE
))
3905 TRACE("Color keying not supported by frame buffer to texture blit\n");
3906 return WINED3DERR_INVALIDCALL
;
3907 /* Destination color key is checked above */
3910 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
3915 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3916 * flip the image nor scale it.
3918 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3919 * -> If the app wants an image width an unscaled width, copy it line per line
3920 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
3921 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3922 * back buffer. This is slower than reading line per line, thus not used for flipping
3923 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3924 * pixel by pixel. */
3925 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
3926 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
3928 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
3929 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
3933 TRACE("Using hardware stretching to flip / stretch the texture.\n");
3934 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
3937 surface_evict_sysmem(dst_surface
);
3942 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3943 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3944 return WINED3DERR_INVALIDCALL
;
3947 /* Context activation is done by the caller. */
3948 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
3949 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
3951 struct wined3d_device
*device
= surface
->resource
.device
;
3952 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
3953 GLint compare_mode
= GL_NONE
;
3954 struct blt_info info
;
3955 GLint old_binding
= 0;
3958 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
3960 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
3961 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
3962 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3963 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
3964 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
3965 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
3966 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
3967 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
3968 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
3969 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
3970 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
3972 SetRect(&rect
, 0, h
, w
, 0);
3973 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
3974 context_active_texture(context
, context
->gl_info
, 0);
3975 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
3976 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
3977 if (gl_info
->supported
[ARB_SHADOW
])
3979 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
3980 if (compare_mode
!= GL_NONE
)
3981 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
3984 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
3985 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
3987 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
3988 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
3989 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
3990 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
3991 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
3992 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
3993 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
3994 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
3995 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
3996 gl_info
->gl_ops
.gl
.p_glEnd();
3998 if (compare_mode
!= GL_NONE
)
3999 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
4000 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
4002 gl_info
->gl_ops
.gl
.p_glPopAttrib();
4004 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
4007 void surface_modify_ds_location(struct wined3d_surface
*surface
,
4008 DWORD location
, UINT w
, UINT h
)
4010 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
4012 #if defined(STAGING_CSMT)
4013 if (((surface
->resource
.locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
4014 || (!(surface
->resource
.locations
& WINED3D_LOCATION_TEXTURE_RGB
)
4015 && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
4016 wined3d_texture_set_dirty(surface
->container
);
4018 surface
->ds_current_size
.cx
= w
;
4019 surface
->ds_current_size
.cy
= h
;
4020 surface
->resource
.locations
= location
;
4021 #else /* STAGING_CSMT */
4022 if (((surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
4023 || (!(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
4024 wined3d_texture_set_dirty(surface
->container
);
4026 surface
->ds_current_size
.cx
= w
;
4027 surface
->ds_current_size
.cy
= h
;
4028 surface
->locations
= location
;
4029 #endif /* STAGING_CSMT */
4032 /* Context activation is done by the caller. */
4033 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
4035 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4036 struct wined3d_device
*device
= surface
->resource
.device
;
4039 TRACE("surface %p, context %p, new location %#x.\n", surface
, context
, location
);
4041 /* TODO: Make this work for modes other than FBO */
4042 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
4044 #if defined(STAGING_CSMT)
4045 if (!(surface
->resource
.locations
& location
))
4046 #else /* STAGING_CSMT */
4047 if (!(surface
->locations
& location
))
4048 #endif /* STAGING_CSMT */
4050 w
= surface
->ds_current_size
.cx
;
4051 h
= surface
->ds_current_size
.cy
;
4052 surface
->ds_current_size
.cx
= 0;
4053 surface
->ds_current_size
.cy
= 0;
4057 w
= surface
->resource
.width
;
4058 h
= surface
->resource
.height
;
4061 if (surface
->ds_current_size
.cx
== surface
->resource
.width
4062 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
4064 TRACE("Location (%#x) is already up to date.\n", location
);
4068 if (surface
->current_renderbuffer
)
4070 FIXME("Not supported with fixed up depth stencil.\n");
4074 wined3d_surface_prepare(surface
, context
, location
);
4075 #if defined(STAGING_CSMT)
4076 if (surface
->resource
.locations
& WINED3D_LOCATION_DISCARDED
)
4078 TRACE("Surface was discarded, no need copy data.\n");
4079 surface
->resource
.locations
&= ~WINED3D_LOCATION_DISCARDED
;
4080 surface
->resource
.locations
|= location
;
4081 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4082 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4086 if (!surface
->resource
.locations
)
4088 FIXME("No up to date depth stencil location.\n");
4089 surface
->resource
.locations
|= location
;
4090 #else /* STAGING_CSMT */
4091 if (surface
->locations
& WINED3D_LOCATION_DISCARDED
)
4093 TRACE("Surface was discarded, no need copy data.\n");
4094 surface
->locations
&= ~WINED3D_LOCATION_DISCARDED
;
4095 surface
->locations
|= location
;
4096 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4097 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4101 if (!surface
->locations
)
4103 FIXME("No up to date depth stencil location.\n");
4104 surface
->locations
|= location
;
4105 #endif /* STAGING_CSMT */
4106 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4107 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4111 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
4113 GLint old_binding
= 0;
4116 /* The render target is allowed to be smaller than the depth/stencil
4117 * buffer, so the onscreen depth/stencil buffer is potentially smaller
4118 * than the offscreen surface. Don't overwrite the offscreen surface
4119 * with undefined data. */
4120 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
4121 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
4123 TRACE("Copying onscreen depth buffer to depth texture.\n");
4125 if (!device
->depth_blt_texture
)
4126 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
4128 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4129 * directly on the FBO texture. That's because we need to flip. */
4130 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4131 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
4132 NULL
, WINED3D_LOCATION_DRAWABLE
);
4133 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
4135 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
4136 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
4140 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
4141 bind_target
= GL_TEXTURE_2D
;
4143 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
4144 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
4145 * internal format, because the internal format might include stencil
4146 * data. In principle we should copy stencil data as well, but unless
4147 * the driver supports stencil export it's hard to do, and doesn't
4148 * seem to be needed in practice. If the hardware doesn't support
4149 * writing stencil data, the glCopyTexImage2D() call might trigger
4150 * software fallbacks. */
4151 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
4152 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
4153 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
4154 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
4155 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
4156 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
4157 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
4159 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4160 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4161 context_set_draw_buffer(context
, GL_NONE
);
4163 /* Do the actual blit */
4164 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
4165 checkGLcall("depth_blt");
4167 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4169 #if defined(STAGING_CSMT)
4170 if (wined3d_settings
.cs_multithreaded
)
4171 gl_info
->gl_ops
.gl
.p_glFinish();
4172 else if (wined3d_settings
.strict_draw_ordering
)
4173 #else /* STAGING_CSMT */
4174 if (wined3d_settings
.strict_draw_ordering
)
4175 #endif /* STAGING_CSMT */
4176 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4178 else if (location
== WINED3D_LOCATION_DRAWABLE
)
4180 TRACE("Copying depth texture to onscreen depth buffer.\n");
4182 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4183 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
4184 NULL
, WINED3D_LOCATION_DRAWABLE
);
4185 surface_depth_blt(surface
, context
, surface
->container
->texture_rgb
.name
,
4186 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
4187 checkGLcall("depth_blt");
4189 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4191 #if defined(STAGING_CSMT)
4192 if (wined3d_settings
.cs_multithreaded
)
4193 gl_info
->gl_ops
.gl
.p_glFinish();
4194 else if (wined3d_settings
.strict_draw_ordering
)
4195 #else /* STAGING_CSMT */
4196 if (wined3d_settings
.strict_draw_ordering
)
4197 #endif /* STAGING_CSMT */
4198 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4202 ERR("Invalid location (%#x) specified.\n", location
);
4205 #if defined(STAGING_CSMT)
4206 surface
->resource
.locations
|= location
;
4207 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4208 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4211 /* Context activation is done by the caller. */
4212 static void surface_load_sysmem(struct wined3d_surface
*surface
,
4213 struct wined3d_context
*context
, DWORD dst_location
)
4215 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4217 if (surface
->resource
.locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
4218 wined3d_resource_load_location(&surface
->resource
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
4220 /* Download the surface to system memory. */
4221 if (surface
->resource
.locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4223 wined3d_texture_bind_and_dirtify(surface
->container
, context
,
4224 !(surface
->resource
.locations
& WINED3D_LOCATION_TEXTURE_RGB
));
4225 surface_download_data(surface
, gl_info
, dst_location
);
4230 if (surface
->resource
.locations
& WINED3D_LOCATION_DRAWABLE
)
4232 read_from_framebuffer(surface
, context
, dst_location
);
4236 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4237 surface
, wined3d_debug_location(surface
->resource
.locations
));
4238 #else /* STAGING_CSMT */
4239 surface
->locations
|= location
;
4240 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4241 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4244 void surface_validate_location(struct wined3d_surface
*surface
, DWORD location
)
4246 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4248 surface
->locations
|= location
;
4251 void surface_invalidate_location(struct wined3d_surface
*surface
, DWORD location
)
4253 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4255 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4256 wined3d_texture_set_dirty(surface
->container
);
4257 surface
->locations
&= ~location
;
4259 if (!surface
->locations
)
4260 ERR("Surface %p does not have any up to date location.\n", surface
);
4263 static DWORD
resource_access_from_location(DWORD location
)
4267 case WINED3D_LOCATION_SYSMEM
:
4268 case WINED3D_LOCATION_USER_MEMORY
:
4269 case WINED3D_LOCATION_DIB
:
4270 case WINED3D_LOCATION_BUFFER
:
4271 return WINED3D_RESOURCE_ACCESS_CPU
;
4273 case WINED3D_LOCATION_DRAWABLE
:
4274 case WINED3D_LOCATION_TEXTURE_SRGB
:
4275 case WINED3D_LOCATION_TEXTURE_RGB
:
4276 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4277 case WINED3D_LOCATION_RB_RESOLVED
:
4278 return WINED3D_RESOURCE_ACCESS_GPU
;
4281 FIXME("Unhandled location %#x.\n", location
);
4286 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
4288 struct wined3d_device
*device
= surface
->resource
.device
;
4289 struct wined3d_context
*context
;
4290 const struct wined3d_gl_info
*gl_info
;
4291 struct wined3d_bo_address dst
, src
;
4292 UINT size
= surface
->resource
.size
;
4294 surface_get_memory(surface
, &dst
, location
);
4295 surface_get_memory(surface
, &src
, surface
->locations
);
4297 if (dst
.buffer_object
)
4299 context
= context_acquire(device
, NULL
);
4300 gl_info
= context
->gl_info
;
4301 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, dst
.buffer_object
));
4302 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER
, 0, size
, src
.addr
));
4303 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
4304 checkGLcall("Upload PBO");
4305 context_release(context
);
4308 if (src
.buffer_object
)
4310 context
= context_acquire(device
, NULL
);
4311 gl_info
= context
->gl_info
;
4312 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, src
.buffer_object
));
4313 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER
, 0, size
, dst
.addr
));
4314 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
4315 checkGLcall("Download PBO");
4316 context_release(context
);
4319 memcpy(dst
.addr
, src
.addr
, size
);
4322 /* Context activation is done by the caller. */
4323 static void surface_load_sysmem(struct wined3d_surface
*surface
,
4324 struct wined3d_context
*context
, DWORD dst_location
)
4326 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4328 if (surface
->locations
& surface_simple_locations
)
4330 surface_copy_simple_location(surface
, dst_location
);
4334 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
4335 surface_load_location(surface
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
4337 /* Download the surface to system memory. */
4338 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4340 wined3d_texture_bind_and_dirtify(surface
->container
, context
,
4341 !(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
4342 surface_download_data(surface
, gl_info
, dst_location
);
4347 if (surface
->locations
& WINED3D_LOCATION_DRAWABLE
)
4349 read_from_framebuffer(surface
, context
, dst_location
);
4353 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4354 surface
, wined3d_debug_location(surface
->locations
));
4355 #endif /* STAGING_CSMT */
4358 /* Context activation is done by the caller. */
4359 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
4360 struct wined3d_context
*context
)
4364 #if defined(STAGING_CSMT)
4365 if (surface
->resource
.locations
& WINED3D_LOCATION_DISCARDED
)
4367 TRACE("Surface was discarded, nothing to do.\n");
4371 #endif /* STAGING_CSMT */
4372 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
4373 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
4375 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4376 return WINED3DERR_INVALIDCALL
;
4379 surface_get_rect(surface
, NULL
, &r
);
4380 #if defined(STAGING_CSMT)
4381 wined3d_resource_load_location(&surface
->resource
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
4382 #else /* STAGING_CSMT */
4383 surface_load_location(surface
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
4384 #endif /* STAGING_CSMT */
4385 surface_blt_to_drawable(surface
->resource
.device
, context
,
4386 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
4391 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
4392 struct wined3d_context
*context
, BOOL srgb
)
4394 #if defined(STAGING_CSMT)
4395 unsigned int width
, src_row_pitch
, src_slice_pitch
, dst_pitch
;
4396 #else /* STAGING_CSMT */
4397 unsigned int width
, src_row_pitch
, src_slice_pitch
, dst_row_pitch
, dst_slice_pitch
;
4398 #endif /* STAGING_CSMT */
4399 const RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4400 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4401 struct wined3d_device
*device
= surface
->resource
.device
;
4402 const struct wined3d_color_key_conversion
*conversion
;
4403 struct wined3d_texture
*texture
= surface
->container
;
4404 struct wined3d_bo_address data
;
4405 struct wined3d_format format
;
4406 POINT dst_point
= {0, 0};
4408 #if defined(STAGING_CSMT)
4409 const DWORD simple_locations
=
4410 WINED3D_LOCATION_SYSMEM
| WINED3D_LOCATION_USER_MEMORY
4411 | WINED3D_LOCATION_DIB
| WINED3D_LOCATION_BUFFER
;
4413 if (surface
->resource
.locations
& WINED3D_LOCATION_DISCARDED
)
4415 TRACE("Surface was discarded, nothing to do.\n");
4416 wined3d_texture_prepare_texture(texture
, context
, srgb
);
4420 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
4421 && wined3d_resource_is_offscreen(&texture
->resource
)
4422 && (surface
->resource
.locations
& WINED3D_LOCATION_DRAWABLE
))
4424 surface_load_fb_texture(surface
, srgb
, context
);
4429 if (surface
->resource
.locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
4430 #else /* STAGING_CSMT */
4432 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
4433 && wined3d_resource_is_offscreen(&texture
->resource
)
4434 && (surface
->locations
& WINED3D_LOCATION_DRAWABLE
))
4436 surface_load_fb_texture(surface
, srgb
, context
);
4441 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
4442 #endif /* STAGING_CSMT */
4443 && (surface
->container
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
4444 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4445 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4446 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4449 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
4450 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
4452 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
4453 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
4458 #if defined(STAGING_CSMT)
4459 if (surface
->resource
.locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
4460 && (!srgb
|| (surface
->container
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
4461 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4462 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4463 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4465 DWORD src_location
= surface
->resource
.locations
& WINED3D_LOCATION_RB_RESOLVED
?
4466 #else /* STAGING_CSMT */
4467 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
4468 && (!srgb
|| (surface
->container
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
4469 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4470 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4471 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4473 DWORD src_location
= surface
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
4474 #endif /* STAGING_CSMT */
4475 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
4476 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
4477 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4479 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, src_location
,
4480 &rect
, surface
, dst_location
, &rect
);
4485 /* Upload from system memory */
4489 #if defined(STAGING_CSMT)
4490 if ((surface
->resource
.locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->resource
.map_binding
))
4491 == WINED3D_LOCATION_TEXTURE_RGB
)
4493 /* Performance warning... */
4494 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
4495 wined3d_resource_prepare_map_memory(&surface
->resource
, context
);
4496 wined3d_resource_load_location(&surface
->resource
, context
, surface
->resource
.map_binding
);
4501 if ((surface
->resource
.locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->resource
.map_binding
))
4502 == WINED3D_LOCATION_TEXTURE_SRGB
)
4504 /* Performance warning... */
4505 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
4506 wined3d_resource_prepare_map_memory(&surface
->resource
, context
);
4507 wined3d_resource_load_location(&surface
->resource
, context
, surface
->resource
.map_binding
);
4511 if (!(surface
->resource
.locations
& simple_locations
))
4513 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4514 /* Lets hope we get it from somewhere... */
4515 wined3d_resource_prepare_system_memory(&surface
->resource
);
4516 wined3d_resource_load_location(&surface
->resource
, context
, WINED3D_LOCATION_SYSMEM
);
4519 wined3d_texture_prepare_texture(texture
, context
, srgb
);
4520 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
4521 wined3d_resource_get_pitch(&surface
->resource
, &src_row_pitch
, &src_slice_pitch
);
4522 #else /* STAGING_CSMT */
4523 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->resource
.map_binding
))
4524 == WINED3D_LOCATION_TEXTURE_RGB
)
4526 /* Performance warning... */
4527 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
4528 surface_prepare_map_memory(surface
);
4529 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
4534 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->resource
.map_binding
))
4535 == WINED3D_LOCATION_TEXTURE_SRGB
)
4537 /* Performance warning... */
4538 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
4539 surface_prepare_map_memory(surface
);
4540 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
4544 if (!(surface
->locations
& surface_simple_locations
))
4546 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4547 /* Lets hope we get it from somewhere... */
4548 surface_prepare_system_memory(surface
);
4549 surface_load_location(surface
, context
, WINED3D_LOCATION_SYSMEM
);
4552 wined3d_texture_prepare_texture(texture
, context
, srgb
);
4553 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
4554 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &src_row_pitch
, &src_slice_pitch
);
4555 #endif /* STAGING_CSMT */
4557 width
= surface
->resource
.width
;
4559 format
= *texture
->resource
.format
;
4560 if ((conversion
= wined3d_format_get_color_key_conversion(texture
, TRUE
)))
4561 format
= *wined3d_get_format(gl_info
, conversion
->dst_format
);
4563 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4564 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
4565 * getting called. */
4566 #if defined(STAGING_CSMT)
4567 if ((format
.convert
|| conversion
) && surface
->resource
.buffer
)
4568 #else /* STAGING_CSMT */
4569 if ((format
.convert
|| conversion
) && surface
->pbo
)
4570 #endif /* STAGING_CSMT */
4572 TRACE("Removing the pbo attached to surface %p.\n", surface
);
4574 if (surface
->flags
& SFLAG_DIBSECTION
)
4575 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
4577 surface
->resource
.map_binding
= WINED3D_LOCATION_SYSMEM
;
4579 #if defined(STAGING_CSMT)
4580 wined3d_resource_prepare_map_memory(&surface
->resource
, context
);
4581 wined3d_resource_load_location(&surface
->resource
, context
, surface
->resource
.map_binding
);
4582 wined3d_resource_free_bo(&surface
->resource
);
4583 wined3d_resource_invalidate_location(&surface
->resource
, WINED3D_LOCATION_BUFFER
);
4586 wined3d_resource_get_memory(&surface
->resource
, surface
->resource
.locations
, &data
);
4589 /* This code is entered for texture formats which need a fixup. */
4590 UINT height
= surface
->resource
.height
;
4592 format
.byte_count
= format
.conv_byte_count
;
4593 dst_pitch
= wined3d_format_calculate_pitch(&format
, width
);
4595 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4597 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4598 context_release(context
);
4599 return E_OUTOFMEMORY
;
4601 format
.convert(data
.addr
, mem
, src_row_pitch
, src_slice_pitch
,
4602 dst_pitch
, dst_pitch
* height
, width
, height
, 1);
4603 src_row_pitch
= dst_pitch
;
4604 #else /* STAGING_CSMT */
4605 surface_prepare_map_memory(surface
);
4606 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
4607 surface_remove_pbo(surface
, gl_info
);
4610 surface_get_memory(surface
, &data
, surface
->locations
);
4613 /* This code is entered for texture formats which need a fixup. */
4614 UINT height
= surface
->resource
.height
;
4616 format
.byte_count
= format
.conv_byte_count
;
4617 wined3d_format_calculate_pitch(&format
, 1, width
, height
, &dst_row_pitch
, &dst_slice_pitch
);
4619 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
)))
4621 ERR("Out of memory (%u).\n", dst_slice_pitch
);
4622 context_release(context
);
4623 return E_OUTOFMEMORY
;
4625 format
.convert(data
.addr
, mem
, src_row_pitch
, src_slice_pitch
,
4626 dst_row_pitch
, dst_slice_pitch
, width
, height
, 1);
4627 src_row_pitch
= dst_row_pitch
;
4628 #endif /* STAGING_CSMT */
4631 else if (conversion
)
4633 /* This code is only entered for color keying fixups */
4634 struct wined3d_palette
*palette
= NULL
;
4635 UINT height
= surface
->resource
.height
;
4637 #if defined(STAGING_CSMT)
4638 dst_pitch
= wined3d_format_calculate_pitch(&format
, width
);
4639 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4641 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4643 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4644 context_release(context
);
4645 return E_OUTOFMEMORY
;
4647 if (texture
->swapchain
&& texture
->swapchain
->palette
)
4648 palette
= texture
->swapchain
->palette
;
4649 conversion
->convert(data
.addr
, src_row_pitch
, mem
, dst_pitch
,
4650 width
, height
, palette
, &texture
->async
.gl_color_key
);
4651 src_row_pitch
= dst_pitch
;
4652 #else /* STAGING_CSMT */
4653 wined3d_format_calculate_pitch(&format
, device
->surface_alignment
,
4654 width
, height
, &dst_row_pitch
, &dst_slice_pitch
);
4656 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
)))
4658 ERR("Out of memory (%u).\n", dst_slice_pitch
);
4659 context_release(context
);
4660 return E_OUTOFMEMORY
;
4662 if (texture
->swapchain
&& texture
->swapchain
->palette
)
4663 palette
= texture
->swapchain
->palette
;
4664 conversion
->convert(data
.addr
, src_row_pitch
, mem
, dst_row_pitch
,
4665 width
, height
, palette
, &texture
->async
.gl_color_key
);
4666 src_row_pitch
= dst_row_pitch
;
4667 #endif /* STAGING_CSMT */
4671 wined3d_surface_upload_data(surface
, gl_info
, &format
, &src_rect
,
4672 src_row_pitch
, &dst_point
, srgb
, wined3d_const_bo_address(&data
));
4674 HeapFree(GetProcessHeap(), 0, mem
);
4679 /* Context activation is done by the caller. */
4680 static void surface_load_renderbuffer(struct wined3d_surface
*surface
, struct wined3d_context
*context
,
4683 const RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4686 #if defined(STAGING_CSMT)
4687 if (surface
->resource
.locations
& WINED3D_LOCATION_RB_MULTISAMPLE
)
4688 src_location
= WINED3D_LOCATION_RB_MULTISAMPLE
;
4689 else if (surface
->resource
.locations
& WINED3D_LOCATION_RB_RESOLVED
)
4690 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
4691 else if (surface
->resource
.locations
& WINED3D_LOCATION_TEXTURE_SRGB
)
4692 #else /* STAGING_CSMT */
4693 if (surface
->locations
& WINED3D_LOCATION_RB_MULTISAMPLE
)
4694 src_location
= WINED3D_LOCATION_RB_MULTISAMPLE
;
4695 else if (surface
->locations
& WINED3D_LOCATION_RB_RESOLVED
)
4696 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
4697 else if (surface
->locations
& WINED3D_LOCATION_TEXTURE_SRGB
)
4698 #endif /* STAGING_CSMT */
4699 src_location
= WINED3D_LOCATION_TEXTURE_SRGB
;
4700 else /* surface_blt_fbo will load the source location if necessary. */
4701 src_location
= WINED3D_LOCATION_TEXTURE_RGB
;
4703 surface_blt_fbo(surface
->resource
.device
, context
, WINED3D_TEXF_POINT
,
4704 surface
, src_location
, &rect
, surface
, dst_location
, &rect
);
4707 #if defined(STAGING_CSMT)
4708 /* Context activation is done by the caller. */
4709 static void wined3d_surface_load_location(struct wined3d_resource
*resource
,
4710 struct wined3d_context
*context
, DWORD location
)
4712 struct wined3d_surface
*surface
= surface_from_resource(resource
);
4713 #else /* STAGING_CSMT */
4714 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
4715 HRESULT
surface_load_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
4717 #endif /* STAGING_CSMT */
4720 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4722 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
4724 if (location
== WINED3D_LOCATION_TEXTURE_RGB
4725 #if defined(STAGING_CSMT)
4726 && surface
->resource
.locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_DISCARDED
))
4728 surface_load_ds_location(surface
, context
, location
);
4731 else if (location
& surface
->resource
.locations
4732 && surface
->container
->resource
.draw_binding
!= WINED3D_LOCATION_DRAWABLE
)
4734 /* Already up to date, nothing to do. */
4739 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4740 wined3d_debug_location(surface
->resource
.locations
), wined3d_debug_location(location
));
4745 if (!surface
->resource
.locations
)
4747 ERR("Surface %p does not have any up to date location.\n", surface
);
4749 #else /* STAGING_CSMT */
4750 && surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_DISCARDED
))
4752 surface_load_ds_location(surface
, context
, location
);
4755 else if (location
& surface
->locations
4756 && surface
->container
->resource
.draw_binding
!= WINED3D_LOCATION_DRAWABLE
)
4758 /* Already up to date, nothing to do. */
4763 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4764 wined3d_debug_location(surface
->locations
), wined3d_debug_location(location
));
4765 return WINED3DERR_INVALIDCALL
;
4769 if (surface
->locations
& location
)
4771 TRACE("Location already up to date.\n");
4775 if (WARN_ON(d3d_surface
))
4777 DWORD required_access
= resource_access_from_location(location
);
4778 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
4779 WARN("Operation requires %#x access, but surface only has %#x.\n",
4780 required_access
, surface
->resource
.access_flags
);
4783 if (!surface
->locations
)
4785 ERR("Surface %p does not have any up to date location.\n", surface
);
4786 return WINED3DERR_INVALIDCALL
;
4787 #endif /* STAGING_CSMT */
4792 case WINED3D_LOCATION_DIB
:
4793 case WINED3D_LOCATION_USER_MEMORY
:
4794 case WINED3D_LOCATION_SYSMEM
:
4795 case WINED3D_LOCATION_BUFFER
:
4796 surface_load_sysmem(surface
, context
, location
);
4799 case WINED3D_LOCATION_DRAWABLE
:
4800 if (FAILED(hr
= surface_load_drawable(surface
, context
)))
4801 #if defined(STAGING_CSMT)
4803 #else /* STAGING_CSMT */
4805 #endif /* STAGING_CSMT */
4808 case WINED3D_LOCATION_RB_RESOLVED
:
4809 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4810 surface_load_renderbuffer(surface
, context
, location
);
4813 case WINED3D_LOCATION_TEXTURE_RGB
:
4814 case WINED3D_LOCATION_TEXTURE_SRGB
:
4815 if (FAILED(hr
= surface_load_texture(surface
, context
,
4816 location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
4817 #if defined(STAGING_CSMT)
4819 #else /* STAGING_CSMT */
4821 #endif /* STAGING_CSMT */
4825 ERR("Don't know how to handle location %#x.\n", location
);
4829 #if defined(STAGING_CSMT)
4830 wined3d_resource_validate_location(&surface
->resource
, location
);
4832 if (location
!= WINED3D_LOCATION_SYSMEM
&& (surface
->resource
.locations
& WINED3D_LOCATION_SYSMEM
))
4833 surface_evict_sysmem(surface
);
4836 #else /* STAGING_CSMT */
4837 surface_validate_location(surface
, location
);
4839 if (location
!= WINED3D_LOCATION_SYSMEM
&& (surface
->locations
& WINED3D_LOCATION_SYSMEM
))
4840 surface_evict_sysmem(surface
);
4843 #endif /* STAGING_CSMT */
4846 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
4847 /* Context activation is done by the caller. */
4848 static void ffp_blit_free(struct wined3d_device
*device
) { }
4850 /* Context activation is done by the caller. */
4851 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
,
4852 const struct wined3d_color_key
*color_key
)
4854 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4856 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
4857 checkGLcall("glEnable(target)");
4862 /* Context activation is done by the caller. */
4863 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
4865 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
4866 checkGLcall("glDisable(GL_TEXTURE_2D)");
4867 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
4869 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
4870 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4872 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
4874 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
4875 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4879 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
,
4880 const struct wined3d_d3d_info
*d3d_info
, enum wined3d_blit_op blit_op
,
4881 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4882 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4884 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4886 TRACE("Source or destination is in system memory.\n");
4892 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
4893 if (d3d_info
->shader_color_key
)
4895 TRACE("Color keying requires converted textures.\n");
4898 case WINED3D_BLIT_OP_COLOR_BLIT
:
4899 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
4900 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
4902 TRACE("Checking support for fixup:\n");
4903 dump_color_fixup_desc(src_format
->color_fixup
);
4906 /* We only support identity conversions. */
4907 if (!is_identity_fixup(src_format
->color_fixup
)
4908 || !is_identity_fixup(dst_format
->color_fixup
))
4910 TRACE("Fixups are not supported.\n");
4914 if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
4916 TRACE("Can only blit to render targets.\n");
4921 case WINED3D_BLIT_OP_COLOR_FILL
:
4922 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
4924 if (!((dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
4925 || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
4928 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
4930 TRACE("Color fill not supported\n");
4934 /* FIXME: We should reject color fills on formats with fixups,
4935 * but this would break P8 color fills for example. */
4939 case WINED3D_BLIT_OP_DEPTH_FILL
:
4943 TRACE("Unsupported blit_op=%d\n", blit_op
);
4948 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_rendertarget_view
*view
,
4949 const RECT
*rect
, const struct wined3d_color
*color
)
4951 const RECT draw_rect
= {0, 0, view
->width
, view
->height
};
4952 #if defined(STAGING_CSMT)
4953 struct wined3d_fb_state fb
= {&view
, NULL
, 1};
4954 #else /* STAGING_CSMT */
4955 struct wined3d_fb_state fb
= {&view
, NULL
};
4956 #endif /* STAGING_CSMT */
4958 device_clear_render_targets(device
, 1, &fb
, 1, rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
4963 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
4964 struct wined3d_rendertarget_view
*view
, const RECT
*rect
, float depth
)
4966 const RECT draw_rect
= {0, 0, view
->width
, view
->height
};
4967 struct wined3d_fb_state fb
= {NULL
, view
};
4969 device_clear_render_targets(device
, 0, &fb
, 1, rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
4974 static void ffp_blit_blit_surface(struct wined3d_device
*device
, enum wined3d_blit_op op
, DWORD filter
,
4975 struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
4976 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4977 const struct wined3d_color_key
*color_key
)
4979 struct wined3d_context
*context
;
4981 /* Blit from offscreen surface to render target */
4982 struct wined3d_color_key old_blt_key
= src_surface
->container
->async
.src_blt_color_key
;
4983 DWORD old_color_key_flags
= src_surface
->container
->async
.color_key_flags
;
4985 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
4987 wined3d_texture_set_color_key(src_surface
->container
, WINED3D_CKEY_SRC_BLT
, color_key
);
4989 context
= context_acquire(device
, dst_surface
);
4991 if (op
== WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
)
4992 glEnable(GL_ALPHA_TEST
);
4994 surface_blt_to_drawable(device
, context
, filter
,
4995 !!color_key
, src_surface
, src_rect
, dst_surface
, dst_rect
);
4997 if (op
== WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
)
4998 glDisable(GL_ALPHA_TEST
);
5000 context_release(context
);
5002 /* Restore the color key parameters */
5003 wined3d_texture_set_color_key(src_surface
->container
, WINED3D_CKEY_SRC_BLT
,
5004 (old_color_key_flags
& WINED3D_CKEY_SRC_BLT
) ? &old_blt_key
: NULL
);
5006 #if defined(STAGING_CSMT)
5007 wined3d_resource_validate_location(&dst_surface
->resource
, dst_surface
->container
->resource
.draw_binding
);
5008 wined3d_resource_invalidate_location(&dst_surface
->resource
, ~dst_surface
->container
->resource
.draw_binding
);
5009 #else /* STAGING_CSMT */
5010 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5011 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
5012 #endif /* STAGING_CSMT */
5015 const struct blit_shader ffp_blit
= {
5021 ffp_blit_color_fill
,
5022 ffp_blit_depth_fill
,
5023 ffp_blit_blit_surface
,
5026 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
5031 /* Context activation is done by the caller. */
5032 static void cpu_blit_free(struct wined3d_device
*device
)
5036 /* Context activation is done by the caller. */
5037 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
,
5038 const struct wined3d_color_key
*color_key
)
5043 /* Context activation is done by the caller. */
5044 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
5048 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
,
5049 const struct wined3d_d3d_info
*d3d_info
, enum wined3d_blit_op blit_op
,
5050 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
5051 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
5053 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
5061 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
5062 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
5063 const struct wined3d_format
*format
, DWORD flags
, const struct wined3d_blt_fx
*fx
)
5065 UINT row_block_count
;
5066 const BYTE
*src_row
;
5073 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
5077 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5079 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
5080 src_row
+= src_pitch
;
5081 dst_row
+= dst_pitch
;
5087 if (flags
== WINED3D_BLT_FX
&& fx
->fx
== WINEDDBLTFX_MIRRORUPDOWN
)
5089 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
5093 case WINED3DFMT_DXT1
:
5094 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5099 BYTE control_row
[4];
5102 const struct block
*s
= (const struct block
*)src_row
;
5103 struct block
*d
= (struct block
*)dst_row
;
5105 for (x
= 0; x
< row_block_count
; ++x
)
5107 d
[x
].color
[0] = s
[x
].color
[0];
5108 d
[x
].color
[1] = s
[x
].color
[1];
5109 d
[x
].control_row
[0] = s
[x
].control_row
[3];
5110 d
[x
].control_row
[1] = s
[x
].control_row
[2];
5111 d
[x
].control_row
[2] = s
[x
].control_row
[1];
5112 d
[x
].control_row
[3] = s
[x
].control_row
[0];
5114 src_row
-= src_pitch
;
5115 dst_row
+= dst_pitch
;
5119 case WINED3DFMT_DXT2
:
5120 case WINED3DFMT_DXT3
:
5121 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
5127 BYTE control_row
[4];
5130 const struct block
*s
= (const struct block
*)src_row
;
5131 struct block
*d
= (struct block
*)dst_row
;
5133 for (x
= 0; x
< row_block_count
; ++x
)
5135 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
5136 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
5137 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
5138 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
5139 d
[x
].color
[0] = s
[x
].color
[0];
5140 d
[x
].color
[1] = s
[x
].color
[1];
5141 d
[x
].control_row
[0] = s
[x
].control_row
[3];
5142 d
[x
].control_row
[1] = s
[x
].control_row
[2];
5143 d
[x
].control_row
[2] = s
[x
].control_row
[1];
5144 d
[x
].control_row
[3] = s
[x
].control_row
[0];
5146 src_row
-= src_pitch
;
5147 dst_row
+= dst_pitch
;
5152 FIXME("Compressed flip not implemented for format %s.\n",
5153 debug_d3dformat(format
->id
));
5158 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
5159 debug_d3dformat(format
->id
), flags
, flags
& WINED3D_BLT_FX
? fx
->fx
: 0);
5164 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5165 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
5166 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
5168 #if defined(STAGING_CSMT)
5169 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
5170 const struct wined3d_format
*src_format
, *dst_format
;
5171 unsigned int src_fmt_flags
, dst_fmt_flags
;
5172 struct wined3d_texture
*src_texture
= NULL
;
5173 void *src_data
= NULL
, *dst_data
= NULL
;
5174 UINT src_row_pitch
, src_slice_pitch
, dst_row_pitch
, dst_slice_pitch
;
5175 const BYTE
*sbase
= NULL
;
5176 HRESULT hr
= WINED3D_OK
;
5180 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5181 struct wined3d_context
*context
= NULL
;
5183 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5184 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5185 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5187 if (device
->d3d_initialized
)
5188 context
= context_acquire(device
, NULL
);
5190 if (!wined3d_resource_prepare_map_memory(&dst_surface
->resource
, context
))
5195 wined3d_resource_load_location(&dst_surface
->resource
, context
, dst_surface
->resource
.map_binding
);
5197 if (src_surface
== dst_surface
)
5199 dst_data
= wined3d_resource_get_map_ptr(&dst_surface
->resource
, context
, 0);
5200 wined3d_resource_get_pitch(&dst_surface
->resource
, &dst_row_pitch
, &dst_slice_pitch
);
5201 src_data
= dst_data
;
5202 src_row_pitch
= dst_row_pitch
;
5203 #else /* STAGING_CSMT */
5204 const struct wined3d_box dst_box
= {dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, 0, 1};
5205 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
5206 const struct wined3d_format
*src_format
, *dst_format
;
5207 unsigned int src_fmt_flags
, dst_fmt_flags
;
5208 struct wined3d_texture
*src_texture
= NULL
;
5209 struct wined3d_map_desc dst_map
, src_map
;
5210 const BYTE
*sbase
= NULL
;
5211 HRESULT hr
= WINED3D_OK
;
5216 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5217 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5218 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5220 if (src_surface
== dst_surface
)
5222 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
5224 #endif /* STAGING_CSMT */
5225 src_format
= dst_surface
->resource
.format
;
5226 dst_format
= src_format
;
5227 dst_fmt_flags
= dst_surface
->container
->resource
.format_flags
;
5228 src_fmt_flags
= dst_fmt_flags
;
5232 dst_format
= dst_surface
->resource
.format
;
5233 dst_fmt_flags
= dst_surface
->container
->resource
.format_flags
;
5236 #if defined(STAGING_CSMT)
5237 if (!wined3d_resource_prepare_map_memory(&src_surface
->resource
, context
))
5243 #endif /* STAGING_CSMT */
5244 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
5246 if (!(src_texture
= surface_convert_format(src_surface
, dst_format
->id
)))
5248 /* The conv function writes a FIXME */
5249 WARN("Cannot convert source surface format to dest format.\n");
5252 src_surface
= surface_from_resource(wined3d_texture_get_sub_resource(src_texture
, 0));
5254 #if defined(STAGING_CSMT)
5255 wined3d_resource_load_location(&src_surface
->resource
, context
, src_surface
->resource
.map_binding
);
5256 wined3d_resource_get_pitch(&src_surface
->resource
, &src_row_pitch
, &src_slice_pitch
);
5257 src_data
= wined3d_resource_get_map_ptr(&src_surface
->resource
, context
, 0);
5258 #else /* STAGING_CSMT */
5259 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
5260 #endif /* STAGING_CSMT */
5261 src_format
= src_surface
->resource
.format
;
5262 src_fmt_flags
= src_surface
->container
->resource
.format_flags
;
5266 src_format
= dst_format
;
5267 src_fmt_flags
= dst_fmt_flags
;
5270 #if defined(STAGING_CSMT)
5271 wined3d_resource_get_pitch(&dst_surface
->resource
, &dst_row_pitch
, &dst_slice_pitch
);
5272 dst_data
= wined3d_resource_get_map_ptr(&dst_surface
->resource
, context
, 0);
5273 #else /* STAGING_CSMT */
5274 wined3d_surface_map(dst_surface
, &dst_map
, &dst_box
, 0);
5275 #endif /* STAGING_CSMT */
5278 bpp
= dst_surface
->resource
.format
->byte_count
;
5279 srcheight
= src_rect
->bottom
- src_rect
->top
;
5280 srcwidth
= src_rect
->right
- src_rect
->left
;
5281 dstheight
= dst_rect
->bottom
- dst_rect
->top
;
5282 dstwidth
= dst_rect
->right
- dst_rect
->left
;
5283 width
= (dst_rect
->right
- dst_rect
->left
) * bpp
;
5286 #if defined(STAGING_CSMT)
5287 sbase
= (BYTE
*)src_data
5288 + ((src_rect
->top
/ src_format
->block_height
) * src_row_pitch
)
5289 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
5290 dbuf
= (BYTE
*)dst_data
5291 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_row_pitch
)
5292 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
5293 #else /* STAGING_CSMT */
5294 sbase
= (BYTE
*)src_map
.data
5295 + ((src_rect
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
5296 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
5297 if (src_surface
!= dst_surface
)
5298 dbuf
= dst_map
.data
;
5300 dbuf
= (BYTE
*)dst_map
.data
5301 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
5302 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
5303 #endif /* STAGING_CSMT */
5305 if (src_fmt_flags
& dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
)
5307 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
5309 if (src_surface
== dst_surface
)
5311 FIXME("Only plain blits supported on compressed surfaces.\n");
5316 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
5318 WARN("Stretching not supported on compressed surfaces.\n");
5319 hr
= WINED3DERR_INVALIDCALL
;
5323 if (!surface_check_block_align_rect(src_surface
, src_rect
))
5325 WARN("Source rectangle not block-aligned.\n");
5326 hr
= WINED3DERR_INVALIDCALL
;
5330 if (!surface_check_block_align_rect(dst_surface
, dst_rect
))
5332 WARN("Destination rectangle not block-aligned.\n");
5333 hr
= WINED3DERR_INVALIDCALL
;
5337 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
5338 #if defined(STAGING_CSMT)
5339 src_row_pitch
, dst_row_pitch
, dstwidth
, dstheight
,
5340 #else /* STAGING_CSMT */
5341 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
5342 #endif /* STAGING_CSMT */
5343 src_format
, flags
, fx
);
5347 /* First, all the 'source-less' blits */
5348 if (flags
& WINED3D_BLT_COLOR_FILL
)
5350 #if defined(STAGING_CSMT)
5351 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_row_pitch
, fx
->fill_color
);
5352 #else /* STAGING_CSMT */
5353 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->fill_color
);
5354 #endif /* STAGING_CSMT */
5355 flags
&= ~WINED3D_BLT_COLOR_FILL
;
5358 if (flags
& WINED3D_BLT_DEPTH_FILL
)
5359 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
5361 /* Now the 'with source' blits. */
5364 int sx
, xinc
, sy
, yinc
;
5366 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
5369 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
5370 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
5372 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
5374 if (!once
++) FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
5377 xinc
= (srcwidth
<< 16) / dstwidth
;
5378 yinc
= (srcheight
<< 16) / dstheight
;
5382 /* No effects, we can cheat here. */
5383 if (dstwidth
== srcwidth
)
5385 if (dstheight
== srcheight
)
5387 /* No stretching in either direction. This needs to be as
5388 * fast as possible. */
5391 /* Check for overlapping surfaces. */
5392 if (src_surface
!= dst_surface
|| dst_rect
->top
< src_rect
->top
5393 || dst_rect
->right
<= src_rect
->left
|| src_rect
->right
<= dst_rect
->left
)
5395 /* No overlap, or dst above src, so copy from top downwards. */
5396 for (y
= 0; y
< dstheight
; ++y
)
5398 memcpy(dbuf
, sbuf
, width
);
5399 #if defined(STAGING_CSMT)
5400 sbuf
+= src_row_pitch
;
5401 dbuf
+= dst_row_pitch
;
5404 else if (dst_rect
->top
> src_rect
->top
)
5406 /* Copy from bottom upwards. */
5407 sbuf
+= src_row_pitch
* dstheight
;
5408 dbuf
+= dst_row_pitch
* dstheight
;
5409 for (y
= 0; y
< dstheight
; ++y
)
5411 sbuf
-= src_row_pitch
;
5412 dbuf
-= dst_row_pitch
;
5413 #else /* STAGING_CSMT */
5414 sbuf
+= src_map
.row_pitch
;
5415 dbuf
+= dst_map
.row_pitch
;
5418 else if (dst_rect
->top
> src_rect
->top
)
5420 /* Copy from bottom upwards. */
5421 sbuf
+= src_map
.row_pitch
* dstheight
;
5422 dbuf
+= dst_map
.row_pitch
* dstheight
;
5423 for (y
= 0; y
< dstheight
; ++y
)
5425 sbuf
-= src_map
.row_pitch
;
5426 dbuf
-= dst_map
.row_pitch
;
5427 #endif /* STAGING_CSMT */
5428 memcpy(dbuf
, sbuf
, width
);
5433 /* Src and dst overlapping on the same line, use memmove. */
5434 for (y
= 0; y
< dstheight
; ++y
)
5436 memmove(dbuf
, sbuf
, width
);
5437 #if defined(STAGING_CSMT)
5438 sbuf
+= src_row_pitch
;
5439 dbuf
+= dst_row_pitch
;
5440 #else /* STAGING_CSMT */
5441 sbuf
+= src_map
.row_pitch
;
5442 dbuf
+= dst_map
.row_pitch
;
5443 #endif /* STAGING_CSMT */
5449 /* Stretching in y direction only. */
5450 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5452 #if defined(STAGING_CSMT)
5453 sbuf
= sbase
+ (sy
>> 16) * src_row_pitch
;
5454 memcpy(dbuf
, sbuf
, width
);
5455 dbuf
+= dst_row_pitch
;
5456 #else /* STAGING_CSMT */
5457 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5458 memcpy(dbuf
, sbuf
, width
);
5459 dbuf
+= dst_map
.row_pitch
;
5460 #endif /* STAGING_CSMT */
5466 /* Stretching in X direction. */
5468 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5470 #if defined(STAGING_CSMT)
5471 sbuf
= sbase
+ (sy
>> 16) * src_row_pitch
;
5473 if ((sy
>> 16) == (last_sy
>> 16))
5475 /* This source row is the same as last source row -
5476 * Copy the already stretched row. */
5477 memcpy(dbuf
, dbuf
- dst_row_pitch
, width
);
5478 #else /* STAGING_CSMT */
5479 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5481 if ((sy
>> 16) == (last_sy
>> 16))
5483 /* This source row is the same as last source row -
5484 * Copy the already stretched row. */
5485 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
5486 #endif /* STAGING_CSMT */
5490 #define STRETCH_ROW(type) \
5492 const type *s = (const type *)sbuf; \
5493 type *d = (type *)dbuf; \
5494 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5495 d[x] = s[sx >> 16]; \
5513 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
5517 s
= sbuf
+ 3 * (sx
>> 16);
5518 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5519 d
[0] = (pixel
) & 0xff;
5520 d
[1] = (pixel
>> 8) & 0xff;
5521 d
[2] = (pixel
>> 16) & 0xff;
5527 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
5528 hr
= WINED3DERR_NOTAVAILABLE
;
5533 #if defined(STAGING_CSMT)
5534 dbuf
+= dst_row_pitch
;
5541 LONG dstyinc
= dst_row_pitch
, dstxinc
= bpp
;
5542 #else /* STAGING_CSMT */
5543 dbuf
+= dst_map
.row_pitch
;
5550 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
5551 #endif /* STAGING_CSMT */
5552 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
5553 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
5554 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
5555 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
5557 /* The color keying flags are checked for correctness in ddraw */
5558 if (flags
& WINED3D_BLT_SRC_CKEY
)
5560 keylow
= src_surface
->container
->async
.src_blt_color_key
.color_space_low_value
;
5561 keyhigh
= src_surface
->container
->async
.src_blt_color_key
.color_space_high_value
;
5563 else if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
5565 keylow
= fx
->src_color_key
.color_space_low_value
;
5566 keyhigh
= fx
->src_color_key
.color_space_high_value
;
5569 if (flags
& WINED3D_BLT_DST_CKEY
)
5571 /* Destination color keys are taken from the source surface! */
5572 destkeylow
= src_surface
->container
->async
.dst_blt_color_key
.color_space_low_value
;
5573 destkeyhigh
= src_surface
->container
->async
.dst_blt_color_key
.color_space_high_value
;
5575 else if (flags
& WINED3D_BLT_DST_CKEY_OVERRIDE
)
5577 destkeylow
= fx
->dst_color_key
.color_space_low_value
;
5578 destkeyhigh
= fx
->dst_color_key
.color_space_high_value
;
5588 get_color_masks(src_format
, masks
);
5593 flags
&= ~(WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
5594 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
);
5597 if (flags
& WINED3D_BLT_FX
)
5599 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
5602 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
5603 #if defined(STAGING_CSMT)
5604 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_row_pitch
);
5605 #else /* STAGING_CSMT */
5606 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
5607 #endif /* STAGING_CSMT */
5608 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
5610 if (fx
->fx
& WINEDDBLTFX_ARITHSTRETCHY
)
5612 /* I don't think we need to do anything about this flag */
5613 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
5615 if (fx
->fx
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
5618 dTopRight
= dTopLeft
;
5621 dBottomRight
= dBottomLeft
;
5623 dstxinc
= dstxinc
* -1;
5625 if (fx
->fx
& WINEDDBLTFX_MIRRORUPDOWN
)
5628 dTopLeft
= dBottomLeft
;
5631 dTopRight
= dBottomRight
;
5633 dstyinc
= dstyinc
* -1;
5635 if (fx
->fx
& WINEDDBLTFX_NOTEARING
)
5637 /* I don't think we need to do anything about this flag */
5638 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
5640 if (fx
->fx
& WINEDDBLTFX_ROTATE180
)
5643 dBottomRight
= dTopLeft
;
5646 dBottomLeft
= dTopRight
;
5648 dstxinc
= dstxinc
* -1;
5649 dstyinc
= dstyinc
* -1;
5651 if (fx
->fx
& WINEDDBLTFX_ROTATE270
)
5654 dTopLeft
= dBottomLeft
;
5655 dBottomLeft
= dBottomRight
;
5656 dBottomRight
= dTopRight
;
5661 dstxinc
= dstxinc
* -1;
5663 if (fx
->fx
& WINEDDBLTFX_ROTATE90
)
5666 dTopLeft
= dTopRight
;
5667 dTopRight
= dBottomRight
;
5668 dBottomRight
= dBottomLeft
;
5673 dstyinc
= dstyinc
* -1;
5675 if (fx
->fx
& WINEDDBLTFX_ZBUFFERBASEDEST
)
5677 /* I don't think we need to do anything about this flag */
5678 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
5681 flags
&= ~(WINED3D_BLT_FX
);
5684 #if defined(STAGING_CSMT)
5685 #define COPY_COLORKEY_FX(type) \
5688 type *d = (type *)dbuf, *dx, tmp; \
5689 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5691 s = (const type *)(sbase + (sy >> 16) * src_row_pitch); \
5693 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5695 tmp = s[sx >> 16]; \
5696 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5697 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5701 dx = (type *)(((BYTE *)dx) + dstxinc); \
5703 d = (type *)(((BYTE *)d) + dstyinc); \
5706 #else /* STAGING_CSMT */
5707 #define COPY_COLORKEY_FX(type) \
5710 type *d = (type *)dbuf, *dx, tmp; \
5711 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5713 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5715 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5717 tmp = s[sx >> 16]; \
5718 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5719 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5723 dx = (type *)(((BYTE *)dx) + dstxinc); \
5725 d = (type *)(((BYTE *)d) + dstyinc); \
5728 #endif /* STAGING_CSMT */
5733 COPY_COLORKEY_FX(BYTE
);
5736 COPY_COLORKEY_FX(WORD
);
5739 COPY_COLORKEY_FX(DWORD
);
5744 BYTE
*d
= dbuf
, *dx
;
5745 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5747 #if defined(STAGING_CSMT)
5748 sbuf
= sbase
+ (sy
>> 16) * src_row_pitch
;
5749 #else /* STAGING_CSMT */
5750 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5751 #endif /* STAGING_CSMT */
5753 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
5755 DWORD pixel
, dpixel
= 0;
5756 s
= sbuf
+ 3 * (sx
>>16);
5757 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5758 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
5759 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
5760 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
5762 dx
[0] = (pixel
) & 0xff;
5763 dx
[1] = (pixel
>> 8) & 0xff;
5764 dx
[2] = (pixel
>> 16) & 0xff;
5773 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5774 (flags
& WINED3D_BLT_SRC_CKEY
) ? "Source" : "Destination", bpp
* 8);
5775 hr
= WINED3DERR_NOTAVAILABLE
;
5777 #undef COPY_COLORKEY_FX
5782 #if defined(STAGING_CSMT)
5783 wined3d_resource_invalidate_location(&dst_surface
->resource
, ~dst_surface
->resource
.map_binding
);
5784 if (dst_surface
->container
)
5785 wined3d_texture_set_dirty(dst_surface
->container
);
5787 #endif /* STAGING_CSMT */
5789 if (flags
&& FIXME_ON(d3d_surface
))
5791 FIXME("\tUnsupported flags: %#x.\n", flags
);
5795 #if defined(STAGING_CSMT)
5798 wined3d_resource_release_map_ptr(&dst_surface
->resource
, context
);
5800 if (dst_surface
->container
->swapchain
5801 && dst_surface
->container
== dst_surface
->container
->swapchain
->front_buffer
)
5803 dst_surface
->lockedRect
= *dst_rect
;
5804 dst_surface
->surface_ops
->surface_frontbuffer_updated(dst_surface
);
5807 if (src_surface
&& src_surface
!= dst_surface
&& src_data
)
5808 wined3d_resource_release_map_ptr(&src_surface
->resource
, context
);
5809 /* Release the converted surface, if any. */
5811 wined3d_texture_decref(src_texture
);
5813 context_release(context
);
5814 #else /* STAGING_CSMT */
5815 wined3d_surface_unmap(dst_surface
);
5816 if (src_surface
&& src_surface
!= dst_surface
)
5817 wined3d_surface_unmap(src_surface
);
5818 /* Release the converted surface, if any. */
5820 wined3d_texture_decref(src_texture
);
5821 #endif /* STAGING_CSMT */
5826 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_rendertarget_view
*view
,
5827 const RECT
*rect
, const struct wined3d_color
*color
)
5829 struct wined3d_surface
*surface
= wined3d_rendertarget_view_get_surface(view
);
5830 static const RECT src_rect
;
5831 struct wined3d_blt_fx fx
;
5833 fx
.fill_color
= wined3d_format_convert_from_float(surface
, color
);
5834 return surface_cpu_blt(surface
, rect
, NULL
, &src_rect
,
5835 WINED3D_BLT_COLOR_FILL
, &fx
, WINED3D_TEXF_POINT
);
5838 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
5839 struct wined3d_rendertarget_view
*view
, const RECT
*rect
, float depth
)
5841 FIXME("Depth filling not implemented by cpu_blit.\n");
5842 return WINED3DERR_INVALIDCALL
;
5845 static void cpu_blit_blit_surface(struct wined3d_device
*device
, enum wined3d_blit_op op
, DWORD filter
,
5846 struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
5847 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5848 const struct wined3d_color_key
*color_key
)
5850 /* FIXME: Remove error returns from surface_blt_cpu. */
5851 ERR("Blit method not implemented by cpu_blit.\n");
5854 const struct blit_shader cpu_blit
= {
5860 cpu_blit_color_fill
,
5861 cpu_blit_depth_fill
,
5862 cpu_blit_blit_surface
,
5865 #if defined(STAGING_CSMT)
5866 void surface_blt_ugly(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5867 #else /* STAGING_CSMT */
5868 HRESULT
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5869 #endif /* STAGING_CSMT */
5870 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
5871 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
5873 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
5874 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5875 DWORD src_ds_flags
, dst_ds_flags
;
5876 BOOL scale
, convert
;
5878 static const DWORD simple_blit
= WINED3D_BLT_ASYNC
5879 | WINED3D_BLT_COLOR_FILL
5880 | WINED3D_BLT_SRC_CKEY
5881 | WINED3D_BLT_SRC_CKEY_OVERRIDE
5883 | WINED3D_BLT_DEPTH_FILL
5884 | WINED3D_BLT_DO_NOT_WAIT
5885 | WINED3D_BLT_ALPHA_TEST
;
5887 #if !defined(STAGING_CSMT)
5888 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5889 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5890 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5891 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
5895 TRACE("fx %#x.\n", fx
->fx
);
5896 TRACE("fill_color 0x%08x.\n", fx
->fill_color
);
5897 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
5898 fx
->dst_color_key
.color_space_low_value
,
5899 fx
->dst_color_key
.color_space_high_value
);
5900 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
5901 fx
->src_color_key
.color_space_low_value
,
5902 fx
->src_color_key
.color_space_high_value
);
5905 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
5907 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5908 return WINEDDERR_SURFACEBUSY
;
5911 if (dst_rect
->left
>= dst_rect
->right
|| dst_rect
->top
>= dst_rect
->bottom
5912 || dst_rect
->left
> dst_surface
->resource
.width
|| dst_rect
->left
< 0
5913 || dst_rect
->top
> dst_surface
->resource
.height
|| dst_rect
->top
< 0
5914 || dst_rect
->right
> dst_surface
->resource
.width
|| dst_rect
->right
< 0
5915 || dst_rect
->bottom
> dst_surface
->resource
.height
|| dst_rect
->bottom
< 0)
5917 WARN("The application gave us a bad destination rectangle.\n");
5918 return WINEDDERR_INVALIDRECT
;
5923 if (src_rect
->left
>= src_rect
->right
|| src_rect
->top
>= src_rect
->bottom
5924 || src_rect
->left
> src_surface
->resource
.width
|| src_rect
->left
< 0
5925 || src_rect
->top
> src_surface
->resource
.height
|| src_rect
->top
< 0
5926 || src_rect
->right
> src_surface
->resource
.width
|| src_rect
->right
< 0
5927 || src_rect
->bottom
> src_surface
->resource
.height
|| src_rect
->bottom
< 0)
5929 WARN("The application gave us a bad source rectangle.\n");
5930 return WINEDDERR_INVALIDRECT
;
5934 if (!fx
|| !(fx
->fx
))
5935 flags
&= ~WINED3D_BLT_FX
;
5937 if (flags
& WINED3D_BLT_WAIT
)
5938 flags
&= ~WINED3D_BLT_WAIT
;
5940 if (flags
& WINED3D_BLT_ASYNC
)
5942 static unsigned int once
;
5945 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
5946 flags
&= ~WINED3D_BLT_ASYNC
;
5949 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
5950 if (flags
& WINED3D_BLT_DO_NOT_WAIT
)
5952 static unsigned int once
;
5955 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
5956 flags
&= ~WINED3D_BLT_DO_NOT_WAIT
;
5959 #endif /* STAGING_CSMT */
5960 if (!device
->d3d_initialized
)
5962 WARN("D3D not initialized, using fallback.\n");
5966 /* We want to avoid invalidating the sysmem location for converted
5967 * surfaces, since otherwise we'd have to convert the data back when
5969 if (dst_surface
->container
->flags
& WINED3D_TEXTURE_CONVERTED
5970 || dst_surface
->container
->resource
.format
->convert
5971 || wined3d_format_get_color_key_conversion(dst_surface
->container
, TRUE
))
5973 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
5977 if (flags
& ~simple_blit
)
5979 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
5984 src_swapchain
= src_surface
->container
->swapchain
;
5986 src_swapchain
= NULL
;
5988 dst_swapchain
= dst_surface
->container
->swapchain
;
5990 /* This isn't strictly needed. FBO blits for example could deal with
5991 * cross-swapchain blits by first downloading the source to a texture
5992 * before switching to the destination context. We just have this here to
5993 * not have to deal with the issue, since cross-swapchain blits should be
5995 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
5997 FIXME("Using fallback for cross-swapchain blit.\n");
6002 && (src_rect
->right
- src_rect
->left
!= dst_rect
->right
- dst_rect
->left
6003 || src_rect
->bottom
- src_rect
->top
!= dst_rect
->bottom
- dst_rect
->top
);
6004 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
6006 dst_ds_flags
= dst_surface
->container
->resource
.format_flags
6007 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
6009 src_ds_flags
= src_surface
->container
->resource
.format_flags
6010 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
6014 if (src_ds_flags
|| dst_ds_flags
)
6016 if (flags
& WINED3D_BLT_DEPTH_FILL
)
6020 TRACE("Depth fill.\n");
6022 if (!surface_convert_depth_to_float(dst_surface
, fx
->fill_color
, &depth
))
6023 #if defined(STAGING_CSMT)
6026 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, dst_rect
, depth
)))
6031 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->container
->resource
.draw_binding
,
6032 src_rect
, dst_surface
, dst_surface
->container
->resource
.draw_binding
, dst_rect
)))
6034 #else /* STAGING_CSMT */
6035 return WINED3DERR_INVALIDCALL
;
6037 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, dst_rect
, depth
)))
6042 if (src_ds_flags
!= dst_ds_flags
)
6044 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
6045 return WINED3DERR_INVALIDCALL
;
6048 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->container
->resource
.draw_binding
,
6049 src_rect
, dst_surface
, dst_surface
->container
->resource
.draw_binding
, dst_rect
)))
6051 #endif /* STAGING_CSMT */
6056 const struct blit_shader
*blitter
;
6058 /* In principle this would apply to depth blits as well, but we don't
6059 * implement those in the CPU blitter at the moment. */
6060 #if defined(STAGING_CSMT)
6061 if ((dst_surface
->resource
.locations
& dst_surface
->resource
.map_binding
)
6062 && (!src_surface
|| (src_surface
->resource
.locations
& src_surface
->resource
.map_binding
)))
6063 #else /* STAGING_CSMT */
6064 if ((dst_surface
->locations
& dst_surface
->resource
.map_binding
)
6065 && (!src_surface
|| (src_surface
->locations
& src_surface
->resource
.map_binding
)))
6066 #endif /* STAGING_CSMT */
6069 TRACE("Not doing sysmem blit because of scaling.\n");
6071 TRACE("Not doing sysmem blit because of format conversion.\n");
6076 if (flags
& WINED3D_BLT_COLOR_FILL
)
6078 struct wined3d_color color
;
6079 const struct wined3d_palette
*palette
= dst_swapchain
? dst_swapchain
->palette
: NULL
;
6081 TRACE("Color fill.\n");
6083 if (!wined3d_format_convert_color_to_float(dst_surface
->resource
.format
,
6084 palette
, fx
->fill_color
, &color
))
6087 if (SUCCEEDED(surface_color_fill(dst_surface
, dst_rect
, &color
)))
6088 #if defined(STAGING_CSMT)
6090 #else /* STAGING_CSMT */
6092 #endif /* STAGING_CSMT */
6096 enum wined3d_blit_op blit_op
= WINED3D_BLIT_OP_COLOR_BLIT
;
6097 const struct wined3d_color_key
*color_key
= NULL
;
6099 TRACE("Color blit.\n");
6100 if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
6102 color_key
= &fx
->src_color_key
;
6103 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
6105 else if (flags
& WINED3D_BLT_SRC_CKEY
)
6107 color_key
= &src_surface
->container
->async
.src_blt_color_key
;
6108 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
6110 else if (flags
& WINED3D_BLT_ALPHA_TEST
)
6112 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
;
6114 #if defined(STAGING_CSMT)
6115 else if ((src_surface
->resource
.locations
& WINED3D_LOCATION_SYSMEM
)
6116 && !(dst_surface
->resource
.locations
& WINED3D_LOCATION_SYSMEM
))
6117 #else /* STAGING_CSMT */
6118 else if ((src_surface
->locations
& WINED3D_LOCATION_SYSMEM
)
6119 && !(dst_surface
->locations
& WINED3D_LOCATION_SYSMEM
))
6120 #endif /* STAGING_CSMT */
6124 TRACE("Not doing upload because of scaling.\n");
6126 TRACE("Not doing upload because of format conversion.\n");
6129 POINT dst_point
= {dst_rect
->left
, dst_rect
->top
};
6131 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, src_rect
)))
6133 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
6135 struct wined3d_context
*context
= context_acquire(device
, dst_surface
);
6136 #if defined(STAGING_CSMT)
6137 wined3d_resource_load_location(&dst_surface
->resource
, context
,
6138 dst_surface
->container
->resource
.draw_binding
);
6139 context_release(context
);
6142 #else /* STAGING_CSMT */
6143 surface_load_location(dst_surface
, context
, dst_surface
->container
->resource
.draw_binding
);
6144 context_release(context
);
6147 #endif /* STAGING_CSMT */
6151 else if (dst_swapchain
&& dst_swapchain
->back_buffers
6152 && dst_surface
->container
== dst_swapchain
->front_buffer
6153 && src_surface
->container
== dst_swapchain
->back_buffers
[0])
6155 /* Use present for back -> front blits. The idea behind this is
6156 * that present is potentially faster than a blit, in particular
6157 * when FBO blits aren't available. Some ddraw applications like
6158 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
6159 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
6160 * applications can't blit directly to the frontbuffer. */
6161 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
6163 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
6165 /* Set the swap effect to COPY, we don't want the backbuffer
6166 * to become undefined. */
6167 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
6168 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
6169 dst_swapchain
->desc
.swap_effect
= swap_effect
;
6171 #if defined(STAGING_CSMT)
6173 #else /* STAGING_CSMT */
6175 #endif /* STAGING_CSMT */
6178 if (fbo_blit_supported(&device
->adapter
->gl_info
, blit_op
,
6179 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
6180 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
6182 struct wined3d_context
*context
;
6183 TRACE("Using FBO blit.\n");
6185 context
= context_acquire(device
, NULL
);
6186 surface_blt_fbo(device
, context
, filter
,
6187 src_surface
, src_surface
->container
->resource
.draw_binding
, src_rect
,
6188 dst_surface
, dst_surface
->container
->resource
.draw_binding
, dst_rect
);
6189 context_release(context
);
6191 #if defined(STAGING_CSMT)
6192 wined3d_resource_validate_location(&dst_surface
->resource
, dst_surface
->container
->resource
.draw_binding
);
6193 wined3d_resource_invalidate_location(&dst_surface
->resource
, ~dst_surface
->container
->resource
.draw_binding
);
6196 #else /* STAGING_CSMT */
6197 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
6198 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
6201 #endif /* STAGING_CSMT */
6204 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
, blit_op
,
6205 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
6206 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
);
6209 blitter
->blit_surface(device
, blit_op
, filter
, src_surface
,
6210 src_rect
, dst_surface
, dst_rect
, color_key
);
6211 #if defined(STAGING_CSMT)
6218 /* Special cases for render targets. */
6219 if ((dst_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
6220 || (src_surface
&& (src_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)))
6222 if (SUCCEEDED(surface_blt_special(dst_surface
, dst_rect
, src_surface
, src_rect
, flags
, fx
, filter
)))
6227 surface_cpu_blt(dst_surface
, dst_rect
, src_surface
, src_rect
, flags
, fx
, filter
);
6231 HRESULT
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
6232 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
6233 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
6235 struct wined3d_device
*device
= dst_surface
->resource
.device
;
6237 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6238 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
6239 flags
, fx
, debug_d3dtexturefiltertype(filter
));
6240 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
6244 TRACE("fx %#x.\n", fx
->fx
);
6245 TRACE("fill_color 0x%08x.\n", fx
->fill_color
);
6246 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
6247 fx
->dst_color_key
.color_space_low_value
,
6248 fx
->dst_color_key
.color_space_high_value
);
6249 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
6250 fx
->src_color_key
.color_space_low_value
,
6251 fx
->src_color_key
.color_space_high_value
);
6254 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
6256 /* TODO: Separate application maps from internal maps */
6257 if (!wined3d_settings
.cs_multithreaded
)
6259 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
6260 return WINEDDERR_SURFACEBUSY
;
6263 wined3d_cs_emit_glfinish(dst_surface
->resource
.device
->cs
);
6264 dst_surface
->resource
.device
->cs
->ops
->finish(dst_surface
->resource
.device
->cs
);
6266 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
6268 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
6269 return WINEDDERR_SURFACEBUSY
;
6273 if (dst_rect
->left
>= dst_rect
->right
|| dst_rect
->top
>= dst_rect
->bottom
6274 || dst_rect
->left
> dst_surface
->resource
.width
|| dst_rect
->left
< 0
6275 || dst_rect
->top
> dst_surface
->resource
.height
|| dst_rect
->top
< 0
6276 || dst_rect
->right
> dst_surface
->resource
.width
|| dst_rect
->right
< 0
6277 || dst_rect
->bottom
> dst_surface
->resource
.height
|| dst_rect
->bottom
< 0)
6279 WARN("The application gave us a bad destination rectangle.\n");
6280 return WINEDDERR_INVALIDRECT
;
6285 DWORD src_ds_flags
, dst_ds_flags
;
6287 if (src_rect
->left
>= src_rect
->right
|| src_rect
->top
>= src_rect
->bottom
6288 || src_rect
->left
> src_surface
->resource
.width
|| src_rect
->left
< 0
6289 || src_rect
->top
> src_surface
->resource
.height
|| src_rect
->top
< 0
6290 || src_rect
->right
> src_surface
->resource
.width
|| src_rect
->right
< 0
6291 || src_rect
->bottom
> src_surface
->resource
.height
|| src_rect
->bottom
< 0)
6293 WARN("The application gave us a bad source rectangle.\n");
6294 return WINEDDERR_INVALIDRECT
;
6297 dst_ds_flags
= dst_surface
->container
->resource
.format_flags
6298 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
6299 src_ds_flags
= src_surface
->container
->resource
.format_flags
6300 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
6301 if (src_ds_flags
!= dst_ds_flags
)
6303 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
6304 return WINED3DERR_INVALIDCALL
;
6308 /* FIXME: We should select the blitter in the main thread, that way we can return an error if the blit
6309 * is unsupported without duplicating all the checks... */
6310 if (flags
& WINED3D_BLT_COLOR_FILL
&& (dst_surface
->container
->resource
.format_flags
& WINED3DFMT_FLAG_BLOCKS
))
6312 WARN("Block color fill, returning WINED3DERR_INVALIDCALL\n");
6313 return WINED3DERR_INVALIDCALL
;
6316 if (!fx
|| !(fx
->fx
))
6317 flags
&= ~WINED3D_BLT_FX
;
6319 if (flags
& WINED3D_BLT_WAIT
)
6320 flags
&= ~WINED3D_BLT_WAIT
;
6322 if (flags
& WINED3D_BLT_ASYNC
)
6324 static unsigned int once
;
6327 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
6328 flags
&= ~WINED3D_BLT_ASYNC
;
6331 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
6332 if (flags
& WINED3D_BLT_DO_NOT_WAIT
)
6334 static unsigned int once
;
6337 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
6338 flags
&= ~WINED3D_BLT_DO_NOT_WAIT
;
6341 TRACE("Emitting blit %p <== %p\n", dst_surface
, src_surface
);
6342 wined3d_cs_emit_blt(device
->cs
, dst_surface
, dst_rect
, src_surface
, src_rect
,
6348 static const struct wined3d_resource_ops surface_resource_ops
=
6350 surface_resource_incref
,
6351 surface_resource_decref
,
6353 surface_resource_sub_resource_map
,
6354 surface_resource_sub_resource_unmap
,
6355 wined3d_surface_location_invalidated
,
6356 wined3d_surface_load_location
,
6358 #else /* STAGING_CSMT */
6365 /* Special cases for render targets. */
6366 if (SUCCEEDED(surface_blt_special(dst_surface
, dst_rect
, src_surface
, src_rect
, flags
, fx
, filter
)))
6370 return surface_cpu_blt(dst_surface
, dst_rect
, src_surface
, src_rect
, flags
, fx
, filter
);
6372 #endif /* STAGING_CSMT */
6374 static HRESULT
surface_init(struct wined3d_surface
*surface
, struct wined3d_texture
*container
,
6375 const struct wined3d_resource_desc
*desc
, GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
)
6377 struct wined3d_device
*device
= container
->resource
.device
;
6378 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6379 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
);
6380 BOOL lockable
= flags
& WINED3D_TEXTURE_CREATE_MAPPABLE
;
6381 UINT multisample_quality
= desc
->multisample_quality
;
6382 unsigned int resource_size
;
6385 /* Quick lockable sanity check.
6386 * TODO: remove this after surfaces, usage and lockability have been debugged properly
6387 * this function is too deep to need to care about things like this.
6388 * Levels need to be checked too, since they all affect what can be done. */
6391 case WINED3D_POOL_MANAGED
:
6392 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
)
6393 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
6396 case WINED3D_POOL_DEFAULT
:
6397 if (lockable
&& !(desc
->usage
& (WINED3DUSAGE_DYNAMIC
6398 | WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
6399 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
6402 case WINED3D_POOL_SCRATCH
:
6403 case WINED3D_POOL_SYSTEM_MEM
:
6407 FIXME("Unknown pool %#x.\n", desc
->pool
);
6411 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
6412 FIXME("Trying to create a render target that isn't in the default pool.\n");
6414 /* FIXME: Check that the format is supported by the device. */
6416 resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, desc
->width
, desc
->height
, 1);
6418 return WINED3DERR_INVALIDCALL
;
6420 if (device
->wined3d
->flags
& WINED3D_NO3D
)
6421 surface
->surface_ops
= &gdi_surface_ops
;
6423 surface
->surface_ops
= &surface_ops
;
6425 if (FAILED(hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
,
6426 format
, desc
->multisample_type
, multisample_quality
, desc
->usage
, desc
->pool
, desc
->width
, desc
->height
,
6427 1, resource_size
, NULL
, &wined3d_null_parent_ops
, &surface_resource_ops
)))
6429 WARN("Failed to initialize resource, returning %#x.\n", hr
);
6433 surface
->container
= container
;
6434 #if defined(STAGING_CSMT)
6435 wined3d_resource_validate_location(&surface
->resource
, WINED3D_LOCATION_SYSMEM
);
6436 #else /* STAGING_CSMT */
6437 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
6438 #endif /* STAGING_CSMT */
6439 list_init(&surface
->renderbuffers
);
6440 list_init(&surface
->overlays
);
6443 if (flags
& WINED3D_TEXTURE_CREATE_DISCARD
)
6444 surface
->flags
|= SFLAG_DISCARD
;
6445 if (lockable
|| desc
->format
== WINED3DFMT_D16_LOCKABLE
)
6446 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
6448 surface
->texture_target
= target
;
6449 surface
->texture_level
= level
;
6450 surface
->texture_layer
= layer
;
6452 /* Call the private setup routine */
6453 if (FAILED(hr
= surface
->surface_ops
->surface_private_setup(surface
)))
6455 ERR("Private setup failed, hr %#x.\n", hr
);
6456 surface_cleanup(surface
);
6460 /* Similar to lockable rendertargets above, creating the DIB section
6461 * during surface initialization prevents the sysmem pointer from changing
6462 * after a wined3d_texture_get_dc() call. */
6463 if ((desc
->usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
6464 && SUCCEEDED(surface_create_dib_section(surface
)))
6465 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
6467 if (surface
->resource
.map_binding
== WINED3D_LOCATION_DIB
)
6469 wined3d_resource_free_sysmem(&surface
->resource
);
6470 #if defined(STAGING_CSMT)
6471 surface
->resource
.map_heap_memory
= NULL
;
6472 wined3d_resource_validate_location(&surface
->resource
, WINED3D_LOCATION_DIB
);
6473 wined3d_resource_invalidate_location(&surface
->resource
, WINED3D_LOCATION_SYSMEM
);
6474 #else /* STAGING_CSMT */
6475 surface_validate_location(surface
, WINED3D_LOCATION_DIB
);
6476 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
6477 #endif /* STAGING_CSMT */
6483 HRESULT
wined3d_surface_create(struct wined3d_texture
*container
, const struct wined3d_resource_desc
*desc
,
6484 GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
, struct wined3d_surface
**surface
)
6486 struct wined3d_device_parent
*device_parent
= container
->resource
.device
->device_parent
;
6487 const struct wined3d_parent_ops
*parent_ops
;
6488 struct wined3d_surface
*object
;
6492 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
6493 "multisample_type %#x, multisample_quality %u, target %#x, level %u, layer %u, flags %#x, surface %p.\n",
6494 container
, desc
->width
, desc
->height
, debug_d3dformat(desc
->format
),
6495 debug_d3dusage(desc
->usage
), desc
->usage
, debug_d3dpool(desc
->pool
),
6496 desc
->multisample_type
, desc
->multisample_quality
, target
, level
, layer
, flags
, surface
);
6498 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
6499 return E_OUTOFMEMORY
;
6501 if (FAILED(hr
= surface_init(object
, container
, desc
, target
, level
, layer
, flags
)))
6503 WARN("Failed to initialize surface, returning %#x.\n", hr
);
6504 #if defined(STAGING_CSMT)
6505 /* The command stream takes care of freeing the memory. */
6506 #else /* STAGING_CSMT */
6507 HeapFree(GetProcessHeap(), 0, object
);
6508 #endif /* STAGING_CSMT */
6512 if (FAILED(hr
= device_parent
->ops
->surface_created(device_parent
,
6513 container
, layer
* container
->level_count
+ level
, &parent
, &parent_ops
)))
6515 WARN("Failed to create surface parent, hr %#x.\n", hr
);
6516 wined3d_surface_destroy(object
);
6520 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object
, parent
, parent_ops
);
6522 object
->resource
.parent
= parent
;
6523 object
->resource
.parent_ops
= parent_ops
;
6529 /* Context activation is done by the caller. */
6530 void wined3d_surface_prepare(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
6534 case WINED3D_LOCATION_TEXTURE_RGB
:
6535 wined3d_texture_prepare_texture(surface
->container
, context
, FALSE
);
6538 case WINED3D_LOCATION_TEXTURE_SRGB
:
6539 wined3d_texture_prepare_texture(surface
->container
, context
, TRUE
);
6542 case WINED3D_LOCATION_RB_MULTISAMPLE
:
6543 surface_prepare_rb(surface
, context
->gl_info
, TRUE
);
6546 case WINED3D_LOCATION_RB_RESOLVED
:
6547 surface_prepare_rb(surface
, context
->gl_info
, FALSE
);