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
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
36 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
38 static const DWORD surface_simple_locations
=
39 WINED3D_LOCATION_SYSMEM
| WINED3D_LOCATION_USER_MEMORY
40 | WINED3D_LOCATION_DIB
| WINED3D_LOCATION_BUFFER
;
42 void wined3d_surface_cleanup(struct wined3d_surface
*surface
)
44 struct wined3d_surface
*overlay
, *cur
;
46 TRACE("surface %p.\n", surface
);
48 if (surface
->rb_multisample
|| surface
->rb_resolved
|| !list_empty(&surface
->renderbuffers
))
50 struct wined3d_device
*device
= surface
->container
->resource
.device
;
51 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
52 const struct wined3d_gl_info
*gl_info
;
53 struct wined3d_context
*context
;
55 context
= context_acquire(device
, NULL
);
56 gl_info
= context
->gl_info
;
58 if (surface
->rb_multisample
)
60 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
61 context_gl_resource_released(device
, surface
->rb_multisample
, TRUE
);
62 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
65 if (surface
->rb_resolved
)
67 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
68 context_gl_resource_released(device
, surface
->rb_resolved
, TRUE
);
69 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
72 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
74 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
75 context_gl_resource_released(device
, entry
->id
, TRUE
);
76 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
77 HeapFree(GetProcessHeap(), 0, entry
);
80 context_release(context
);
83 if (surface
->flags
& SFLAG_DIBSECTION
)
85 DeleteDC(surface
->hDC
);
86 DeleteObject(surface
->dib
.DIBsection
);
87 surface
->dib
.bitmap_data
= NULL
;
90 if (surface
->overlay_dest
)
91 list_remove(&surface
->overlay_entry
);
93 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
95 list_remove(&overlay
->overlay_entry
);
96 overlay
->overlay_dest
= NULL
;
99 resource_cleanup(&surface
->resource
);
102 void surface_get_drawable_size(const struct wined3d_surface
*surface
, const struct wined3d_context
*context
,
103 unsigned int *width
, unsigned int *height
)
105 if (surface
->container
->swapchain
)
107 /* The drawable size of an onscreen drawable is the surface size.
108 * (Actually: The window size, but the surface is created in window
110 *width
= context
->current_rt
.texture
->resource
.width
;
111 *height
= context
->current_rt
.texture
->resource
.height
;
113 else if (wined3d_settings
.offscreen_rendering_mode
== ORM_BACKBUFFER
)
115 const struct wined3d_swapchain
*swapchain
= context
->swapchain
;
117 /* The drawable size of a backbuffer / aux buffer offscreen target is
118 * the size of the current context's drawable, which is the size of
119 * the back buffer of the swapchain the active context belongs to. */
120 *width
= swapchain
->desc
.backbuffer_width
;
121 *height
= swapchain
->desc
.backbuffer_height
;
125 struct wined3d_surface
*rt
;
127 /* The drawable size of an FBO target is the OpenGL texture size,
128 * which is the power of two size. */
129 rt
= context
->current_rt
.texture
->sub_resources
[context
->current_rt
.sub_resource_idx
].u
.surface
;
130 *width
= rt
->pow2Width
;
131 *height
= rt
->pow2Height
;
139 enum wined3d_gl_resource_type tex_type
;
140 GLfloat coords
[4][3];
151 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
153 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
154 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
155 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
156 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
159 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
161 GLfloat (*coords
)[3] = info
->coords
;
167 FIXME("Unsupported texture target %#x\n", target
);
168 /* Fall back to GL_TEXTURE_2D */
170 info
->binding
= GL_TEXTURE_BINDING_2D
;
171 info
->bind_target
= GL_TEXTURE_2D
;
172 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_2D
;
173 coords
[0][0] = (float)rect
->left
/ w
;
174 coords
[0][1] = (float)rect
->top
/ h
;
177 coords
[1][0] = (float)rect
->right
/ w
;
178 coords
[1][1] = (float)rect
->top
/ h
;
181 coords
[2][0] = (float)rect
->left
/ w
;
182 coords
[2][1] = (float)rect
->bottom
/ h
;
185 coords
[3][0] = (float)rect
->right
/ w
;
186 coords
[3][1] = (float)rect
->bottom
/ h
;
190 case GL_TEXTURE_RECTANGLE_ARB
:
191 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
192 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
193 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_RECT
;
194 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
195 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
196 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
197 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
200 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
201 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
202 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
203 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
204 cube_coords_float(rect
, w
, h
, &f
);
206 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
207 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
208 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
209 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
212 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
213 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
214 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
215 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
216 cube_coords_float(rect
, w
, h
, &f
);
218 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
219 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
220 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
221 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
224 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
225 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
226 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
227 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
228 cube_coords_float(rect
, w
, h
, &f
);
230 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
231 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
232 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
233 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
236 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
237 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
238 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
239 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
240 cube_coords_float(rect
, w
, h
, &f
);
242 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
243 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
244 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
245 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
248 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
249 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
250 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
251 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
252 cube_coords_float(rect
, w
, h
, &f
);
254 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
255 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
256 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
257 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
260 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
261 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
262 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
263 info
->tex_type
= WINED3D_GL_RES_TYPE_TEX_CUBE
;
264 cube_coords_float(rect
, w
, h
, &f
);
266 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
267 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
268 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
269 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
274 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
277 *rect_out
= *rect_in
;
282 rect_out
->right
= surface
->resource
.width
;
283 rect_out
->bottom
= surface
->resource
.height
;
287 /* Context activation is done by the caller. */
288 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
289 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
291 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
292 struct wined3d_texture
*texture
= src_surface
->container
;
293 struct blt_info info
;
295 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
297 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
298 checkGLcall("glEnable(bind_target)");
300 context_bind_texture(context
, info
.bind_target
, texture
->texture_rgb
.name
);
302 /* Filtering for StretchRect */
303 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
304 checkGLcall("glTexParameteri");
305 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
306 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
307 checkGLcall("glTexParameteri");
308 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
309 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
310 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
311 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
312 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
313 checkGLcall("glTexEnvi");
316 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
317 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
318 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
320 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
321 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
323 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
324 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
326 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
327 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
328 gl_info
->gl_ops
.gl
.p_glEnd();
330 /* Unbind the texture */
331 context_bind_texture(context
, info
.bind_target
, 0);
333 /* We changed the filtering settings on the texture. Inform the
334 * container about this to get the filters reset properly next draw. */
335 texture
->texture_rgb
.sampler_desc
.mag_filter
= WINED3D_TEXF_POINT
;
336 texture
->texture_rgb
.sampler_desc
.min_filter
= WINED3D_TEXF_POINT
;
337 texture
->texture_rgb
.sampler_desc
.mip_filter
= WINED3D_TEXF_NONE
;
338 texture
->texture_rgb
.sampler_desc
.srgb_decode
= FALSE
;
341 /* Works correctly only for <= 4 bpp formats. */
342 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
344 masks
[0] = ((1u << format
->red_size
) - 1) << format
->red_offset
;
345 masks
[1] = ((1u << format
->green_size
) - 1) << format
->green_offset
;
346 masks
[2] = ((1u << format
->blue_size
) - 1) << format
->blue_offset
;
349 HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
351 struct wined3d_texture
*texture
= surface
->container
;
352 const struct wined3d_format
*format
= texture
->resource
.format
;
353 unsigned int format_flags
= texture
->resource
.format_flags
;
354 unsigned int row_pitch
, slice_pitch
;
358 TRACE("surface %p.\n", surface
);
360 if (!(format_flags
& WINED3DFMT_FLAG_GETDC
))
362 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
363 return WINED3DERR_INVALIDCALL
;
366 switch (format
->byte_count
)
370 /* Allocate extra space to store the RGB bit masks. */
371 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3]));
375 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[0]));
379 /* Allocate extra space for a palette. */
380 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
381 FIELD_OFFSET(BITMAPINFO
, bmiColors
[1u << (format
->byte_count
* 8)]));
386 return E_OUTOFMEMORY
;
388 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
389 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &row_pitch
, &slice_pitch
);
390 b_info
->bmiHeader
.biWidth
= row_pitch
/ format
->byte_count
;
391 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
;
392 b_info
->bmiHeader
.biSizeImage
= slice_pitch
;
393 b_info
->bmiHeader
.biPlanes
= 1;
394 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
396 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
397 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
398 b_info
->bmiHeader
.biClrUsed
= 0;
399 b_info
->bmiHeader
.biClrImportant
= 0;
401 /* Get the bit masks */
402 masks
= (DWORD
*)b_info
->bmiColors
;
405 case WINED3DFMT_B8G8R8_UNORM
:
406 b_info
->bmiHeader
.biCompression
= BI_RGB
;
409 case WINED3DFMT_B5G5R5X1_UNORM
:
410 case WINED3DFMT_B5G5R5A1_UNORM
:
411 case WINED3DFMT_B4G4R4A4_UNORM
:
412 case WINED3DFMT_B4G4R4X4_UNORM
:
413 case WINED3DFMT_B2G3R3_UNORM
:
414 case WINED3DFMT_B2G3R3A8_UNORM
:
415 case WINED3DFMT_R10G10B10A2_UNORM
:
416 case WINED3DFMT_R8G8B8A8_UNORM
:
417 case WINED3DFMT_R8G8B8X8_UNORM
:
418 case WINED3DFMT_B10G10R10A2_UNORM
:
419 case WINED3DFMT_B5G6R5_UNORM
:
420 case WINED3DFMT_R16G16B16A16_UNORM
:
421 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
422 get_color_masks(format
, masks
);
426 /* Don't know palette */
427 b_info
->bmiHeader
.biCompression
= BI_RGB
;
431 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
432 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
433 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
434 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->dib
.bitmap_data
, 0, 0);
436 if (!surface
->dib
.DIBsection
)
438 ERR("Failed to create DIB section.\n");
439 HeapFree(GetProcessHeap(), 0, b_info
);
440 return HRESULT_FROM_WIN32(GetLastError());
443 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
444 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
446 HeapFree(GetProcessHeap(), 0, b_info
);
448 /* Now allocate a DC. */
449 surface
->hDC
= CreateCompatibleDC(0);
450 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
452 surface
->flags
|= SFLAG_DIBSECTION
;
457 static void surface_get_memory(const struct wined3d_surface
*surface
, struct wined3d_bo_address
*data
,
460 if (location
& WINED3D_LOCATION_BUFFER
)
463 data
->buffer_object
= surface
->container
->sub_resources
[surface_get_sub_resource_idx(surface
)].buffer_object
;
466 if (location
& WINED3D_LOCATION_USER_MEMORY
)
468 data
->addr
= surface
->container
->user_memory
;
469 data
->buffer_object
= 0;
472 if (location
& WINED3D_LOCATION_DIB
)
474 data
->addr
= surface
->dib
.bitmap_data
;
475 data
->buffer_object
= 0;
478 if (location
& WINED3D_LOCATION_SYSMEM
)
480 data
->addr
= surface
->resource
.heap_memory
;
481 data
->buffer_object
= 0;
485 ERR("Unexpected locations %s.\n", wined3d_debug_location(location
));
487 data
->buffer_object
= 0;
490 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
492 TRACE("surface %p.\n", surface
);
494 if (surface
->resource
.heap_memory
)
497 /* Whatever surface we have, make sure that there is memory allocated
498 * for the downloaded copy, or a PBO to map. */
499 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
500 ERR("Failed to allocate system memory.\n");
502 if (surface_get_sub_resource(surface
)->locations
& WINED3D_LOCATION_SYSMEM
)
503 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
506 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
508 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
509 struct wined3d_texture
*texture
= surface
->container
;
511 if (surface
->resource
.map_count
|| texture
->download_count
> MAXLOCKCOUNT
512 || texture
->flags
& (WINED3D_TEXTURE_CONVERTED
| WINED3D_TEXTURE_PIN_SYSMEM
))
515 wined3d_resource_free_sysmem(&surface
->resource
);
516 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_SYSMEM
);
519 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
521 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
523 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
528 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
529 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
530 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
532 const struct wined3d_gl_info
*gl_info
;
533 struct wined3d_context
*context
;
534 DWORD src_mask
, dst_mask
;
537 TRACE("device %p\n", device
);
538 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
539 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
540 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
541 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
543 src_mask
= src_surface
->container
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
544 dst_mask
= dst_surface
->container
->resource
.format_flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
546 if (src_mask
!= dst_mask
)
548 ERR("Incompatible formats %s and %s.\n",
549 debug_d3dformat(src_surface
->container
->resource
.format
->id
),
550 debug_d3dformat(dst_surface
->container
->resource
.format
->id
));
556 ERR("Not a depth / stencil format: %s.\n",
557 debug_d3dformat(src_surface
->container
->resource
.format
->id
));
562 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
563 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
564 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
565 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
567 context
= context_acquire(device
, NULL
);
570 context_release(context
);
571 WARN("Invalid context, skipping blit.\n");
575 /* Make sure the locations are up-to-date. Loading the destination
576 * surface isn't required if the entire surface is overwritten. */
577 surface_load_location(src_surface
, context
, src_location
);
578 if (!surface_is_full_rect(dst_surface
, dst_rect
))
579 surface_load_location(dst_surface
, context
, dst_location
);
581 wined3d_surface_prepare(dst_surface
, context
, dst_location
);
583 gl_info
= context
->gl_info
;
585 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
586 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
588 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
589 context_set_draw_buffer(context
, GL_NONE
);
590 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
591 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
593 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
595 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
596 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
598 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
600 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
602 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
603 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
605 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
606 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
609 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
610 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
612 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
613 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
614 checkGLcall("glBlitFramebuffer()");
616 if (wined3d_settings
.strict_draw_ordering
)
617 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
619 context_release(context
);
622 /* Blit between surface locations. Onscreen on different swapchains is not supported.
623 * Depth / stencil is not supported. Context activation is done by the caller. */
624 static void surface_blt_fbo(const struct wined3d_device
*device
,
625 struct wined3d_context
*old_ctx
, enum wined3d_texture_filter_type filter
,
626 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
627 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
629 const struct wined3d_gl_info
*gl_info
;
630 struct wined3d_context
*context
= old_ctx
;
631 struct wined3d_surface
*required_rt
, *restore_rt
= NULL
;
632 RECT src_rect
, dst_rect
;
636 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
637 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
638 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
639 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
640 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
642 src_rect
= *src_rect_in
;
643 dst_rect
= *dst_rect_in
;
647 case WINED3D_TEXF_LINEAR
:
648 gl_filter
= GL_LINEAR
;
652 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
653 case WINED3D_TEXF_NONE
:
654 case WINED3D_TEXF_POINT
:
655 gl_filter
= GL_NEAREST
;
659 /* Resolve the source surface first if needed. */
660 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
661 && (src_surface
->container
->resource
.format
->id
!= dst_surface
->container
->resource
.format
->id
662 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
663 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
664 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
666 /* Make sure the locations are up-to-date. Loading the destination
667 * surface isn't required if the entire surface is overwritten. (And is
668 * in fact harmful if we're being called by surface_load_location() with
669 * the purpose of loading the destination surface.) */
670 surface_load_location(src_surface
, old_ctx
, src_location
);
671 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
672 surface_load_location(dst_surface
, old_ctx
, dst_location
);
674 wined3d_surface_prepare(dst_surface
, old_ctx
, dst_location
);
677 if (src_location
== WINED3D_LOCATION_DRAWABLE
) required_rt
= src_surface
;
678 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) required_rt
= dst_surface
;
679 else required_rt
= NULL
;
681 restore_rt
= context_get_rt_surface(old_ctx
);
682 if (restore_rt
!= required_rt
)
683 context
= context_acquire(device
, required_rt
);
689 context_release(context
);
690 WARN("Invalid context, skipping blit.\n");
694 gl_info
= context
->gl_info
;
696 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
698 TRACE("Source surface %p is onscreen.\n", src_surface
);
699 buffer
= wined3d_texture_get_gl_buffer(src_surface
->container
);
700 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
704 TRACE("Source surface %p is offscreen.\n", src_surface
);
705 buffer
= GL_COLOR_ATTACHMENT0
;
708 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
709 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
710 checkGLcall("glReadBuffer()");
711 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
713 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
715 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
716 buffer
= wined3d_texture_get_gl_buffer(dst_surface
->container
);
717 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
721 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
722 buffer
= GL_COLOR_ATTACHMENT0
;
725 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
726 context_set_draw_buffer(context
, buffer
);
727 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
728 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
730 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
731 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
732 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
733 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
734 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
736 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
737 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
739 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
740 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
741 checkGLcall("glBlitFramebuffer()");
743 if (wined3d_settings
.strict_draw_ordering
744 || (dst_location
== WINED3D_LOCATION_DRAWABLE
745 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
746 gl_info
->gl_ops
.gl
.p_glFlush();
749 context_restore(context
, restore_rt
);
752 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
753 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
754 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
756 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
759 /* Source and/or destination need to be on the GL side */
760 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
765 case WINED3D_BLIT_OP_COLOR_BLIT
:
766 if (!((src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
767 || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
769 if (!((dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
770 || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
772 if (!(src_format
->id
== dst_format
->id
773 || (is_identity_fixup(src_format
->color_fixup
)
774 && is_identity_fixup(dst_format
->color_fixup
))))
778 case WINED3D_BLIT_OP_DEPTH_BLIT
:
779 if (!(src_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
781 if (!(dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
783 /* Accept pure swizzle fixups for depth formats. In general we
784 * ignore the stencil component (if present) at the moment and the
785 * swizzle is not relevant with just the depth component. */
786 if (is_complex_fixup(src_format
->color_fixup
) || is_complex_fixup(dst_format
->color_fixup
)
787 || is_scaling_fixup(src_format
->color_fixup
) || is_scaling_fixup(dst_format
->color_fixup
))
798 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
800 const struct wined3d_format
*format
= surface
->container
->resource
.format
;
804 case WINED3DFMT_S1_UINT_D15_UNORM
:
805 *float_depth
= depth
/ (float)0x00007fff;
808 case WINED3DFMT_D16_UNORM
:
809 *float_depth
= depth
/ (float)0x0000ffff;
812 case WINED3DFMT_D24_UNORM_S8_UINT
:
813 case WINED3DFMT_X8D24_UNORM
:
814 *float_depth
= depth
/ (float)0x00ffffff;
817 case WINED3DFMT_D32_UNORM
:
818 *float_depth
= depth
/ (float)0xffffffff;
822 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
829 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
831 struct wined3d_resource
*resource
= &surface
->container
->resource
;
832 struct wined3d_device
*device
= resource
->device
;
833 struct wined3d_rendertarget_view_desc view_desc
;
834 struct wined3d_rendertarget_view
*view
;
835 const struct blit_shader
*blitter
;
838 if (!(blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
,
839 WINED3D_BLIT_OP_DEPTH_FILL
, NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
)))
841 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
842 return WINED3DERR_INVALIDCALL
;
845 view_desc
.format_id
= resource
->format
->id
;
846 view_desc
.u
.texture
.level_idx
= surface
->texture_level
;
847 view_desc
.u
.texture
.layer_idx
= surface
->texture_layer
;
848 view_desc
.u
.texture
.layer_count
= 1;
849 if (FAILED(hr
= wined3d_rendertarget_view_create(&view_desc
,
850 resource
, NULL
, &wined3d_null_parent_ops
, &view
)))
852 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
856 hr
= blitter
->depth_fill(device
, view
, rect
, WINED3DCLEAR_ZBUFFER
, depth
, 0);
857 wined3d_rendertarget_view_decref(view
);
862 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
863 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
865 struct wined3d_texture
*src_texture
= src_surface
->container
;
866 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
867 struct wined3d_device
*device
= src_texture
->resource
.device
;
869 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
870 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
871 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
))
872 return WINED3DERR_INVALIDCALL
;
874 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
876 surface_modify_ds_location(dst_surface
, dst_location
,
877 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
882 static ULONG
surface_resource_incref(struct wined3d_resource
*resource
)
884 struct wined3d_surface
*surface
= surface_from_resource(resource
);
886 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
888 return wined3d_texture_incref(surface
->container
);
891 static ULONG
surface_resource_decref(struct wined3d_resource
*resource
)
893 struct wined3d_surface
*surface
= surface_from_resource(resource
);
895 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
897 return wined3d_texture_decref(surface
->container
);
900 static void surface_unload(struct wined3d_resource
*resource
)
902 struct wined3d_surface
*surface
= surface_from_resource(resource
);
903 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
904 struct wined3d_texture
*texture
= surface
->container
;
905 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
906 struct wined3d_device
*device
= resource
->device
;
907 const struct wined3d_gl_info
*gl_info
;
908 struct wined3d_context
*context
;
910 TRACE("surface %p.\n", surface
);
912 context
= context_acquire(device
, NULL
);
913 gl_info
= context
->gl_info
;
915 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
917 /* Default pool resources are supposed to be destroyed before Reset is called.
918 * Implicit resources stay however. So this means we have an implicit render target
919 * or depth stencil. The content may be destroyed, but we still have to tear down
920 * opengl resources, so we cannot leave early.
922 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
923 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
924 * or the depth stencil into an FBO the texture or render buffer will be removed
925 * and all flags get lost */
926 if (resource
->usage
& WINED3DUSAGE_DEPTHSTENCIL
)
928 wined3d_texture_validate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_DISCARDED
);
929 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, ~WINED3D_LOCATION_DISCARDED
);
933 surface_prepare_system_memory(surface
);
934 memset(surface
->resource
.heap_memory
, 0, surface
->resource
.size
);
935 wined3d_texture_validate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_SYSMEM
);
936 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, ~WINED3D_LOCATION_SYSMEM
);
941 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
942 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, ~surface
->resource
.map_binding
);
945 /* Destroy fbo render buffers. This is needed for implicit render targets, for
946 * all application-created targets the application has to release the surface
947 * before calling _Reset
949 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
951 context_gl_resource_released(device
, entry
->id
, TRUE
);
952 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
953 list_remove(&entry
->entry
);
954 HeapFree(GetProcessHeap(), 0, entry
);
956 list_init(&surface
->renderbuffers
);
957 surface
->current_renderbuffer
= NULL
;
959 if (surface
->rb_multisample
)
961 context_gl_resource_released(device
, surface
->rb_multisample
, TRUE
);
962 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
963 surface
->rb_multisample
= 0;
965 if (surface
->rb_resolved
)
967 context_gl_resource_released(device
, surface
->rb_resolved
, TRUE
);
968 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
969 surface
->rb_resolved
= 0;
972 context_release(context
);
974 resource_unload(resource
);
977 static HRESULT
surface_resource_sub_resource_map(struct wined3d_resource
*resource
, unsigned int sub_resource_idx
,
978 struct wined3d_map_desc
*map_desc
, const struct wined3d_box
*box
, DWORD flags
)
980 ERR("Not supported on sub-resources.\n");
981 return WINED3DERR_INVALIDCALL
;
984 static HRESULT
surface_resource_sub_resource_unmap(struct wined3d_resource
*resource
, unsigned int sub_resource_idx
)
986 ERR("Not supported on sub-resources.\n");
987 return WINED3DERR_INVALIDCALL
;
990 static const struct wined3d_resource_ops surface_resource_ops
=
992 surface_resource_incref
,
993 surface_resource_decref
,
995 surface_resource_sub_resource_map
,
996 surface_resource_sub_resource_unmap
,
999 /* This call just downloads data, the caller is responsible for binding the
1000 * correct texture. */
1001 /* Context activation is done by the caller. */
1002 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1005 struct wined3d_texture
*texture
= surface
->container
;
1006 const struct wined3d_format
*format
= texture
->resource
.format
;
1007 struct wined3d_bo_address data
;
1009 /* Only support read back of converted P8 surfaces. */
1010 if (texture
->flags
& WINED3D_TEXTURE_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1012 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1016 surface_get_memory(surface
, &data
, dst_location
);
1018 if (texture
->resource
.format_flags
& WINED3DFMT_FLAG_COMPRESSED
)
1020 TRACE("(%p) : Calling glGetCompressedTexImage level %d, format %#x, type %#x, data %p.\n",
1021 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, data
.addr
);
1023 if (data
.buffer_object
)
1025 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1026 checkGLcall("glBindBuffer");
1027 GL_EXTCALL(glGetCompressedTexImage(surface
->texture_target
, surface
->texture_level
, NULL
));
1028 checkGLcall("glGetCompressedTexImage");
1029 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1030 checkGLcall("glBindBuffer");
1034 GL_EXTCALL(glGetCompressedTexImage(surface
->texture_target
,
1035 surface
->texture_level
, data
.addr
));
1036 checkGLcall("glGetCompressedTexImage");
1041 unsigned int dst_row_pitch
, dst_slice_pitch
;
1042 unsigned int src_row_pitch
, src_slice_pitch
;
1043 GLenum gl_format
= format
->glFormat
;
1044 GLenum gl_type
= format
->glType
;
1047 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
1049 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &dst_row_pitch
, &dst_slice_pitch
);
1050 wined3d_format_calculate_pitch(format
, texture
->resource
.device
->surface_alignment
,
1051 surface
->pow2Width
, surface
->pow2Height
, &src_row_pitch
, &src_slice_pitch
);
1052 mem
= HeapAlloc(GetProcessHeap(), 0, src_slice_pitch
);
1059 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1060 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1062 if (data
.buffer_object
)
1064 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1065 checkGLcall("glBindBuffer");
1067 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1068 gl_format
, gl_type
, NULL
);
1069 checkGLcall("glGetTexImage");
1071 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1072 checkGLcall("glBindBuffer");
1076 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1077 gl_format
, gl_type
, mem
);
1078 checkGLcall("glGetTexImage");
1081 if (texture
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
1083 const BYTE
*src_data
;
1087 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1088 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1089 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1091 * We're doing this...
1093 * instead of boxing the texture :
1094 * |<-texture width ->| -->pow2width| /\
1095 * |111111111111111111| | |
1096 * |222 Texture 222222| boxed empty | texture height
1097 * |3333 Data 33333333| | |
1098 * |444444444444444444| | \/
1099 * ----------------------------------- |
1100 * | boxed empty | boxed empty | pow2height
1102 * -----------------------------------
1105 * we're repacking the data to the expected texture width
1107 * |<-texture width ->| -->pow2width| /\
1108 * |111111111111111111222222222222222| |
1109 * |222333333333333333333444444444444| texture height
1113 * | empty | pow2height
1115 * -----------------------------------
1119 * |<-texture width ->| /\
1120 * |111111111111111111|
1121 * |222222222222222222|texture height
1122 * |333333333333333333|
1123 * |444444444444444444| \/
1124 * --------------------
1126 * This also means that any references to surface memory should work with the data as if it were a
1127 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1129 * internally the texture is still stored in a boxed format so any references to textureName will
1130 * get a boxed texture with width pow2width and not a texture of width resource.width. */
1132 dst_data
= data
.addr
;
1133 TRACE("Repacking the surface data from pitch %u to pitch %u.\n", src_row_pitch
, dst_row_pitch
);
1134 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1136 memcpy(dst_data
, src_data
, dst_row_pitch
);
1137 src_data
+= src_row_pitch
;
1138 dst_data
+= dst_row_pitch
;
1141 HeapFree(GetProcessHeap(), 0, mem
);
1146 /* This call just uploads data, the caller is responsible for binding the
1147 * correct texture. */
1148 /* Context activation is done by the caller. */
1149 void wined3d_surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1150 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1151 BOOL srgb
, const struct wined3d_const_bo_address
*data
)
1153 struct wined3d_texture
*texture
= surface
->container
;
1154 UINT update_w
= src_rect
->right
- src_rect
->left
;
1155 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1157 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1158 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1159 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1161 if (surface
->resource
.map_count
)
1163 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1164 texture
->flags
|= WINED3D_TEXTURE_PIN_SYSMEM
;
1167 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_HEIGHT_SCALE
)
1169 update_h
*= format
->height_scale
.numerator
;
1170 update_h
/= format
->height_scale
.denominator
;
1173 if (data
->buffer_object
)
1175 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, data
->buffer_object
));
1176 checkGLcall("glBindBuffer");
1179 if (format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_COMPRESSED
)
1181 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1182 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1183 const BYTE
*addr
= data
->addr
;
1186 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1187 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1190 internal
= format
->glGammaInternal
;
1191 else if (texture
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1192 && wined3d_resource_is_offscreen(&texture
->resource
))
1193 internal
= format
->rtInternal
;
1195 internal
= format
->glInternal
;
1197 TRACE("glCompressedTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, "
1198 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1199 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1201 if (row_length
== src_pitch
)
1203 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1204 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1210 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1211 * can't use the unpack row length like for glTexSubImage2D. */
1212 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1214 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1215 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1216 y
+= format
->block_height
;
1220 checkGLcall("glCompressedTexSubImage2D");
1224 const BYTE
*addr
= data
->addr
;
1226 addr
+= src_rect
->top
* src_pitch
;
1227 addr
+= src_rect
->left
* format
->byte_count
;
1229 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1230 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1231 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1233 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1234 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1235 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1236 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1237 checkGLcall("glTexSubImage2D");
1240 if (data
->buffer_object
)
1242 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
1243 checkGLcall("glBindBuffer");
1246 if (wined3d_settings
.strict_draw_ordering
)
1247 gl_info
->gl_ops
.gl
.p_glFlush();
1249 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1251 struct wined3d_device
*device
= texture
->resource
.device
;
1254 for (i
= 0; i
< device
->context_count
; ++i
)
1256 context_surface_update(device
->contexts
[i
], surface
);
1261 static BOOL
surface_check_block_align_rect(struct wined3d_surface
*surface
, const RECT
*rect
)
1263 struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
1265 return wined3d_texture_check_block_align(surface
->container
, surface
->texture_level
, &box
);
1268 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1269 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1271 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
1272 struct wined3d_texture
*src_texture
= src_surface
->container
;
1273 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
1274 unsigned int src_row_pitch
, src_slice_pitch
;
1275 const struct wined3d_format
*src_format
;
1276 const struct wined3d_format
*dst_format
;
1277 unsigned int src_fmt_flags
, dst_fmt_flags
;
1278 const struct wined3d_gl_info
*gl_info
;
1279 struct wined3d_context
*context
;
1280 struct wined3d_bo_address data
;
1281 UINT update_w
, update_h
;
1286 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1287 dst_surface
, wine_dbgstr_point(dst_point
),
1288 src_surface
, wine_dbgstr_rect(src_rect
));
1290 src_format
= src_texture
->resource
.format
;
1291 dst_format
= dst_texture
->resource
.format
;
1292 src_fmt_flags
= src_texture
->resource
.format_flags
;
1293 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
1295 if (src_format
->id
!= dst_format
->id
)
1297 WARN("Source and destination surfaces should have the same format.\n");
1298 return WINED3DERR_INVALIDCALL
;
1307 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1309 WARN("Invalid destination point.\n");
1310 return WINED3DERR_INVALIDCALL
;
1315 SetRect(&r
, 0, 0, src_surface
->resource
.width
, src_surface
->resource
.height
);
1318 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
1319 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
1321 WARN("Invalid source rectangle.\n");
1322 return WINED3DERR_INVALIDCALL
;
1325 dst_w
= dst_surface
->resource
.width
;
1326 dst_h
= dst_surface
->resource
.height
;
1328 update_w
= src_rect
->right
- src_rect
->left
;
1329 update_h
= src_rect
->bottom
- src_rect
->top
;
1331 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1332 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1334 WARN("Destination out of bounds.\n");
1335 return WINED3DERR_INVALIDCALL
;
1338 if ((src_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align_rect(src_surface
, src_rect
))
1340 WARN("Source rectangle not block-aligned.\n");
1341 return WINED3DERR_INVALIDCALL
;
1344 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1345 if ((dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align_rect(dst_surface
, &dst_rect
))
1347 WARN("Destination rectangle not block-aligned.\n");
1348 return WINED3DERR_INVALIDCALL
;
1351 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1352 if (dst_format
->convert
|| wined3d_format_get_color_key_conversion(dst_texture
, FALSE
))
1353 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1355 context
= context_acquire(dst_texture
->resource
.device
, NULL
);
1356 gl_info
= context
->gl_info
;
1358 /* Only load the surface for partial updates. For newly allocated texture
1359 * the texture wouldn't be the current location, and we'd upload zeroes
1360 * just to overwrite them again. */
1361 if (update_w
== dst_w
&& update_h
== dst_h
)
1362 wined3d_texture_prepare_texture(dst_texture
, context
, FALSE
);
1364 surface_load_location(dst_surface
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
1365 wined3d_texture_bind_and_dirtify(dst_texture
, context
, FALSE
);
1367 surface_get_memory(src_surface
, &data
, surface_get_sub_resource(src_surface
)->locations
);
1368 wined3d_texture_get_pitch(src_texture
, src_surface
->texture_level
, &src_row_pitch
, &src_slice_pitch
);
1370 wined3d_surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
,
1371 src_row_pitch
, dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1373 context_release(context
);
1375 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
1376 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1381 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1382 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1383 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1384 /* Context activation is done by the caller. */
1385 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1387 const struct wined3d_gl_info
*gl_info
= &surface
->container
->resource
.device
->adapter
->gl_info
;
1388 struct wined3d_renderbuffer_entry
*entry
;
1389 GLuint renderbuffer
= 0;
1390 unsigned int src_width
, src_height
;
1391 unsigned int width
, height
;
1393 if (rt
&& rt
->container
->resource
.format
->id
!= WINED3DFMT_NULL
)
1395 width
= rt
->pow2Width
;
1396 height
= rt
->pow2Height
;
1400 width
= surface
->pow2Width
;
1401 height
= surface
->pow2Height
;
1404 src_width
= surface
->pow2Width
;
1405 src_height
= surface
->pow2Height
;
1407 /* A depth stencil smaller than the render target is not valid */
1408 if (width
> src_width
|| height
> src_height
) return;
1410 /* Remove any renderbuffer set if the sizes match */
1411 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1412 || (width
== src_width
&& height
== src_height
))
1414 surface
->current_renderbuffer
= NULL
;
1418 /* Look if we've already got a renderbuffer of the correct dimensions */
1419 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1421 if (entry
->width
== width
&& entry
->height
== height
)
1423 renderbuffer
= entry
->id
;
1424 surface
->current_renderbuffer
= entry
;
1431 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
1432 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
1433 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
1434 surface
->container
->resource
.format
->glInternal
, width
, height
);
1436 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
1437 entry
->width
= width
;
1438 entry
->height
= height
;
1439 entry
->id
= renderbuffer
;
1440 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
1442 surface
->current_renderbuffer
= entry
;
1445 checkGLcall("set_compatible_renderbuffer");
1448 /* Context activation is done by the caller. */
1449 void surface_load(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
1451 DWORD location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
1453 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
1455 if (surface
->container
->resource
.pool
== WINED3D_POOL_SCRATCH
)
1456 ERR("Not supported on scratch surfaces.\n");
1458 if (surface_get_sub_resource(surface
)->locations
& location
)
1460 TRACE("surface is already in texture\n");
1463 TRACE("Reloading because surface is dirty.\n");
1465 surface_load_location(surface
, context
, location
);
1466 surface_evict_sysmem(surface
);
1469 /* See also float_16_to_32() in wined3d_private.h */
1470 static inline unsigned short float_32_to_16(const float *in
)
1473 float tmp
= fabsf(*in
);
1474 unsigned int mantissa
;
1477 /* Deal with special numbers */
1483 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
1485 if (tmp
< (float)(1u << 10))
1491 } while (tmp
< (float)(1u << 10));
1493 else if (tmp
>= (float)(1u << 11))
1499 } while (tmp
>= (float)(1u << 11));
1502 mantissa
= (unsigned int)tmp
;
1503 if (tmp
- mantissa
>= 0.5f
)
1504 ++mantissa
; /* Round to nearest, away from zero. */
1506 exp
+= 10; /* Normalize the mantissa. */
1507 exp
+= 15; /* Exponent is encoded with excess 15. */
1509 if (exp
> 30) /* too big */
1511 ret
= 0x7c00; /* INF */
1515 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1518 mantissa
= mantissa
>> 1;
1521 ret
= mantissa
& 0x3ff;
1525 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
1528 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
1532 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
1533 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1535 unsigned short *dst_s
;
1539 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1541 for (y
= 0; y
< h
; ++y
)
1543 src_f
= (const float *)(src
+ y
* pitch_in
);
1544 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
1545 for (x
= 0; x
< w
; ++x
)
1547 dst_s
[x
] = float_32_to_16(src_f
+ x
);
1552 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1553 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1555 static const unsigned char convert_5to8
[] =
1557 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
1558 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
1559 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
1560 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
1562 static const unsigned char convert_6to8
[] =
1564 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
1565 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
1566 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
1567 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
1568 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
1569 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
1570 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
1571 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
1575 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1577 for (y
= 0; y
< h
; ++y
)
1579 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
1580 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1581 for (x
= 0; x
< w
; ++x
)
1583 WORD pixel
= src_line
[x
];
1584 dst_line
[x
] = 0xff000000u
1585 | convert_5to8
[(pixel
& 0xf800u
) >> 11] << 16
1586 | convert_6to8
[(pixel
& 0x07e0u
) >> 5] << 8
1587 | convert_5to8
[(pixel
& 0x001fu
)];
1592 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
1593 * in both cases we're just setting the X / Alpha channel to 0xff. */
1594 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1595 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1599 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1601 for (y
= 0; y
< h
; ++y
)
1603 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
1604 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1606 for (x
= 0; x
< w
; ++x
)
1608 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
1613 static inline BYTE
cliptobyte(int x
)
1615 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
1618 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
1619 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1621 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
1624 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
1626 for (y
= 0; y
< h
; ++y
)
1628 const BYTE
*src_line
= src
+ y
* pitch_in
;
1629 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
1630 for (x
= 0; x
< w
; ++x
)
1632 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1633 * C = Y - 16; D = U - 128; E = V - 128;
1634 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1635 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1636 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1637 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1638 * U and V are shared between the pixels. */
1639 if (!(x
& 1)) /* For every even pixel, read new U and V. */
1641 d
= (int) src_line
[1] - 128;
1642 e
= (int) src_line
[3] - 128;
1644 g2
= - 100 * d
- 208 * e
+ 128;
1647 c2
= 298 * ((int) src_line
[0] - 16);
1648 dst_line
[x
] = 0xff000000
1649 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
1650 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
1651 | cliptobyte((c2
+ b2
) >> 8); /* blue */
1652 /* Scale RGB values to 0..255 range,
1653 * then clip them if still not in range (may be negative),
1654 * then shift them within DWORD if necessary. */
1660 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
1661 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
1664 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
1666 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
1668 for (y
= 0; y
< h
; ++y
)
1670 const BYTE
*src_line
= src
+ y
* pitch_in
;
1671 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
1672 for (x
= 0; x
< w
; ++x
)
1674 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
1675 * C = Y - 16; D = U - 128; E = V - 128;
1676 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
1677 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
1678 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
1679 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
1680 * U and V are shared between the pixels. */
1681 if (!(x
& 1)) /* For every even pixel, read new U and V. */
1683 d
= (int) src_line
[1] - 128;
1684 e
= (int) src_line
[3] - 128;
1686 g2
= - 100 * d
- 208 * e
+ 128;
1689 c2
= 298 * ((int) src_line
[0] - 16);
1690 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
1691 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
1692 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
1693 /* Scale RGB values to 0..255 range,
1694 * then clip them if still not in range (may be negative),
1695 * then shift them within DWORD if necessary. */
1701 struct d3dfmt_converter_desc
1703 enum wined3d_format_id from
, to
;
1704 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
1707 static const struct d3dfmt_converter_desc converters
[] =
1709 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
1710 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
1711 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
1712 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
1713 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
1714 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
1717 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
1718 enum wined3d_format_id to
)
1722 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
1724 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
1725 return &converters
[i
];
1731 static struct wined3d_texture
*surface_convert_format(struct wined3d_texture
*src_texture
,
1732 unsigned int sub_resource_idx
, enum wined3d_format_id format
)
1734 struct wined3d_map_desc src_map
, dst_map
;
1735 const struct d3dfmt_converter_desc
*conv
;
1736 struct wined3d_texture
*dst_texture
;
1737 struct wined3d_resource_desc desc
;
1739 if (!(conv
= find_converter(src_texture
->resource
.format
->id
, format
)))
1741 FIXME("Cannot find a conversion function from format %s to %s.\n",
1742 debug_d3dformat(src_texture
->resource
.format
->id
), debug_d3dformat(format
));
1746 /* FIXME: Multisampled conversion? */
1747 wined3d_resource_get_desc(src_texture
->sub_resources
[sub_resource_idx
].resource
, &desc
);
1748 desc
.resource_type
= WINED3D_RTYPE_TEXTURE_2D
;
1749 desc
.format
= format
;
1751 desc
.pool
= WINED3D_POOL_SCRATCH
;
1752 if (FAILED(wined3d_texture_create(src_texture
->resource
.device
, &desc
, 1,
1753 WINED3D_TEXTURE_CREATE_MAPPABLE
| WINED3D_TEXTURE_CREATE_DISCARD
,
1754 NULL
, NULL
, &wined3d_null_parent_ops
, &dst_texture
)))
1756 ERR("Failed to create a destination texture for conversion.\n");
1760 memset(&src_map
, 0, sizeof(src_map
));
1761 memset(&dst_map
, 0, sizeof(dst_map
));
1763 if (FAILED(wined3d_resource_map(&src_texture
->resource
, sub_resource_idx
,
1764 &src_map
, NULL
, WINED3D_MAP_READONLY
)))
1766 ERR("Failed to map the source texture.\n");
1767 wined3d_texture_decref(dst_texture
);
1770 if (FAILED(wined3d_resource_map(&dst_texture
->resource
, 0, &dst_map
, NULL
, 0)))
1772 ERR("Failed to map the destination texture.\n");
1773 wined3d_resource_unmap(&src_texture
->resource
, sub_resource_idx
);
1774 wined3d_texture_decref(dst_texture
);
1778 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
, desc
.width
, desc
.height
);
1780 wined3d_resource_unmap(&dst_texture
->resource
, 0);
1781 wined3d_resource_unmap(&src_texture
->resource
, sub_resource_idx
);
1786 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
1787 unsigned int bpp
, UINT pitch
, DWORD color
)
1794 #define COLORFILL_ROW(type) \
1796 type *d = (type *)buf; \
1797 for (x = 0; x < width; ++x) \
1798 d[x] = (type)color; \
1804 COLORFILL_ROW(BYTE
);
1808 COLORFILL_ROW(WORD
);
1814 for (x
= 0; x
< width
; ++x
, d
+= 3)
1816 d
[0] = (color
) & 0xff;
1817 d
[1] = (color
>> 8) & 0xff;
1818 d
[2] = (color
>> 16) & 0xff;
1823 COLORFILL_ROW(DWORD
);
1827 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
1828 return WINED3DERR_NOTAVAILABLE
;
1831 #undef COLORFILL_ROW
1833 /* Now copy first row. */
1835 for (y
= 1; y
< height
; ++y
)
1838 memcpy(buf
, first
, width
* bpp
);
1844 static void read_from_framebuffer(struct wined3d_surface
*surface
,
1845 struct wined3d_context
*old_ctx
, DWORD dst_location
)
1847 struct wined3d_texture
*texture
= surface
->container
;
1848 struct wined3d_device
*device
= texture
->resource
.device
;
1849 const struct wined3d_gl_info
*gl_info
;
1850 struct wined3d_context
*context
= old_ctx
;
1851 struct wined3d_surface
*restore_rt
= NULL
;
1852 unsigned int row_pitch
, slice_pitch
;
1854 BYTE
*row
, *top
, *bottom
;
1856 BOOL srcIsUpsideDown
;
1857 struct wined3d_bo_address data
;
1859 surface_get_memory(surface
, &data
, dst_location
);
1861 restore_rt
= context_get_rt_surface(old_ctx
);
1862 if (restore_rt
!= surface
)
1863 context
= context_acquire(device
, surface
);
1867 context_apply_blit_state(context
, device
);
1868 gl_info
= context
->gl_info
;
1870 /* Select the correct read buffer, and give some debug output.
1871 * There is no need to keep track of the current read buffer or reset it, every part of the code
1872 * that reads sets the read buffer as desired.
1874 if (wined3d_resource_is_offscreen(&texture
->resource
))
1876 /* Mapping the primary render target which is not on a swapchain.
1877 * Read from the back buffer. */
1878 TRACE("Mapping offscreen render target.\n");
1879 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
1880 srcIsUpsideDown
= TRUE
;
1884 /* Onscreen surfaces are always part of a swapchain */
1885 GLenum buffer
= wined3d_texture_get_gl_buffer(texture
);
1886 TRACE("Mapping %#x buffer.\n", buffer
);
1887 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
1888 checkGLcall("glReadBuffer");
1889 srcIsUpsideDown
= FALSE
;
1892 if (data
.buffer_object
)
1894 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1895 checkGLcall("glBindBuffer");
1898 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &row_pitch
, &slice_pitch
);
1900 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1901 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, row_pitch
/ texture
->resource
.format
->byte_count
);
1902 checkGLcall("glPixelStorei");
1904 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0,
1905 surface
->resource
.width
, surface
->resource
.height
,
1906 texture
->resource
.format
->glFormat
,
1907 texture
->resource
.format
->glType
, data
.addr
);
1908 checkGLcall("glReadPixels");
1910 /* Reset previous pixel store pack state */
1911 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
1912 checkGLcall("glPixelStorei");
1914 if (!srcIsUpsideDown
)
1916 /* glReadPixels returns the image upside down, and there is no way to
1917 * prevent this. Flip the lines in software. */
1919 if (!(row
= HeapAlloc(GetProcessHeap(), 0, row_pitch
)))
1922 if (data
.buffer_object
)
1924 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
1925 checkGLcall("glMapBuffer");
1931 bottom
= mem
+ row_pitch
* (surface
->resource
.height
- 1);
1932 for (i
= 0; i
< surface
->resource
.height
/ 2; i
++)
1934 memcpy(row
, top
, row_pitch
);
1935 memcpy(top
, bottom
, row_pitch
);
1936 memcpy(bottom
, row
, row_pitch
);
1938 bottom
-= row_pitch
;
1940 HeapFree(GetProcessHeap(), 0, row
);
1942 if (data
.buffer_object
)
1943 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
1947 if (data
.buffer_object
)
1949 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1950 checkGLcall("glBindBuffer");
1954 context_restore(context
, restore_rt
);
1957 /* Read the framebuffer contents into a texture. Note that this function
1958 * doesn't do any kind of flipping. Using this on an onscreen surface will
1959 * result in a flipped D3D texture.
1961 * Context activation is done by the caller. This function may temporarily
1962 * switch to a different context and restore the original one before return. */
1963 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
, struct wined3d_context
*old_ctx
)
1965 struct wined3d_texture
*texture
= surface
->container
;
1966 struct wined3d_device
*device
= texture
->resource
.device
;
1967 const struct wined3d_gl_info
*gl_info
;
1968 struct wined3d_context
*context
= old_ctx
;
1969 struct wined3d_surface
*restore_rt
= NULL
;
1971 restore_rt
= context_get_rt_surface(old_ctx
);
1972 if (restore_rt
!= surface
)
1973 context
= context_acquire(device
, surface
);
1977 gl_info
= context
->gl_info
;
1978 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
1980 wined3d_texture_prepare_texture(texture
, context
, srgb
);
1981 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
1983 TRACE("Reading back offscreen render target %p.\n", surface
);
1985 if (wined3d_resource_is_offscreen(&texture
->resource
))
1986 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
1988 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(texture
));
1989 checkGLcall("glReadBuffer");
1991 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1992 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
1993 checkGLcall("glCopyTexSubImage2D");
1996 context_restore(context
, restore_rt
);
1999 static void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
2001 struct wined3d_texture
*texture
= surface
->container
;
2002 const struct wined3d_format
*format
= texture
->resource
.format
;
2008 if (surface
->rb_multisample
)
2011 /* TODO: Nvidia exposes their Coverage Sample Anti-Aliasing (CSAA) feature
2012 * through type == MULTISAMPLE_XX and quality != 0. This could be mapped
2013 * to GL_NV_framebuffer_multisample_coverage.
2015 * AMD has a similar feature called Enhanced Quality Anti-Aliasing (EQAA),
2016 * but it does not have an equivalent OpenGL extension. */
2018 /* We advertise as many WINED3D_MULTISAMPLE_NON_MASKABLE quality levels
2019 * as the count of advertised multisample types for the surface format. */
2020 if (texture
->resource
.multisample_type
== WINED3D_MULTISAMPLE_NON_MASKABLE
)
2022 unsigned int i
, count
= 0;
2024 for (i
= 0; i
< sizeof(format
->multisample_types
) * 8; ++i
)
2026 if (format
->multisample_types
& 1u << i
)
2028 if (texture
->resource
.multisample_quality
== count
++)
2036 samples
= texture
->resource
.multisample_type
;
2039 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
2040 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
2041 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, samples
,
2042 format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
2043 checkGLcall("glRenderbufferStorageMultisample()");
2044 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
2048 if (surface
->rb_resolved
)
2051 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
2052 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
2053 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, format
->glInternal
,
2054 surface
->pow2Width
, surface
->pow2Height
);
2055 checkGLcall("glRenderbufferStorage()");
2056 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
2060 /* Does a direct frame buffer -> texture copy. Stretching is done with single
2061 * pixel copy calls. */
2062 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
2063 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
2065 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
2066 struct wined3d_texture
*src_texture
= src_surface
->container
;
2067 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2068 struct wined3d_device
*device
= dst_texture
->resource
.device
;
2069 const struct wined3d_gl_info
*gl_info
;
2071 struct wined3d_context
*context
;
2072 BOOL upsidedown
= FALSE
;
2073 RECT dst_rect
= *dst_rect_in
;
2075 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2076 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2078 if(dst_rect
.top
> dst_rect
.bottom
) {
2079 UINT tmp
= dst_rect
.bottom
;
2080 dst_rect
.bottom
= dst_rect
.top
;
2085 context
= context_acquire(device
, src_surface
);
2086 gl_info
= context
->gl_info
;
2087 context_apply_blit_state(context
, device
);
2088 wined3d_texture_load(dst_texture
, context
, FALSE
);
2090 /* Bind the target texture */
2091 context_bind_texture(context
, dst_texture
->target
, dst_texture
->texture_rgb
.name
);
2092 if (wined3d_resource_is_offscreen(&src_texture
->resource
))
2094 TRACE("Reading from an offscreen target\n");
2095 upsidedown
= !upsidedown
;
2096 gl_info
->gl_ops
.gl
.p_glReadBuffer(context_get_offscreen_gl_buffer(context
));
2100 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture
));
2102 checkGLcall("glReadBuffer");
2104 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
2105 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
2107 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
2109 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2111 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
2112 ERR("Texture filtering not supported in direct blit.\n");
2114 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
2115 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
2117 ERR("Texture filtering not supported in direct blit\n");
2121 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
2122 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
2124 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
2125 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
2126 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
2127 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
2128 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
2133 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
2134 /* I have to process this row by row to swap the image,
2135 * otherwise it would be upside down, so stretching in y direction
2136 * doesn't cost extra time
2138 * However, stretching in x direction can be avoided if not necessary
2140 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
2141 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
2143 /* Well, that stuff works, but it's very slow.
2144 * find a better way instead
2148 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
2150 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
2151 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
2152 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
2157 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
2158 dst_rect
.left
/* x offset */, row
/* y offset */,
2159 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
2163 checkGLcall("glCopyTexSubImage2D");
2165 context_release(context
);
2167 /* The texture is now most up to date - If the surface is a render target
2168 * and has a drawable, this path is never entered. */
2169 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
2170 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
2173 /* Uses the hardware to stretch and flip the image */
2174 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
2175 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
2177 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
2178 struct wined3d_texture
*src_texture
= src_surface
->container
;
2179 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2180 struct wined3d_device
*device
= dst_texture
->resource
.device
;
2181 GLuint src
, backup
= 0;
2182 float left
, right
, top
, bottom
; /* Texture coordinates */
2183 UINT fbwidth
= src_surface
->resource
.width
;
2184 UINT fbheight
= src_surface
->resource
.height
;
2185 const struct wined3d_gl_info
*gl_info
;
2186 struct wined3d_context
*context
;
2187 GLenum drawBuffer
= GL_BACK
;
2188 GLenum offscreen_buffer
;
2189 GLenum texture_target
;
2190 BOOL noBackBufferBackup
;
2192 BOOL upsidedown
= FALSE
;
2193 RECT dst_rect
= *dst_rect_in
;
2195 TRACE("Using hwstretch blit\n");
2196 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2197 context
= context_acquire(device
, src_surface
);
2198 gl_info
= context
->gl_info
;
2199 context_apply_blit_state(context
, device
);
2200 wined3d_texture_load(dst_texture
, context
, FALSE
);
2202 offscreen_buffer
= context_get_offscreen_gl_buffer(context
);
2204 src_offscreen
= wined3d_resource_is_offscreen(&src_texture
->resource
);
2205 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
2206 if (!noBackBufferBackup
&& !src_texture
->texture_rgb
.name
)
2208 /* Get it a description */
2209 wined3d_texture_load(src_texture
, context
, FALSE
);
2212 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2213 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2215 if (context
->aux_buffers
>= 2)
2217 /* Got more than one aux buffer? Use the 2nd aux buffer */
2218 drawBuffer
= GL_AUX1
;
2220 else if ((!src_offscreen
|| offscreen_buffer
== GL_BACK
) && context
->aux_buffers
>= 1)
2222 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2223 drawBuffer
= GL_AUX0
;
2226 if (noBackBufferBackup
)
2228 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
2229 checkGLcall("glGenTextures");
2230 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
2231 texture_target
= GL_TEXTURE_2D
;
2235 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2236 * we are reading from the back buffer, the backup can be used as source texture
2238 texture_target
= src_surface
->texture_target
;
2239 context_bind_texture(context
, texture_target
, src_texture
->texture_rgb
.name
);
2240 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
2241 checkGLcall("glEnable(texture_target)");
2243 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2244 surface_get_sub_resource(src_surface
)->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
2247 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2248 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2250 if(dst_rect
.top
> dst_rect
.bottom
) {
2251 UINT tmp
= dst_rect
.bottom
;
2252 dst_rect
.bottom
= dst_rect
.top
;
2259 TRACE("Reading from an offscreen target\n");
2260 upsidedown
= !upsidedown
;
2261 gl_info
->gl_ops
.gl
.p_glReadBuffer(offscreen_buffer
);
2265 gl_info
->gl_ops
.gl
.p_glReadBuffer(wined3d_texture_get_gl_buffer(src_texture
));
2268 /* TODO: Only back up the part that will be overwritten */
2269 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
2271 checkGLcall("glCopyTexSubImage2D");
2273 /* No issue with overriding these - the sampler is dirty due to blit usage */
2274 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
2275 checkGLcall("glTexParameteri");
2276 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
2277 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
2278 checkGLcall("glTexParameteri");
2280 if (!src_texture
->swapchain
|| src_texture
== src_texture
->swapchain
->back_buffers
[0])
2282 src
= backup
? backup
: src_texture
->texture_rgb
.name
;
2286 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
2287 checkGLcall("glReadBuffer(GL_FRONT)");
2289 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
2290 checkGLcall("glGenTextures(1, &src)");
2291 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
2293 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
2294 * out for power of 2 sizes
2296 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
2297 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
2298 checkGLcall("glTexImage2D");
2299 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
2301 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2302 checkGLcall("glTexParameteri");
2303 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2304 checkGLcall("glTexParameteri");
2306 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
2307 checkGLcall("glReadBuffer(GL_BACK)");
2309 if (texture_target
!= GL_TEXTURE_2D
)
2311 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2312 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
2313 texture_target
= GL_TEXTURE_2D
;
2316 checkGLcall("glEnd and previous");
2318 left
= src_rect
->left
;
2319 right
= src_rect
->right
;
2323 top
= src_surface
->resource
.height
- src_rect
->top
;
2324 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
2328 top
= src_surface
->resource
.height
- src_rect
->bottom
;
2329 bottom
= src_surface
->resource
.height
- src_rect
->top
;
2332 if (src_texture
->flags
& WINED3D_TEXTURE_NORMALIZED_COORDS
)
2334 left
/= src_surface
->pow2Width
;
2335 right
/= src_surface
->pow2Width
;
2336 top
/= src_surface
->pow2Height
;
2337 bottom
/= src_surface
->pow2Height
;
2340 /* draw the source texture stretched and upside down. The correct surface is bound already */
2341 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2342 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2344 context_set_draw_buffer(context
, drawBuffer
);
2345 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
2347 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
2349 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
2350 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
2353 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
2354 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
2357 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
2358 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
2361 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
2362 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
2363 gl_info
->gl_ops
.gl
.p_glEnd();
2364 checkGLcall("glEnd and previous");
2366 if (texture_target
!= dst_surface
->texture_target
)
2368 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2369 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
2370 texture_target
= dst_surface
->texture_target
;
2373 /* Now read the stretched and upside down image into the destination texture */
2374 context_bind_texture(context
, texture_target
, dst_texture
->texture_rgb
.name
);
2375 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
2377 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
2378 0, 0, /* We blitted the image to the origin */
2379 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
2380 checkGLcall("glCopyTexSubImage2D");
2382 if (drawBuffer
== GL_BACK
)
2384 /* Write the back buffer backup back. */
2387 if (texture_target
!= GL_TEXTURE_2D
)
2389 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2390 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
2391 texture_target
= GL_TEXTURE_2D
;
2393 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
2397 if (texture_target
!= src_surface
->texture_target
)
2399 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2400 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
2401 texture_target
= src_surface
->texture_target
;
2403 context_bind_texture(context
, src_surface
->texture_target
, src_texture
->texture_rgb
.name
);
2406 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
2408 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
2409 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
2412 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
2413 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
2416 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
2417 (float)fbheight
/ (float)src_surface
->pow2Height
);
2418 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
2421 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
2422 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
2423 gl_info
->gl_ops
.gl
.p_glEnd();
2425 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
2426 checkGLcall("glDisable(texture_target)");
2429 if (src
!= src_texture
->texture_rgb
.name
&& src
!= backup
)
2431 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
2432 checkGLcall("glDeleteTextures(1, &src)");
2436 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
2437 checkGLcall("glDeleteTextures(1, &backup)");
2440 if (wined3d_settings
.strict_draw_ordering
)
2441 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2443 context_release(context
);
2445 /* The texture is now most up to date - If the surface is a render target
2446 * and has a drawable, this path is never entered. */
2447 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, WINED3D_LOCATION_TEXTURE_RGB
);
2448 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~WINED3D_LOCATION_TEXTURE_RGB
);
2451 /* Front buffer coordinates are always full screen coordinates, but our GL
2452 * drawable is limited to the window's client area. The sysmem and texture
2453 * copies do have the full screen size. Note that GL has a bottom-left
2454 * origin, while D3D has a top-left origin. */
2455 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
2457 UINT drawable_height
;
2459 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
2461 POINT offset
= {0, 0};
2464 ScreenToClient(window
, &offset
);
2465 OffsetRect(rect
, offset
.x
, offset
.y
);
2467 GetClientRect(window
, &windowsize
);
2468 drawable_height
= windowsize
.bottom
- windowsize
.top
;
2472 drawable_height
= surface
->resource
.height
;
2475 rect
->top
= drawable_height
- rect
->top
;
2476 rect
->bottom
= drawable_height
- rect
->bottom
;
2479 /* Context activation is done by the caller. */
2480 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
2481 struct wined3d_context
*old_ctx
,
2482 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
2483 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
2484 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
2486 struct wined3d_texture
*src_texture
= src_surface
->container
;
2487 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2488 const struct wined3d_gl_info
*gl_info
;
2489 struct wined3d_context
*context
= old_ctx
;
2490 struct wined3d_surface
*restore_rt
= NULL
;
2491 RECT src_rect
, dst_rect
;
2493 src_rect
= *src_rect_in
;
2494 dst_rect
= *dst_rect_in
;
2496 restore_rt
= context_get_rt_surface(old_ctx
);
2497 if (restore_rt
!= dst_surface
)
2498 context
= context_acquire(device
, dst_surface
);
2502 gl_info
= context
->gl_info
;
2504 /* Make sure the surface is up-to-date. This should probably use
2505 * surface_load_location() and worry about the destination surface too,
2506 * unless we're overwriting it completely. */
2507 wined3d_texture_load(src_texture
, context
, FALSE
);
2509 /* Activate the destination context, set it up for blitting */
2510 context_apply_blit_state(context
, device
);
2512 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
2513 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
2515 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
, NULL
);
2519 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
2520 checkGLcall("glEnable(GL_ALPHA_TEST)");
2522 /* For P8 surfaces, the alpha component contains the palette index.
2523 * Which means that the colorkey is one of the palette entries. In
2524 * other cases pixels that should be masked away have alpha set to 0. */
2525 if (src_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
2526 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
2527 (float)src_texture
->async
.src_blt_color_key
.color_space_low_value
/ 255.0f
);
2529 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
2530 checkGLcall("glAlphaFunc");
2534 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2535 checkGLcall("glDisable(GL_ALPHA_TEST)");
2538 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
2542 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2543 checkGLcall("glDisable(GL_ALPHA_TEST)");
2546 /* Leave the opengl state valid for blitting */
2547 device
->blitter
->unset_shader(context
->gl_info
);
2549 if (wined3d_settings
.strict_draw_ordering
2550 || (dst_texture
->swapchain
&& dst_texture
->swapchain
->front_buffer
== dst_texture
))
2551 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2554 context_restore(context
, restore_rt
);
2557 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
2559 struct wined3d_resource
*resource
= &s
->container
->resource
;
2560 struct wined3d_device
*device
= resource
->device
;
2561 struct wined3d_rendertarget_view_desc view_desc
;
2562 struct wined3d_rendertarget_view
*view
;
2563 const struct blit_shader
*blitter
;
2566 if (!(blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
,
2567 WINED3D_BLIT_OP_COLOR_FILL
, NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
)))
2569 FIXME("No blitter is capable of performing the requested color fill operation.\n");
2570 return WINED3DERR_INVALIDCALL
;
2573 view_desc
.format_id
= resource
->format
->id
;
2574 view_desc
.u
.texture
.level_idx
= s
->texture_level
;
2575 view_desc
.u
.texture
.layer_idx
= s
->texture_layer
;
2576 view_desc
.u
.texture
.layer_count
= 1;
2577 if (FAILED(hr
= wined3d_rendertarget_view_create(&view_desc
,
2578 resource
, NULL
, &wined3d_null_parent_ops
, &view
)))
2580 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
2584 hr
= blitter
->color_fill(device
, view
, rect
, color
);
2585 wined3d_rendertarget_view_decref(view
);
2590 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
2591 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
2592 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
2594 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
2595 struct wined3d_device
*device
= dst_texture
->resource
.device
;
2596 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->fb
.render_targets
[0]);
2597 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
2598 struct wined3d_texture
*src_texture
;
2600 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2601 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
2602 flags
, fx
, debug_d3dtexturefiltertype(filter
));
2604 /* Get the swapchain. One of the surfaces has to be a primary surface */
2605 if (dst_texture
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
2607 WARN("Destination is in sysmem, rejecting gl blt\n");
2608 return WINED3DERR_INVALIDCALL
;
2611 dst_swapchain
= dst_texture
->swapchain
;
2615 src_texture
= src_surface
->container
;
2616 if (src_texture
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
2618 WARN("Src is in sysmem, rejecting gl blt\n");
2619 return WINED3DERR_INVALIDCALL
;
2622 src_swapchain
= src_texture
->swapchain
;
2627 src_swapchain
= NULL
;
2630 /* Early sort out of cases where no render target is used */
2631 if (!dst_swapchain
&& !src_swapchain
&& src_surface
!= rt
&& dst_surface
!= rt
)
2633 TRACE("No surface is render target, not using hardware blit.\n");
2634 return WINED3DERR_INVALIDCALL
;
2637 /* No destination color keying supported */
2638 if (flags
& (WINED3D_BLT_DST_CKEY
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
2640 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2641 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2642 return WINED3DERR_INVALIDCALL
;
2645 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
2647 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
2648 return WINED3DERR_INVALIDCALL
;
2651 if (dst_swapchain
&& src_swapchain
)
2653 FIXME("Implement hardware blit between two different swapchains\n");
2654 return WINED3DERR_INVALIDCALL
;
2659 /* Handled with regular texture -> swapchain blit */
2660 if (src_surface
== rt
)
2661 TRACE("Blit from active render target to a swapchain\n");
2663 else if (src_swapchain
&& dst_surface
== rt
)
2665 FIXME("Implement blit from a swapchain to the active render target\n");
2666 return WINED3DERR_INVALIDCALL
;
2669 if ((src_swapchain
|| src_surface
== rt
) && !dst_swapchain
)
2671 /* Blit from render target to texture */
2674 /* P8 read back is not implemented */
2675 if (src_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
2676 || dst_texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
2678 TRACE("P8 read back not supported by frame buffer to texture blit\n");
2679 return WINED3DERR_INVALIDCALL
;
2682 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_SRC_CKEY_OVERRIDE
))
2684 TRACE("Color keying not supported by frame buffer to texture blit\n");
2685 return WINED3DERR_INVALIDCALL
;
2686 /* Destination color key is checked above */
2689 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
2694 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2695 * flip the image nor scale it.
2697 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2698 * -> If the app wants an image width an unscaled width, copy it line per line
2699 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
2700 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2701 * back buffer. This is slower than reading line per line, thus not used for flipping
2702 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2703 * pixel by pixel. */
2704 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
2705 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
2707 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
2708 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
2712 TRACE("Using hardware stretching to flip / stretch the texture.\n");
2713 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
2716 surface_evict_sysmem(dst_surface
);
2721 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2722 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2723 return WINED3DERR_INVALIDCALL
;
2726 /* Context activation is done by the caller. */
2727 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
2728 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
2730 struct wined3d_device
*device
= surface
->container
->resource
.device
;
2731 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2732 GLint compare_mode
= GL_NONE
;
2733 struct blt_info info
;
2734 GLint old_binding
= 0;
2737 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
2739 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
2740 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
2741 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
2742 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
2743 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
2744 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
2745 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
2746 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
2747 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
2748 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
2749 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
2751 SetRect(&rect
, 0, h
, w
, 0);
2752 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
2753 context_active_texture(context
, context
->gl_info
, 0);
2754 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
2755 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
2756 if (gl_info
->supported
[ARB_SHADOW
])
2758 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
2759 if (compare_mode
!= GL_NONE
)
2760 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
2763 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
2764 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
2766 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
2767 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
2768 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
2769 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
2770 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
2771 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
2772 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
2773 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
2774 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
2775 gl_info
->gl_ops
.gl
.p_glEnd();
2777 if (compare_mode
!= GL_NONE
)
2778 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
2779 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
2781 gl_info
->gl_ops
.gl
.p_glPopAttrib();
2783 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
2786 void surface_modify_ds_location(struct wined3d_surface
*surface
,
2787 DWORD location
, UINT w
, UINT h
)
2789 struct wined3d_texture_sub_resource
*sub_resource
;
2791 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
2793 sub_resource
= surface_get_sub_resource(surface
);
2794 if (((sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
2795 || (!(sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
)
2796 && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
2797 wined3d_texture_set_dirty(surface
->container
);
2799 surface
->ds_current_size
.cx
= w
;
2800 surface
->ds_current_size
.cy
= h
;
2801 sub_resource
->locations
= location
;
2804 /* Context activation is done by the caller. */
2805 static void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
2807 struct wined3d_texture
*texture
= surface
->container
;
2808 struct wined3d_device
*device
= texture
->resource
.device
;
2809 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2812 TRACE("surface %p, context %p, new location %#x.\n", surface
, context
, location
);
2814 /* TODO: Make this work for modes other than FBO */
2815 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
2817 if (!(surface_get_sub_resource(surface
)->locations
& location
))
2819 w
= surface
->ds_current_size
.cx
;
2820 h
= surface
->ds_current_size
.cy
;
2821 surface
->ds_current_size
.cx
= 0;
2822 surface
->ds_current_size
.cy
= 0;
2826 w
= surface
->resource
.width
;
2827 h
= surface
->resource
.height
;
2830 if (surface
->current_renderbuffer
)
2832 FIXME("Not supported with fixed up depth stencil.\n");
2836 wined3d_surface_prepare(surface
, context
, location
);
2838 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
2840 GLint old_binding
= 0;
2843 /* The render target is allowed to be smaller than the depth/stencil
2844 * buffer, so the onscreen depth/stencil buffer is potentially smaller
2845 * than the offscreen surface. Don't overwrite the offscreen surface
2846 * with undefined data. */
2847 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
2848 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
2850 TRACE("Copying onscreen depth buffer to depth texture.\n");
2852 if (!device
->depth_blt_texture
)
2853 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
2855 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
2856 * directly on the FBO texture. That's because we need to flip. */
2857 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
2858 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
2859 NULL
, WINED3D_LOCATION_DRAWABLE
);
2860 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
2862 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
2863 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
2867 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
2868 bind_target
= GL_TEXTURE_2D
;
2870 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
2871 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
2872 * internal format, because the internal format might include stencil
2873 * data. In principle we should copy stencil data as well, but unless
2874 * the driver supports stencil export it's hard to do, and doesn't
2875 * seem to be needed in practice. If the hardware doesn't support
2876 * writing stencil data, the glCopyTexImage2D() call might trigger
2877 * software fallbacks. */
2878 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
2879 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2880 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2881 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2882 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2883 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
2884 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
2886 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
2887 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
2888 context_set_draw_buffer(context
, GL_NONE
);
2890 /* Do the actual blit */
2891 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
2892 checkGLcall("depth_blt");
2894 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
2896 if (wined3d_settings
.strict_draw_ordering
)
2897 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2899 else if (location
== WINED3D_LOCATION_DRAWABLE
)
2901 TRACE("Copying depth texture to onscreen depth buffer.\n");
2903 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
2904 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
2905 NULL
, WINED3D_LOCATION_DRAWABLE
);
2906 surface_depth_blt(surface
, context
, texture
->texture_rgb
.name
,
2907 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
2908 checkGLcall("depth_blt");
2910 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
2912 if (wined3d_settings
.strict_draw_ordering
)
2913 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
2917 ERR("Invalid location (%#x) specified.\n", location
);
2921 static DWORD
resource_access_from_location(DWORD location
)
2925 case WINED3D_LOCATION_SYSMEM
:
2926 case WINED3D_LOCATION_USER_MEMORY
:
2927 case WINED3D_LOCATION_DIB
:
2928 case WINED3D_LOCATION_BUFFER
:
2929 return WINED3D_RESOURCE_ACCESS_CPU
;
2931 case WINED3D_LOCATION_DRAWABLE
:
2932 case WINED3D_LOCATION_TEXTURE_SRGB
:
2933 case WINED3D_LOCATION_TEXTURE_RGB
:
2934 case WINED3D_LOCATION_RB_MULTISAMPLE
:
2935 case WINED3D_LOCATION_RB_RESOLVED
:
2936 return WINED3D_RESOURCE_ACCESS_GPU
;
2939 FIXME("Unhandled location %#x.\n", location
);
2944 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
2946 struct wined3d_device
*device
= surface
->container
->resource
.device
;
2947 struct wined3d_context
*context
;
2948 const struct wined3d_gl_info
*gl_info
;
2949 struct wined3d_bo_address dst
, src
;
2950 UINT size
= surface
->resource
.size
;
2952 surface_get_memory(surface
, &dst
, location
);
2953 surface_get_memory(surface
, &src
, surface_get_sub_resource(surface
)->locations
);
2955 if (dst
.buffer_object
)
2957 context
= context_acquire(device
, NULL
);
2958 gl_info
= context
->gl_info
;
2959 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, dst
.buffer_object
));
2960 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER
, 0, size
, src
.addr
));
2961 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
2962 checkGLcall("Upload PBO");
2963 context_release(context
);
2966 if (src
.buffer_object
)
2968 context
= context_acquire(device
, NULL
);
2969 gl_info
= context
->gl_info
;
2970 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, src
.buffer_object
));
2971 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER
, 0, size
, dst
.addr
));
2972 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
2973 checkGLcall("Download PBO");
2974 context_release(context
);
2977 memcpy(dst
.addr
, src
.addr
, size
);
2980 /* Context activation is done by the caller. */
2981 static void surface_load_sysmem(struct wined3d_surface
*surface
,
2982 struct wined3d_context
*context
, DWORD dst_location
)
2984 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
2985 struct wined3d_texture_sub_resource
*sub_resource
;
2987 wined3d_surface_prepare(surface
, context
, dst_location
);
2989 sub_resource
= surface_get_sub_resource(surface
);
2990 if (sub_resource
->locations
& surface_simple_locations
)
2992 surface_copy_simple_location(surface
, dst_location
);
2996 if (sub_resource
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
2997 surface_load_location(surface
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
2999 /* Download the surface to system memory. */
3000 if (sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
3002 struct wined3d_texture
*texture
= surface
->container
;
3004 wined3d_texture_bind_and_dirtify(texture
, context
,
3005 !(sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
3006 surface_download_data(surface
, gl_info
, dst_location
);
3007 ++texture
->download_count
;
3012 if (sub_resource
->locations
& WINED3D_LOCATION_DRAWABLE
)
3014 read_from_framebuffer(surface
, context
, dst_location
);
3018 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
3019 surface
, wined3d_debug_location(sub_resource
->locations
));
3022 /* Context activation is done by the caller. */
3023 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
3024 struct wined3d_context
*context
)
3026 struct wined3d_texture
*texture
= surface
->container
;
3029 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
3030 && wined3d_resource_is_offscreen(&texture
->resource
))
3032 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
3033 return WINED3DERR_INVALIDCALL
;
3036 surface_get_rect(surface
, NULL
, &r
);
3037 surface_load_location(surface
, context
, WINED3D_LOCATION_TEXTURE_RGB
);
3038 surface_blt_to_drawable(texture
->resource
.device
, context
,
3039 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
3044 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
3045 struct wined3d_context
*context
, BOOL srgb
)
3047 unsigned int width
, src_row_pitch
, src_slice_pitch
, dst_row_pitch
, dst_slice_pitch
;
3048 const RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
3049 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
3050 struct wined3d_texture
*texture
= surface
->container
;
3051 struct wined3d_device
*device
= texture
->resource
.device
;
3052 const struct wined3d_color_key_conversion
*conversion
;
3053 struct wined3d_texture_sub_resource
*sub_resource
;
3054 struct wined3d_bo_address data
;
3055 struct wined3d_format format
;
3056 POINT dst_point
= {0, 0};
3059 sub_resource
= surface_get_sub_resource(surface
);
3060 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
3061 && wined3d_resource_is_offscreen(&texture
->resource
)
3062 && (sub_resource
->locations
& WINED3D_LOCATION_DRAWABLE
))
3064 surface_load_fb_texture(surface
, srgb
, context
);
3069 if (sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
3070 && (texture
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
3071 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
3072 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
,
3073 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
))
3076 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
3077 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
3079 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
3080 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
3085 if (sub_resource
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
3086 && (!srgb
|| (texture
->resource
.format_flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
3087 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
3088 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
,
3089 NULL
, texture
->resource
.usage
, texture
->resource
.pool
, texture
->resource
.format
))
3091 DWORD src_location
= sub_resource
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
3092 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
3093 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
3094 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
3096 surface_blt_fbo(device
, context
, WINED3D_TEXF_POINT
, surface
, src_location
,
3097 &rect
, surface
, dst_location
, &rect
);
3102 /* Upload from system memory */
3106 if ((sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->resource
.map_binding
))
3107 == WINED3D_LOCATION_TEXTURE_RGB
)
3109 /* Performance warning... */
3110 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
3111 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
3116 if ((sub_resource
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->resource
.map_binding
))
3117 == WINED3D_LOCATION_TEXTURE_SRGB
)
3119 /* Performance warning... */
3120 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
3121 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
3125 if (!(sub_resource
->locations
& surface_simple_locations
))
3127 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
3128 /* Lets hope we get it from somewhere... */
3129 surface_load_location(surface
, context
, WINED3D_LOCATION_SYSMEM
);
3132 wined3d_texture_prepare_texture(texture
, context
, srgb
);
3133 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
3134 wined3d_texture_get_pitch(texture
, surface
->texture_level
, &src_row_pitch
, &src_slice_pitch
);
3136 width
= surface
->resource
.width
;
3138 format
= *texture
->resource
.format
;
3139 if ((conversion
= wined3d_format_get_color_key_conversion(texture
, TRUE
)))
3140 format
= *wined3d_get_format(gl_info
, conversion
->dst_format
);
3142 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
3143 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
3144 * getting called. */
3145 if ((format
.convert
|| conversion
)
3146 && texture
->sub_resources
[surface_get_sub_resource_idx(surface
)].buffer_object
)
3148 TRACE("Removing the pbo attached to surface %p.\n", surface
);
3150 if (surface
->flags
& SFLAG_DIBSECTION
)
3151 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
3153 surface
->resource
.map_binding
= WINED3D_LOCATION_SYSMEM
;
3155 surface_load_location(surface
, context
, surface
->resource
.map_binding
);
3156 wined3d_texture_remove_buffer_object(texture
, surface_get_sub_resource_idx(surface
), gl_info
);
3159 surface_get_memory(surface
, &data
, sub_resource
->locations
);
3162 /* This code is entered for texture formats which need a fixup. */
3163 UINT height
= surface
->resource
.height
;
3165 format
.byte_count
= format
.conv_byte_count
;
3166 wined3d_format_calculate_pitch(&format
, 1, width
, height
, &dst_row_pitch
, &dst_slice_pitch
);
3168 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
)))
3170 ERR("Out of memory (%u).\n", dst_slice_pitch
);
3171 context_release(context
);
3172 return E_OUTOFMEMORY
;
3174 format
.convert(data
.addr
, mem
, src_row_pitch
, src_slice_pitch
,
3175 dst_row_pitch
, dst_slice_pitch
, width
, height
, 1);
3176 src_row_pitch
= dst_row_pitch
;
3179 else if (conversion
)
3181 /* This code is only entered for color keying fixups */
3182 struct wined3d_palette
*palette
= NULL
;
3183 UINT height
= surface
->resource
.height
;
3185 wined3d_format_calculate_pitch(&format
, device
->surface_alignment
,
3186 width
, height
, &dst_row_pitch
, &dst_slice_pitch
);
3188 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch
)))
3190 ERR("Out of memory (%u).\n", dst_slice_pitch
);
3191 context_release(context
);
3192 return E_OUTOFMEMORY
;
3194 if (texture
->swapchain
&& texture
->swapchain
->palette
)
3195 palette
= texture
->swapchain
->palette
;
3196 conversion
->convert(data
.addr
, src_row_pitch
, mem
, dst_row_pitch
,
3197 width
, height
, palette
, &texture
->async
.gl_color_key
);
3198 src_row_pitch
= dst_row_pitch
;
3202 wined3d_surface_upload_data(surface
, gl_info
, &format
, &src_rect
,
3203 src_row_pitch
, &dst_point
, srgb
, wined3d_const_bo_address(&data
));
3205 HeapFree(GetProcessHeap(), 0, mem
);
3210 /* Context activation is done by the caller. */
3211 static void surface_load_renderbuffer(struct wined3d_surface
*surface
, struct wined3d_context
*context
,
3214 const RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
3215 DWORD locations
= surface_get_sub_resource(surface
)->locations
;
3218 if (locations
& WINED3D_LOCATION_RB_MULTISAMPLE
)
3219 src_location
= WINED3D_LOCATION_RB_MULTISAMPLE
;
3220 else if (locations
& WINED3D_LOCATION_RB_RESOLVED
)
3221 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
3222 else if (locations
& WINED3D_LOCATION_TEXTURE_SRGB
)
3223 src_location
= WINED3D_LOCATION_TEXTURE_SRGB
;
3224 else /* surface_blt_fbo will load the source location if necessary. */
3225 src_location
= WINED3D_LOCATION_TEXTURE_RGB
;
3227 surface_blt_fbo(surface
->container
->resource
.device
, context
, WINED3D_TEXF_POINT
,
3228 surface
, src_location
, &rect
, surface
, dst_location
, &rect
);
3231 /* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
3232 HRESULT
surface_load_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
3234 unsigned int sub_resource_idx
= surface_get_sub_resource_idx(surface
);
3235 struct wined3d_texture
*texture
= surface
->container
;
3236 struct wined3d_texture_sub_resource
*sub_resource
;
3239 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
3241 sub_resource
= &texture
->sub_resources
[sub_resource_idx
];
3242 if (sub_resource
->locations
& location
&& (!(texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
3243 || (surface
->ds_current_size
.cx
== surface
->resource
.width
3244 && surface
->ds_current_size
.cy
== surface
->resource
.height
)))
3246 TRACE("Location (%#x) is already up to date.\n", location
);
3252 DWORD required_access
= resource_access_from_location(location
);
3253 if ((texture
->resource
.access_flags
& required_access
) != required_access
)
3254 WARN("Operation requires %#x access, but surface only has %#x.\n",
3255 required_access
, texture
->resource
.access_flags
);
3258 if (sub_resource
->locations
& WINED3D_LOCATION_DISCARDED
)
3260 TRACE("Surface previously discarded, nothing to do.\n");
3261 wined3d_surface_prepare(surface
, context
, location
);
3262 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
3263 wined3d_texture_invalidate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_DISCARDED
);
3267 if (!sub_resource
->locations
)
3269 ERR("Surface %p does not have any up to date location.\n", surface
);
3270 wined3d_texture_validate_location(texture
, sub_resource_idx
, WINED3D_LOCATION_DISCARDED
);
3271 return surface_load_location(surface
, context
, location
);
3274 if (texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
3276 if ((location
== WINED3D_LOCATION_TEXTURE_RGB
&& sub_resource
->locations
& WINED3D_LOCATION_DRAWABLE
)
3277 || (location
== WINED3D_LOCATION_DRAWABLE
&& sub_resource
->locations
& WINED3D_LOCATION_TEXTURE_RGB
))
3279 surface_load_ds_location(surface
, context
, location
);
3283 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
3284 wined3d_debug_location(sub_resource
->locations
), wined3d_debug_location(location
));
3285 return WINED3DERR_INVALIDCALL
;
3290 case WINED3D_LOCATION_DIB
:
3291 case WINED3D_LOCATION_USER_MEMORY
:
3292 case WINED3D_LOCATION_SYSMEM
:
3293 case WINED3D_LOCATION_BUFFER
:
3294 surface_load_sysmem(surface
, context
, location
);
3297 case WINED3D_LOCATION_DRAWABLE
:
3298 if (FAILED(hr
= surface_load_drawable(surface
, context
)))
3302 case WINED3D_LOCATION_RB_RESOLVED
:
3303 case WINED3D_LOCATION_RB_MULTISAMPLE
:
3304 surface_load_renderbuffer(surface
, context
, location
);
3307 case WINED3D_LOCATION_TEXTURE_RGB
:
3308 case WINED3D_LOCATION_TEXTURE_SRGB
:
3309 if (FAILED(hr
= surface_load_texture(surface
, context
,
3310 location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
3315 ERR("Don't know how to handle location %#x.\n", location
);
3320 wined3d_texture_validate_location(texture
, sub_resource_idx
, location
);
3322 if (texture
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
3324 surface
->ds_current_size
.cx
= surface
->resource
.width
;
3325 surface
->ds_current_size
.cy
= surface
->resource
.height
;
3328 if (location
!= WINED3D_LOCATION_SYSMEM
&& (sub_resource
->locations
& WINED3D_LOCATION_SYSMEM
))
3329 surface_evict_sysmem(surface
);
3334 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
3335 /* Context activation is done by the caller. */
3336 static void ffp_blit_free(struct wined3d_device
*device
) { }
3338 /* Context activation is done by the caller. */
3339 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
,
3340 const struct wined3d_color_key
*color_key
)
3342 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
3344 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
3345 checkGLcall("glEnable(target)");
3350 /* Context activation is done by the caller. */
3351 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
3353 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
3354 checkGLcall("glDisable(GL_TEXTURE_2D)");
3355 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
3357 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
3358 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
3360 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
3362 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
3363 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
3367 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
,
3368 const struct wined3d_d3d_info
*d3d_info
, enum wined3d_blit_op blit_op
,
3369 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
3370 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
3372 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
3374 TRACE("Source or destination is in system memory.\n");
3380 case WINED3D_BLIT_OP_COLOR_BLIT_CKEY
:
3381 if (d3d_info
->shader_color_key
)
3383 TRACE("Color keying requires converted textures.\n");
3386 case WINED3D_BLIT_OP_COLOR_BLIT
:
3387 case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
:
3390 TRACE("Checking support for fixup:\n");
3391 dump_color_fixup_desc(src_format
->color_fixup
);
3394 /* We only support identity conversions. */
3395 if (!is_identity_fixup(src_format
->color_fixup
)
3396 || !is_identity_fixup(dst_format
->color_fixup
))
3398 TRACE("Fixups are not supported.\n");
3402 if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
3404 TRACE("Can only blit to render targets.\n");
3409 case WINED3D_BLIT_OP_COLOR_FILL
:
3410 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
3412 if (!((dst_format
->flags
[WINED3D_GL_RES_TYPE_TEX_2D
] & WINED3DFMT_FLAG_FBO_ATTACHABLE
)
3413 || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
3416 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
3418 TRACE("Color fill not supported\n");
3422 /* FIXME: We should reject color fills on formats with fixups,
3423 * but this would break P8 color fills for example. */
3427 case WINED3D_BLIT_OP_DEPTH_FILL
:
3431 TRACE("Unsupported blit_op=%d\n", blit_op
);
3436 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_rendertarget_view
*view
,
3437 const RECT
*rect
, const struct wined3d_color
*color
)
3439 const RECT draw_rect
= {0, 0, view
->width
, view
->height
};
3440 struct wined3d_fb_state fb
= {&view
, NULL
};
3442 device_clear_render_targets(device
, 1, &fb
, 1, rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
3447 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
3448 struct wined3d_rendertarget_view
*view
, const RECT
*rect
, DWORD clear_flags
,
3449 float depth
, DWORD stencil
)
3451 const RECT draw_rect
= {0, 0, view
->width
, view
->height
};
3452 struct wined3d_fb_state fb
= {NULL
, view
};
3454 device_clear_render_targets(device
, 0, &fb
, 1, rect
, &draw_rect
, clear_flags
, NULL
, depth
, stencil
);
3459 static void ffp_blit_blit_surface(struct wined3d_device
*device
, enum wined3d_blit_op op
, DWORD filter
,
3460 struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
3461 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3462 const struct wined3d_color_key
*color_key
)
3464 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
3465 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
3466 struct wined3d_texture
*src_texture
= src_surface
->container
;
3467 struct wined3d_context
*context
;
3469 /* Blit from offscreen surface to render target */
3470 struct wined3d_color_key old_blt_key
= src_texture
->async
.src_blt_color_key
;
3471 DWORD old_color_key_flags
= src_texture
->async
.color_key_flags
;
3473 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
3475 wined3d_texture_set_color_key(src_texture
, WINED3D_CKEY_SRC_BLT
, color_key
);
3477 context
= context_acquire(device
, dst_surface
);
3479 if (op
== WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
)
3480 glEnable(GL_ALPHA_TEST
);
3482 surface_blt_to_drawable(device
, context
, filter
,
3483 !!color_key
, src_surface
, src_rect
, dst_surface
, dst_rect
);
3485 if (op
== WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
)
3486 glDisable(GL_ALPHA_TEST
);
3488 context_release(context
);
3490 /* Restore the color key parameters */
3491 wined3d_texture_set_color_key(src_texture
, WINED3D_CKEY_SRC_BLT
,
3492 (old_color_key_flags
& WINED3D_CKEY_SRC_BLT
) ? &old_blt_key
: NULL
);
3494 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
, dst_texture
->resource
.draw_binding
);
3495 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
, ~dst_texture
->resource
.draw_binding
);
3498 const struct blit_shader ffp_blit
= {
3504 ffp_blit_color_fill
,
3505 ffp_blit_depth_fill
,
3506 ffp_blit_blit_surface
,
3509 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
3514 /* Context activation is done by the caller. */
3515 static void cpu_blit_free(struct wined3d_device
*device
)
3519 /* Context activation is done by the caller. */
3520 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
,
3521 const struct wined3d_color_key
*color_key
)
3526 /* Context activation is done by the caller. */
3527 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
3531 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
,
3532 const struct wined3d_d3d_info
*d3d_info
, enum wined3d_blit_op blit_op
,
3533 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
3534 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
3536 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
3544 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
3545 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
3546 const struct wined3d_format
*format
, DWORD flags
, const struct wined3d_blt_fx
*fx
)
3548 UINT row_block_count
;
3549 const BYTE
*src_row
;
3556 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
3560 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3562 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
3563 src_row
+= src_pitch
;
3564 dst_row
+= dst_pitch
;
3570 if (flags
== WINED3D_BLT_FX
&& fx
->fx
== WINEDDBLTFX_MIRRORUPDOWN
)
3572 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
3576 case WINED3DFMT_DXT1
:
3577 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3582 BYTE control_row
[4];
3585 const struct block
*s
= (const struct block
*)src_row
;
3586 struct block
*d
= (struct block
*)dst_row
;
3588 for (x
= 0; x
< row_block_count
; ++x
)
3590 d
[x
].color
[0] = s
[x
].color
[0];
3591 d
[x
].color
[1] = s
[x
].color
[1];
3592 d
[x
].control_row
[0] = s
[x
].control_row
[3];
3593 d
[x
].control_row
[1] = s
[x
].control_row
[2];
3594 d
[x
].control_row
[2] = s
[x
].control_row
[1];
3595 d
[x
].control_row
[3] = s
[x
].control_row
[0];
3597 src_row
-= src_pitch
;
3598 dst_row
+= dst_pitch
;
3602 case WINED3DFMT_DXT2
:
3603 case WINED3DFMT_DXT3
:
3604 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
3610 BYTE control_row
[4];
3613 const struct block
*s
= (const struct block
*)src_row
;
3614 struct block
*d
= (struct block
*)dst_row
;
3616 for (x
= 0; x
< row_block_count
; ++x
)
3618 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
3619 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
3620 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
3621 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
3622 d
[x
].color
[0] = s
[x
].color
[0];
3623 d
[x
].color
[1] = s
[x
].color
[1];
3624 d
[x
].control_row
[0] = s
[x
].control_row
[3];
3625 d
[x
].control_row
[1] = s
[x
].control_row
[2];
3626 d
[x
].control_row
[2] = s
[x
].control_row
[1];
3627 d
[x
].control_row
[3] = s
[x
].control_row
[0];
3629 src_row
-= src_pitch
;
3630 dst_row
+= dst_pitch
;
3635 FIXME("Compressed flip not implemented for format %s.\n",
3636 debug_d3dformat(format
->id
));
3641 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
3642 debug_d3dformat(format
->id
), flags
, flags
& WINED3D_BLT_FX
? fx
->fx
: 0);
3647 static HRESULT
surface_cpu_blt(struct wined3d_texture
*dst_texture
, unsigned int dst_sub_resource_idx
,
3648 const struct wined3d_box
*dst_box
, struct wined3d_texture
*src_texture
, unsigned int src_sub_resource_idx
,
3649 const struct wined3d_box
*src_box
, DWORD flags
, const struct wined3d_blt_fx
*fx
,
3650 enum wined3d_texture_filter_type filter
)
3652 unsigned int bpp
, src_height
, src_width
, dst_height
, dst_width
, row_byte_count
;
3653 const struct wined3d_format
*src_format
, *dst_format
;
3654 struct wined3d_texture
*converted_texture
= NULL
;
3655 unsigned int src_fmt_flags
, dst_fmt_flags
;
3656 struct wined3d_map_desc dst_map
, src_map
;
3657 const BYTE
*sbase
= NULL
;
3658 HRESULT hr
= WINED3D_OK
;
3659 BOOL same_sub_resource
;
3664 TRACE("dst_texture %p, dst_sub_resource_idx %u, dst_box %s, src_texture %p, "
3665 "src_sub_resource_idx %u, src_box %s, flags %#x, fx %p, filter %s.\n",
3666 dst_texture
, dst_sub_resource_idx
, debug_box(dst_box
), src_texture
,
3667 src_sub_resource_idx
, debug_box(src_box
), flags
, fx
, debug_d3dtexturefiltertype(filter
));
3669 if (src_texture
== dst_texture
&& src_sub_resource_idx
== dst_sub_resource_idx
)
3671 same_sub_resource
= TRUE
;
3672 wined3d_resource_map(&dst_texture
->resource
, dst_sub_resource_idx
, &dst_map
, NULL
, 0);
3674 src_format
= dst_texture
->resource
.format
;
3675 dst_format
= src_format
;
3676 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
3677 src_fmt_flags
= dst_fmt_flags
;
3681 same_sub_resource
= FALSE
;
3682 dst_format
= dst_texture
->resource
.format
;
3683 dst_fmt_flags
= dst_texture
->resource
.format_flags
;
3686 if (dst_texture
->resource
.format
->id
!= src_texture
->resource
.format
->id
)
3688 if (!(converted_texture
= surface_convert_format(src_texture
, src_sub_resource_idx
, dst_format
->id
)))
3690 /* The conv function writes a FIXME */
3691 WARN("Cannot convert source surface format to dest format.\n");
3694 src_texture
= converted_texture
;
3695 src_sub_resource_idx
= 0;
3697 wined3d_resource_map(&src_texture
->resource
, src_sub_resource_idx
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
3698 src_format
= src_texture
->resource
.format
;
3699 src_fmt_flags
= src_texture
->resource
.format_flags
;
3703 src_format
= dst_format
;
3704 src_fmt_flags
= dst_fmt_flags
;
3707 wined3d_resource_map(&dst_texture
->resource
, dst_sub_resource_idx
, &dst_map
, dst_box
, 0);
3710 bpp
= dst_format
->byte_count
;
3711 src_height
= src_box
->bottom
- src_box
->top
;
3712 src_width
= src_box
->right
- src_box
->left
;
3713 dst_height
= dst_box
->bottom
- dst_box
->top
;
3714 dst_width
= dst_box
->right
- dst_box
->left
;
3715 row_byte_count
= dst_width
* bpp
;
3718 sbase
= (BYTE
*)src_map
.data
3719 + ((src_box
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
3720 + ((src_box
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
3721 if (same_sub_resource
)
3722 dbuf
= (BYTE
*)dst_map
.data
3723 + ((dst_box
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
3724 + ((dst_box
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
3726 dbuf
= dst_map
.data
;
3728 if (src_fmt_flags
& dst_fmt_flags
& WINED3DFMT_FLAG_BLOCKS
)
3730 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
3732 if (same_sub_resource
)
3734 FIXME("Only plain blits supported on compressed surfaces.\n");
3739 if (src_height
!= dst_height
|| src_width
!= dst_width
)
3741 WARN("Stretching not supported on compressed surfaces.\n");
3742 hr
= WINED3DERR_INVALIDCALL
;
3746 if (!wined3d_texture_check_block_align(src_texture
,
3747 src_sub_resource_idx
% src_texture
->level_count
, src_box
))
3749 WARN("Source rectangle not block-aligned.\n");
3750 hr
= WINED3DERR_INVALIDCALL
;
3754 if (!wined3d_texture_check_block_align(dst_texture
,
3755 dst_sub_resource_idx
% dst_texture
->level_count
, dst_box
))
3757 WARN("Destination rectangle not block-aligned.\n");
3758 hr
= WINED3DERR_INVALIDCALL
;
3762 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
3763 src_map
.row_pitch
, dst_map
.row_pitch
, dst_width
, dst_height
,
3764 src_format
, flags
, fx
);
3768 /* First, all the 'source-less' blits */
3769 if (flags
& WINED3D_BLT_COLOR_FILL
)
3771 hr
= _Blt_ColorFill(dbuf
, dst_width
, dst_height
, bpp
, dst_map
.row_pitch
, fx
->fill_color
);
3772 flags
&= ~WINED3D_BLT_COLOR_FILL
;
3775 if (flags
& WINED3D_BLT_DEPTH_FILL
)
3776 FIXME("WINED3D_BLT_DEPTH_FILL needs to be implemented!\n");
3778 /* Now the 'with source' blits. */
3781 int sx
, xinc
, sy
, yinc
;
3783 if (!dst_width
|| !dst_height
) /* Hmm... stupid program? */
3786 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
3787 && (src_width
!= dst_width
|| src_height
!= dst_height
))
3789 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
3790 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
3793 xinc
= (src_width
<< 16) / dst_width
;
3794 yinc
= (src_height
<< 16) / dst_height
;
3798 /* No effects, we can cheat here. */
3799 if (dst_width
== src_width
)
3801 if (dst_height
== src_height
)
3803 /* No stretching in either direction. This needs to be as
3804 * fast as possible. */
3807 /* Check for overlapping surfaces. */
3808 if (!same_sub_resource
|| dst_box
->top
< src_box
->top
3809 || dst_box
->right
<= src_box
->left
|| src_box
->right
<= dst_box
->left
)
3811 /* No overlap, or dst above src, so copy from top downwards. */
3812 for (y
= 0; y
< dst_height
; ++y
)
3814 memcpy(dbuf
, sbuf
, row_byte_count
);
3815 sbuf
+= src_map
.row_pitch
;
3816 dbuf
+= dst_map
.row_pitch
;
3819 else if (dst_box
->top
> src_box
->top
)
3821 /* Copy from bottom upwards. */
3822 sbuf
+= src_map
.row_pitch
* dst_height
;
3823 dbuf
+= dst_map
.row_pitch
* dst_height
;
3824 for (y
= 0; y
< dst_height
; ++y
)
3826 sbuf
-= src_map
.row_pitch
;
3827 dbuf
-= dst_map
.row_pitch
;
3828 memcpy(dbuf
, sbuf
, row_byte_count
);
3833 /* Src and dst overlapping on the same line, use memmove. */
3834 for (y
= 0; y
< dst_height
; ++y
)
3836 memmove(dbuf
, sbuf
, row_byte_count
);
3837 sbuf
+= src_map
.row_pitch
;
3838 dbuf
+= dst_map
.row_pitch
;
3844 /* Stretching in y direction only. */
3845 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
3847 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
3848 memcpy(dbuf
, sbuf
, row_byte_count
);
3849 dbuf
+= dst_map
.row_pitch
;
3855 /* Stretching in X direction. */
3857 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
3859 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
3861 if ((sy
>> 16) == (last_sy
>> 16))
3863 /* This source row is the same as last source row -
3864 * Copy the already stretched row. */
3865 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, row_byte_count
);
3869 #define STRETCH_ROW(type) \
3871 const type *s = (const type *)sbuf; \
3872 type *d = (type *)dbuf; \
3873 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
3874 d[x] = s[sx >> 16]; \
3892 for (x
= sx
= 0; x
< dst_width
; x
++, sx
+= xinc
)
3896 s
= sbuf
+ 3 * (sx
>> 16);
3897 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
3898 d
[0] = (pixel
) & 0xff;
3899 d
[1] = (pixel
>> 8) & 0xff;
3900 d
[2] = (pixel
>> 16) & 0xff;
3906 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
3907 hr
= WINED3DERR_NOTAVAILABLE
;
3912 dbuf
+= dst_map
.row_pitch
;
3919 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
3920 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
3921 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
3922 if (flags
& (WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
3923 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
))
3925 /* The color keying flags are checked for correctness in ddraw */
3926 if (flags
& WINED3D_BLT_SRC_CKEY
)
3928 keylow
= src_texture
->async
.src_blt_color_key
.color_space_low_value
;
3929 keyhigh
= src_texture
->async
.src_blt_color_key
.color_space_high_value
;
3931 else if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
3933 keylow
= fx
->src_color_key
.color_space_low_value
;
3934 keyhigh
= fx
->src_color_key
.color_space_high_value
;
3937 if (flags
& WINED3D_BLT_DST_CKEY
)
3939 /* Destination color keys are taken from the source surface! */
3940 destkeylow
= src_texture
->async
.dst_blt_color_key
.color_space_low_value
;
3941 destkeyhigh
= src_texture
->async
.dst_blt_color_key
.color_space_high_value
;
3943 else if (flags
& WINED3D_BLT_DST_CKEY_OVERRIDE
)
3945 destkeylow
= fx
->dst_color_key
.color_space_low_value
;
3946 destkeyhigh
= fx
->dst_color_key
.color_space_high_value
;
3956 get_color_masks(src_format
, masks
);
3961 flags
&= ~(WINED3D_BLT_SRC_CKEY
| WINED3D_BLT_DST_CKEY
3962 | WINED3D_BLT_SRC_CKEY_OVERRIDE
| WINED3D_BLT_DST_CKEY_OVERRIDE
);
3965 if (flags
& WINED3D_BLT_FX
)
3967 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
3970 dTopRight
= dbuf
+ ((dst_width
- 1) * bpp
);
3971 dBottomLeft
= dTopLeft
+ ((dst_height
- 1) * dst_map
.row_pitch
);
3972 dBottomRight
= dBottomLeft
+ ((dst_width
- 1) * bpp
);
3974 if (fx
->fx
& WINEDDBLTFX_ARITHSTRETCHY
)
3976 /* I don't think we need to do anything about this flag */
3977 WARN("Nothing done for WINEDDBLTFX_ARITHSTRETCHY.\n");
3979 if (fx
->fx
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
3982 dTopRight
= dTopLeft
;
3985 dBottomRight
= dBottomLeft
;
3987 dstxinc
= dstxinc
* -1;
3989 if (fx
->fx
& WINEDDBLTFX_MIRRORUPDOWN
)
3992 dTopLeft
= dBottomLeft
;
3995 dTopRight
= dBottomRight
;
3997 dstyinc
= dstyinc
* -1;
3999 if (fx
->fx
& WINEDDBLTFX_NOTEARING
)
4001 /* I don't think we need to do anything about this flag */
4002 WARN("Nothing done for WINEDDBLTFX_NOTEARING.\n");
4004 if (fx
->fx
& WINEDDBLTFX_ROTATE180
)
4007 dBottomRight
= dTopLeft
;
4010 dBottomLeft
= dTopRight
;
4012 dstxinc
= dstxinc
* -1;
4013 dstyinc
= dstyinc
* -1;
4015 if (fx
->fx
& WINEDDBLTFX_ROTATE270
)
4018 dTopLeft
= dBottomLeft
;
4019 dBottomLeft
= dBottomRight
;
4020 dBottomRight
= dTopRight
;
4025 dstxinc
= dstxinc
* -1;
4027 if (fx
->fx
& WINEDDBLTFX_ROTATE90
)
4030 dTopLeft
= dTopRight
;
4031 dTopRight
= dBottomRight
;
4032 dBottomRight
= dBottomLeft
;
4037 dstyinc
= dstyinc
* -1;
4039 if (fx
->fx
& WINEDDBLTFX_ZBUFFERBASEDEST
)
4041 /* I don't think we need to do anything about this flag */
4042 WARN("Nothing done for WINEDDBLTFX_ZBUFFERBASEDEST.\n");
4045 flags
&= ~(WINED3D_BLT_FX
);
4048 #define COPY_COLORKEY_FX(type) \
4051 type *d = (type *)dbuf, *dx, tmp; \
4052 for (y = sy = 0; y < dst_height; ++y, sy += yinc) \
4054 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
4056 for (x = sx = 0; x < dst_width; ++x, sx += xinc) \
4058 tmp = s[sx >> 16]; \
4059 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
4060 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
4064 dx = (type *)(((BYTE *)dx) + dstxinc); \
4066 d = (type *)(((BYTE *)d) + dstyinc); \
4073 COPY_COLORKEY_FX(BYTE
);
4076 COPY_COLORKEY_FX(WORD
);
4079 COPY_COLORKEY_FX(DWORD
);
4084 BYTE
*d
= dbuf
, *dx
;
4085 for (y
= sy
= 0; y
< dst_height
; ++y
, sy
+= yinc
)
4087 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
4089 for (x
= sx
= 0; x
< dst_width
; ++x
, sx
+= xinc
)
4091 DWORD pixel
, dpixel
= 0;
4092 s
= sbuf
+ 3 * (sx
>>16);
4093 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
4094 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
4095 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
4096 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
4098 dx
[0] = (pixel
) & 0xff;
4099 dx
[1] = (pixel
>> 8) & 0xff;
4100 dx
[2] = (pixel
>> 16) & 0xff;
4109 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
4110 (flags
& WINED3D_BLT_SRC_CKEY
) ? "Source" : "Destination", bpp
* 8);
4111 hr
= WINED3DERR_NOTAVAILABLE
;
4113 #undef COPY_COLORKEY_FX
4120 FIXME(" Unsupported flags %#x.\n", flags
);
4123 wined3d_resource_unmap(&dst_texture
->resource
, dst_sub_resource_idx
);
4124 if (src_texture
&& !same_sub_resource
)
4125 wined3d_resource_unmap(&src_texture
->resource
, src_sub_resource_idx
);
4126 if (converted_texture
)
4127 wined3d_texture_decref(converted_texture
);
4132 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_rendertarget_view
*view
,
4133 const RECT
*rect
, const struct wined3d_color
*color
)
4135 const struct wined3d_box box
= {rect
->left
, rect
->top
, rect
->right
, rect
->bottom
, 0, 1};
4136 static const struct wined3d_box src_box
;
4137 struct wined3d_blt_fx fx
;
4139 fx
.fill_color
= wined3d_format_convert_from_float(view
->format
, color
);
4140 return surface_cpu_blt(wined3d_texture_from_resource(view
->resource
), view
->sub_resource_idx
,
4141 &box
, NULL
, 0, &src_box
, WINED3D_BLT_COLOR_FILL
, &fx
, WINED3D_TEXF_POINT
);
4144 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
4145 struct wined3d_rendertarget_view
*view
, const RECT
*rect
, DWORD clear_flags
,
4146 float depth
, DWORD stencil
)
4148 FIXME("Depth/stencil filling not implemented by cpu_blit.\n");
4149 return WINED3DERR_INVALIDCALL
;
4152 static void cpu_blit_blit_surface(struct wined3d_device
*device
, enum wined3d_blit_op op
, DWORD filter
,
4153 struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
4154 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4155 const struct wined3d_color_key
*color_key
)
4157 /* FIXME: Remove error returns from surface_blt_cpu. */
4158 ERR("Blit method not implemented by cpu_blit.\n");
4161 const struct blit_shader cpu_blit
= {
4167 cpu_blit_color_fill
,
4168 cpu_blit_depth_fill
,
4169 cpu_blit_blit_surface
,
4172 HRESULT
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4173 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
4174 const struct wined3d_blt_fx
*fx
, enum wined3d_texture_filter_type filter
)
4176 struct wined3d_box dst_box
= {dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, 0, 1};
4177 struct wined3d_box src_box
= {src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
, 0, 1};
4178 unsigned int dst_sub_resource_idx
= surface_get_sub_resource_idx(dst_surface
);
4179 struct wined3d_texture
*dst_texture
= dst_surface
->container
;
4180 struct wined3d_device
*device
= dst_texture
->resource
.device
;
4181 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
4182 struct wined3d_texture
*src_texture
= NULL
;
4183 DWORD src_ds_flags
, dst_ds_flags
;
4184 BOOL scale
, convert
;
4186 static const DWORD simple_blit
= WINED3D_BLT_ASYNC
4187 | WINED3D_BLT_COLOR_FILL
4188 | WINED3D_BLT_SRC_CKEY
4189 | WINED3D_BLT_SRC_CKEY_OVERRIDE
4191 | WINED3D_BLT_DEPTH_FILL
4192 | WINED3D_BLT_DO_NOT_WAIT
4193 | WINED3D_BLT_ALPHA_TEST
;
4195 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4196 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
4197 flags
, fx
, debug_d3dtexturefiltertype(filter
));
4198 TRACE("Usage is %s.\n", debug_d3dusage(dst_texture
->resource
.usage
));
4202 TRACE("fx %#x.\n", fx
->fx
);
4203 TRACE("fill_color 0x%08x.\n", fx
->fill_color
);
4204 TRACE("dst_color_key {0x%08x, 0x%08x}.\n",
4205 fx
->dst_color_key
.color_space_low_value
,
4206 fx
->dst_color_key
.color_space_high_value
);
4207 TRACE("src_color_key {0x%08x, 0x%08x}.\n",
4208 fx
->src_color_key
.color_space_low_value
,
4209 fx
->src_color_key
.color_space_high_value
);
4212 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
4214 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
4215 return WINEDDERR_SURFACEBUSY
;
4218 if (dst_rect
->left
>= dst_rect
->right
|| dst_rect
->top
>= dst_rect
->bottom
4219 || dst_rect
->left
> dst_surface
->resource
.width
|| dst_rect
->left
< 0
4220 || dst_rect
->top
> dst_surface
->resource
.height
|| dst_rect
->top
< 0
4221 || dst_rect
->right
> dst_surface
->resource
.width
|| dst_rect
->right
< 0
4222 || dst_rect
->bottom
> dst_surface
->resource
.height
|| dst_rect
->bottom
< 0)
4224 WARN("The application gave us a bad destination rectangle.\n");
4225 return WINEDDERR_INVALIDRECT
;
4230 if (src_rect
->left
>= src_rect
->right
|| src_rect
->top
>= src_rect
->bottom
4231 || src_rect
->left
> src_surface
->resource
.width
|| src_rect
->left
< 0
4232 || src_rect
->top
> src_surface
->resource
.height
|| src_rect
->top
< 0
4233 || src_rect
->right
> src_surface
->resource
.width
|| src_rect
->right
< 0
4234 || src_rect
->bottom
> src_surface
->resource
.height
|| src_rect
->bottom
< 0)
4236 WARN("The application gave us a bad source rectangle.\n");
4237 return WINEDDERR_INVALIDRECT
;
4239 src_texture
= src_surface
->container
;
4242 if (!fx
|| !(fx
->fx
))
4243 flags
&= ~WINED3D_BLT_FX
;
4245 if (flags
& WINED3D_BLT_WAIT
)
4246 flags
&= ~WINED3D_BLT_WAIT
;
4248 if (flags
& WINED3D_BLT_ASYNC
)
4250 static unsigned int once
;
4253 FIXME("Can't handle WINED3D_BLT_ASYNC flag.\n");
4254 flags
&= ~WINED3D_BLT_ASYNC
;
4257 /* WINED3D_BLT_DO_NOT_WAIT appeared in DX7. */
4258 if (flags
& WINED3D_BLT_DO_NOT_WAIT
)
4260 static unsigned int once
;
4263 FIXME("Can't handle WINED3D_BLT_DO_NOT_WAIT flag.\n");
4264 flags
&= ~WINED3D_BLT_DO_NOT_WAIT
;
4267 if (!device
->d3d_initialized
)
4269 WARN("D3D not initialized, using fallback.\n");
4273 /* We want to avoid invalidating the sysmem location for converted
4274 * surfaces, since otherwise we'd have to convert the data back when
4276 if (dst_texture
->flags
& WINED3D_TEXTURE_CONVERTED
|| dst_texture
->resource
.format
->convert
4277 || wined3d_format_get_color_key_conversion(dst_texture
, TRUE
))
4279 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
4283 if (flags
& ~simple_blit
)
4285 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
4290 src_swapchain
= src_texture
->swapchain
;
4292 src_swapchain
= NULL
;
4294 dst_swapchain
= dst_texture
->swapchain
;
4296 /* This isn't strictly needed. FBO blits for example could deal with
4297 * cross-swapchain blits by first downloading the source to a texture
4298 * before switching to the destination context. We just have this here to
4299 * not have to deal with the issue, since cross-swapchain blits should be
4301 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
4303 FIXME("Using fallback for cross-swapchain blit.\n");
4308 && (src_rect
->right
- src_rect
->left
!= dst_rect
->right
- dst_rect
->left
4309 || src_rect
->bottom
- src_rect
->top
!= dst_rect
->bottom
- dst_rect
->top
);
4310 convert
= src_surface
&& src_texture
->resource
.format
->id
!= dst_texture
->resource
.format
->id
;
4312 dst_ds_flags
= dst_texture
->resource
.format_flags
4313 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
4315 src_ds_flags
= src_texture
->resource
.format_flags
4316 & (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
4320 if (src_ds_flags
|| dst_ds_flags
)
4322 if (flags
& WINED3D_BLT_DEPTH_FILL
)
4326 TRACE("Depth fill.\n");
4328 if (!surface_convert_depth_to_float(dst_surface
, fx
->fill_color
, &depth
))
4329 return WINED3DERR_INVALIDCALL
;
4331 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, dst_rect
, depth
)))
4336 if (src_ds_flags
!= dst_ds_flags
)
4338 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
4339 return WINED3DERR_INVALIDCALL
;
4342 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_texture
->resource
.draw_binding
,
4343 src_rect
, dst_surface
, dst_texture
->resource
.draw_binding
, dst_rect
)))
4349 struct wined3d_texture_sub_resource
*src_sub_resource
, *dst_sub_resource
;
4350 const struct blit_shader
*blitter
;
4352 dst_sub_resource
= surface_get_sub_resource(dst_surface
);
4353 src_sub_resource
= src_surface
? surface_get_sub_resource(src_surface
) : NULL
;
4355 /* In principle this would apply to depth blits as well, but we don't
4356 * implement those in the CPU blitter at the moment. */
4357 if ((dst_sub_resource
->locations
& dst_surface
->resource
.map_binding
)
4358 && (!src_surface
|| (src_sub_resource
->locations
& src_surface
->resource
.map_binding
)))
4361 TRACE("Not doing sysmem blit because of scaling.\n");
4363 TRACE("Not doing sysmem blit because of format conversion.\n");
4368 if (flags
& WINED3D_BLT_COLOR_FILL
)
4370 struct wined3d_color color
;
4371 const struct wined3d_palette
*palette
= dst_swapchain
? dst_swapchain
->palette
: NULL
;
4373 TRACE("Color fill.\n");
4375 if (!wined3d_format_convert_color_to_float(dst_texture
->resource
.format
,
4376 palette
, fx
->fill_color
, &color
))
4379 if (SUCCEEDED(surface_color_fill(dst_surface
, dst_rect
, &color
)))
4384 enum wined3d_blit_op blit_op
= WINED3D_BLIT_OP_COLOR_BLIT
;
4385 const struct wined3d_color_key
*color_key
= NULL
;
4387 TRACE("Color blit.\n");
4388 if (flags
& WINED3D_BLT_SRC_CKEY_OVERRIDE
)
4390 color_key
= &fx
->src_color_key
;
4391 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
4393 else if (flags
& WINED3D_BLT_SRC_CKEY
)
4395 color_key
= &src_texture
->async
.src_blt_color_key
;
4396 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_CKEY
;
4398 else if (flags
& WINED3D_BLT_ALPHA_TEST
)
4400 blit_op
= WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST
;
4402 else if ((src_sub_resource
->locations
& WINED3D_LOCATION_SYSMEM
)
4403 && !(dst_sub_resource
->locations
& WINED3D_LOCATION_SYSMEM
))
4407 TRACE("Not doing upload because of scaling.\n");
4409 TRACE("Not doing upload because of format conversion.\n");
4412 POINT dst_point
= {dst_rect
->left
, dst_rect
->top
};
4414 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, src_rect
)))
4416 if (!wined3d_resource_is_offscreen(&dst_texture
->resource
))
4418 struct wined3d_context
*context
= context_acquire(device
, dst_surface
);
4419 surface_load_location(dst_surface
, context
, dst_texture
->resource
.draw_binding
);
4420 context_release(context
);
4426 else if (dst_swapchain
&& dst_swapchain
->back_buffers
4427 && dst_texture
== dst_swapchain
->front_buffer
4428 && src_texture
== dst_swapchain
->back_buffers
[0])
4430 /* Use present for back -> front blits. The idea behind this is
4431 * that present is potentially faster than a blit, in particular
4432 * when FBO blits aren't available. Some ddraw applications like
4433 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
4434 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
4435 * applications can't blit directly to the frontbuffer. */
4436 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
4438 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
4440 /* Set the swap effect to COPY, we don't want the backbuffer
4441 * to become undefined. */
4442 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
4443 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, 0);
4444 dst_swapchain
->desc
.swap_effect
= swap_effect
;
4449 if (fbo_blit_supported(&device
->adapter
->gl_info
, blit_op
,
4450 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
4451 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
))
4453 struct wined3d_context
*context
;
4454 TRACE("Using FBO blit.\n");
4456 context
= context_acquire(device
, NULL
);
4457 surface_blt_fbo(device
, context
, filter
,
4458 src_surface
, src_texture
->resource
.draw_binding
, src_rect
,
4459 dst_surface
, dst_texture
->resource
.draw_binding
, dst_rect
);
4460 context_release(context
);
4462 wined3d_texture_validate_location(dst_texture
, dst_sub_resource_idx
,
4463 dst_texture
->resource
.draw_binding
);
4464 wined3d_texture_invalidate_location(dst_texture
, dst_sub_resource_idx
,
4465 ~dst_texture
->resource
.draw_binding
);
4470 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, &device
->adapter
->d3d_info
, blit_op
,
4471 src_rect
, src_texture
->resource
.usage
, src_texture
->resource
.pool
, src_texture
->resource
.format
,
4472 dst_rect
, dst_texture
->resource
.usage
, dst_texture
->resource
.pool
, dst_texture
->resource
.format
);
4475 blitter
->blit_surface(device
, blit_op
, filter
, src_surface
,
4476 src_rect
, dst_surface
, dst_rect
, color_key
);
4483 /* Special cases for render targets. */
4484 if (SUCCEEDED(surface_blt_special(dst_surface
, dst_rect
, src_surface
, src_rect
, flags
, fx
, filter
)))
4488 return surface_cpu_blt(dst_texture
, surface_get_sub_resource_idx(dst_surface
), &dst_box
,
4489 src_texture
, src_texture
? surface_get_sub_resource_idx(src_surface
) : 0, &src_box
, flags
, fx
, filter
);
4492 HRESULT
wined3d_surface_init(struct wined3d_surface
*surface
, struct wined3d_texture
*container
,
4493 const struct wined3d_resource_desc
*desc
, GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
)
4495 unsigned int sub_resource_idx
= layer
* container
->level_count
+ level
;
4496 struct wined3d_device
*device
= container
->resource
.device
;
4497 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4498 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
);
4499 BOOL lockable
= flags
& WINED3D_TEXTURE_CREATE_MAPPABLE
;
4500 UINT multisample_quality
= desc
->multisample_quality
;
4501 unsigned int resource_size
;
4504 if (container
->flags
& WINED3D_TEXTURE_COND_NP2_EMULATED
)
4506 unsigned int pow2_width
= 1, pow2_height
= 1;
4508 /* Find the nearest pow2 match. */
4509 while (pow2_width
< desc
->width
)
4511 while (pow2_height
< desc
->height
)
4514 surface
->pow2Width
= pow2_width
;
4515 surface
->pow2Height
= pow2_height
;
4519 surface
->pow2Width
= desc
->width
;
4520 surface
->pow2Height
= desc
->height
;
4523 /* Quick lockable sanity check.
4524 * TODO: remove this after surfaces, usage and lockability have been debugged properly
4525 * this function is too deep to need to care about things like this.
4526 * Levels need to be checked too, since they all affect what can be done. */
4529 case WINED3D_POOL_MANAGED
:
4530 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
)
4531 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
4534 case WINED3D_POOL_DEFAULT
:
4535 if (lockable
&& !(desc
->usage
& (WINED3DUSAGE_DYNAMIC
4536 | WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
4537 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
4540 case WINED3D_POOL_SCRATCH
:
4541 case WINED3D_POOL_SYSTEM_MEM
:
4545 FIXME("Unknown pool %#x.\n", desc
->pool
);
4549 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
4550 FIXME("Trying to create a render target that isn't in the default pool.\n");
4552 /* FIXME: Check that the format is supported by the device. */
4554 resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, desc
->width
, desc
->height
, 1);
4556 return WINED3DERR_INVALIDCALL
;
4558 if (FAILED(hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
,
4559 format
, desc
->multisample_type
, multisample_quality
, desc
->usage
, desc
->pool
, desc
->width
, desc
->height
,
4560 1, resource_size
, NULL
, &wined3d_null_parent_ops
, &surface_resource_ops
)))
4562 WARN("Failed to initialize resource, returning %#x.\n", hr
);
4566 surface
->container
= container
;
4567 surface
->texture_target
= target
;
4568 surface
->texture_level
= level
;
4569 surface
->texture_layer
= layer
;
4571 list_init(&surface
->renderbuffers
);
4572 list_init(&surface
->overlays
);
4575 if (flags
& WINED3D_TEXTURE_CREATE_DISCARD
)
4576 surface
->flags
|= SFLAG_DISCARD
;
4577 if (lockable
|| desc
->format
== WINED3DFMT_D16_LOCKABLE
)
4578 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
4580 wined3d_texture_validate_location(container
, sub_resource_idx
, WINED3D_LOCATION_SYSMEM
);
4581 if (container
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
4582 container
->sub_resources
[sub_resource_idx
].locations
= WINED3D_LOCATION_DISCARDED
;
4584 if (wined3d_texture_use_pbo(container
, gl_info
))
4585 surface
->resource
.map_binding
= WINED3D_LOCATION_BUFFER
;
4587 /* Similar to lockable rendertargets above, creating the DIB section
4588 * during surface initialization prevents the sysmem pointer from changing
4589 * after a wined3d_texture_get_dc() call. */
4590 if ((desc
->usage
& WINED3DUSAGE_OWNDC
) || (device
->wined3d
->flags
& WINED3D_NO3D
))
4592 if (FAILED(hr
= surface_create_dib_section(surface
)))
4594 wined3d_surface_cleanup(surface
);
4597 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
4600 if (surface
->resource
.map_binding
== WINED3D_LOCATION_DIB
)
4602 wined3d_resource_free_sysmem(&surface
->resource
);
4603 wined3d_texture_validate_location(container
, sub_resource_idx
, WINED3D_LOCATION_DIB
);
4604 wined3d_texture_invalidate_location(container
, sub_resource_idx
, WINED3D_LOCATION_SYSMEM
);
4610 /* Context activation is done by the caller. Context may be NULL in
4611 * WINED3D_NO3D mode. */
4612 void wined3d_surface_prepare(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
4614 struct wined3d_texture
*texture
= surface
->container
;
4618 case WINED3D_LOCATION_SYSMEM
:
4619 surface_prepare_system_memory(surface
);
4622 case WINED3D_LOCATION_USER_MEMORY
:
4623 if (!texture
->user_memory
)
4624 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
4627 case WINED3D_LOCATION_DIB
:
4628 if (!surface
->dib
.bitmap_data
)
4629 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
4632 case WINED3D_LOCATION_BUFFER
:
4633 wined3d_texture_prepare_buffer_object(texture
,
4634 surface_get_sub_resource_idx(surface
), context
->gl_info
);
4637 case WINED3D_LOCATION_TEXTURE_RGB
:
4638 wined3d_texture_prepare_texture(texture
, context
, FALSE
);
4641 case WINED3D_LOCATION_TEXTURE_SRGB
:
4642 wined3d_texture_prepare_texture(texture
, context
, TRUE
);
4645 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4646 surface_prepare_rb(surface
, context
->gl_info
, TRUE
);
4649 case WINED3D_LOCATION_RB_RESOLVED
:
4650 surface_prepare_rb(surface
, context
->gl_info
, FALSE
);