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_surface
);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d
);
37 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
39 static const DWORD surface_simple_locations
=
40 WINED3D_LOCATION_SYSMEM
| WINED3D_LOCATION_USER_MEMORY
41 | WINED3D_LOCATION_DIB
| WINED3D_LOCATION_BUFFER
;
43 static void surface_cleanup(struct wined3d_surface
*surface
)
45 struct wined3d_surface
*overlay
, *cur
;
47 TRACE("surface %p.\n", surface
);
49 if (surface
->pbo
|| surface
->rb_multisample
50 || surface
->rb_resolved
|| !list_empty(&surface
->renderbuffers
))
52 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
53 const struct wined3d_gl_info
*gl_info
;
54 struct wined3d_context
*context
;
56 context
= context_acquire(surface
->resource
.device
, NULL
);
57 gl_info
= context
->gl_info
;
61 TRACE("Deleting PBO %u.\n", surface
->pbo
);
62 GL_EXTCALL(glDeleteBuffers(1, &surface
->pbo
));
65 if (surface
->rb_multisample
)
67 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
68 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
71 if (surface
->rb_resolved
)
73 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
74 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
77 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
79 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
80 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
81 HeapFree(GetProcessHeap(), 0, entry
);
84 context_release(context
);
87 if (surface
->flags
& SFLAG_DIBSECTION
)
89 DeleteDC(surface
->hDC
);
90 DeleteObject(surface
->dib
.DIBsection
);
91 surface
->dib
.bitmap_data
= NULL
;
94 if (surface
->overlay_dest
)
95 list_remove(&surface
->overlay_entry
);
97 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
99 list_remove(&overlay
->overlay_entry
);
100 overlay
->overlay_dest
= NULL
;
103 resource_cleanup(&surface
->resource
);
106 void wined3d_surface_destroy(struct wined3d_surface
*surface
)
108 TRACE("surface %p.\n", surface
);
110 surface_cleanup(surface
);
111 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
112 HeapFree(GetProcessHeap(), 0, surface
);
115 void surface_get_drawable_size(const struct wined3d_surface
*surface
, const struct wined3d_context
*context
,
116 unsigned int *width
, unsigned int *height
)
118 if (surface
->container
->swapchain
)
120 /* The drawable size of an onscreen drawable is the surface size.
121 * (Actually: The window size, but the surface is created in window
123 *width
= context
->current_rt
->resource
.width
;
124 *height
= context
->current_rt
->resource
.height
;
126 else if (wined3d_settings
.offscreen_rendering_mode
== ORM_BACKBUFFER
)
128 const struct wined3d_swapchain
*swapchain
= context
->swapchain
;
130 /* The drawable size of a backbuffer / aux buffer offscreen target is
131 * the size of the current context's drawable, which is the size of
132 * the back buffer of the swapchain the active context belongs to. */
133 *width
= swapchain
->desc
.backbuffer_width
;
134 *height
= swapchain
->desc
.backbuffer_height
;
138 /* The drawable size of an FBO target is the OpenGL texture size,
139 * which is the power of two size. */
140 *width
= context
->current_rt
->pow2Width
;
141 *height
= context
->current_rt
->pow2Height
;
149 enum tex_types tex_type
;
150 GLfloat coords
[4][3];
161 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
163 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
164 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
165 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
166 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
169 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
171 GLfloat (*coords
)[3] = info
->coords
;
177 FIXME("Unsupported texture target %#x\n", target
);
178 /* Fall back to GL_TEXTURE_2D */
180 info
->binding
= GL_TEXTURE_BINDING_2D
;
181 info
->bind_target
= GL_TEXTURE_2D
;
182 info
->tex_type
= tex_2d
;
183 coords
[0][0] = (float)rect
->left
/ w
;
184 coords
[0][1] = (float)rect
->top
/ h
;
187 coords
[1][0] = (float)rect
->right
/ w
;
188 coords
[1][1] = (float)rect
->top
/ h
;
191 coords
[2][0] = (float)rect
->left
/ w
;
192 coords
[2][1] = (float)rect
->bottom
/ h
;
195 coords
[3][0] = (float)rect
->right
/ w
;
196 coords
[3][1] = (float)rect
->bottom
/ h
;
200 case GL_TEXTURE_RECTANGLE_ARB
:
201 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
202 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
203 info
->tex_type
= tex_rect
;
204 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
205 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
206 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
207 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
210 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
211 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
212 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
213 info
->tex_type
= tex_cube
;
214 cube_coords_float(rect
, w
, h
, &f
);
216 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
217 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
218 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
219 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
222 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
223 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
224 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
225 info
->tex_type
= tex_cube
;
226 cube_coords_float(rect
, w
, h
, &f
);
228 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
229 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
230 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
231 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
235 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
236 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
237 info
->tex_type
= tex_cube
;
238 cube_coords_float(rect
, w
, h
, &f
);
240 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
241 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
242 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
243 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
246 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
247 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
248 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
249 info
->tex_type
= tex_cube
;
250 cube_coords_float(rect
, w
, h
, &f
);
252 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
253 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
254 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
255 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
258 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
259 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
260 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
261 info
->tex_type
= tex_cube
;
262 cube_coords_float(rect
, w
, h
, &f
);
264 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
265 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
266 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
267 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
270 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
271 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
272 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
273 info
->tex_type
= tex_cube
;
274 cube_coords_float(rect
, w
, h
, &f
);
276 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
277 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
278 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
279 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
284 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
287 *rect_out
= *rect_in
;
292 rect_out
->right
= surface
->resource
.width
;
293 rect_out
->bottom
= surface
->resource
.height
;
297 /* Context activation is done by the caller. */
298 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
299 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
301 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
302 struct wined3d_texture
*texture
= src_surface
->container
;
303 struct blt_info info
;
305 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
307 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
308 checkGLcall("glEnable(bind_target)");
310 context_bind_texture(context
, info
.bind_target
, texture
->texture_rgb
.name
);
312 /* Filtering for StretchRect */
313 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
314 wined3d_gl_mag_filter(magLookup
, filter
));
315 checkGLcall("glTexParameteri");
316 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
317 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
318 checkGLcall("glTexParameteri");
319 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
320 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
321 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
322 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
323 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
324 checkGLcall("glTexEnvi");
327 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
328 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
329 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
331 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
332 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
334 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
335 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
337 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
338 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
339 gl_info
->gl_ops
.gl
.p_glEnd();
341 /* Unbind the texture */
342 context_bind_texture(context
, info
.bind_target
, 0);
344 /* We changed the filtering settings on the texture. Inform the
345 * container about this to get the filters reset properly next draw. */
346 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3D_TEXF_POINT
;
347 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3D_TEXF_POINT
;
348 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3D_TEXF_NONE
;
349 texture
->texture_rgb
.states
[WINED3DTEXSTA_SRGBTEXTURE
] = FALSE
;
352 /* Works correctly only for <= 4 bpp formats. */
353 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
355 masks
[0] = ((1 << format
->red_size
) - 1) << format
->red_offset
;
356 masks
[1] = ((1 << format
->green_size
) - 1) << format
->green_offset
;
357 masks
[2] = ((1 << format
->blue_size
) - 1) << format
->blue_offset
;
360 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
362 const struct wined3d_format
*format
= surface
->resource
.format
;
368 TRACE("surface %p.\n", surface
);
370 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
372 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
373 return WINED3DERR_INVALIDCALL
;
376 switch (format
->byte_count
)
380 /* Allocate extra space to store the RGB bit masks. */
381 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
385 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
389 /* Allocate extra space for a palette. */
390 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
391 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
396 return E_OUTOFMEMORY
;
398 /* Some applications access the surface in via DWORDs, and do not take
399 * the necessary care at the end of the surface. So we need at least
400 * 4 extra bytes at the end of the surface. Check against the page size,
401 * if the last page used for the surface has at least 4 spare bytes we're
402 * safe, otherwise add an extra line to the DIB section. */
403 GetSystemInfo(&sysInfo
);
404 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
407 TRACE("Adding an extra line to the DIB section.\n");
410 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
411 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
412 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
413 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
414 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
415 * wined3d_surface_get_pitch(surface
);
416 b_info
->bmiHeader
.biPlanes
= 1;
417 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
419 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
420 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
421 b_info
->bmiHeader
.biClrUsed
= 0;
422 b_info
->bmiHeader
.biClrImportant
= 0;
424 /* Get the bit masks */
425 masks
= (DWORD
*)b_info
->bmiColors
;
426 switch (surface
->resource
.format
->id
)
428 case WINED3DFMT_B8G8R8_UNORM
:
429 b_info
->bmiHeader
.biCompression
= BI_RGB
;
432 case WINED3DFMT_B5G5R5X1_UNORM
:
433 case WINED3DFMT_B5G5R5A1_UNORM
:
434 case WINED3DFMT_B4G4R4A4_UNORM
:
435 case WINED3DFMT_B4G4R4X4_UNORM
:
436 case WINED3DFMT_B2G3R3_UNORM
:
437 case WINED3DFMT_B2G3R3A8_UNORM
:
438 case WINED3DFMT_R10G10B10A2_UNORM
:
439 case WINED3DFMT_R8G8B8A8_UNORM
:
440 case WINED3DFMT_R8G8B8X8_UNORM
:
441 case WINED3DFMT_B10G10R10A2_UNORM
:
442 case WINED3DFMT_B5G6R5_UNORM
:
443 case WINED3DFMT_R16G16B16A16_UNORM
:
444 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
445 get_color_masks(format
, masks
);
449 /* Don't know palette */
450 b_info
->bmiHeader
.biCompression
= BI_RGB
;
454 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
455 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
456 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
457 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->dib
.bitmap_data
, 0, 0);
459 if (!surface
->dib
.DIBsection
)
461 ERR("Failed to create DIB section.\n");
462 HeapFree(GetProcessHeap(), 0, b_info
);
463 return HRESULT_FROM_WIN32(GetLastError());
466 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
467 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
469 HeapFree(GetProcessHeap(), 0, b_info
);
471 /* Now allocate a DC. */
472 surface
->hDC
= CreateCompatibleDC(0);
473 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
475 surface
->flags
|= SFLAG_DIBSECTION
;
480 static void surface_get_memory(const struct wined3d_surface
*surface
, struct wined3d_bo_address
*data
,
483 if (location
& WINED3D_LOCATION_BUFFER
)
486 data
->buffer_object
= surface
->pbo
;
489 if (location
& WINED3D_LOCATION_USER_MEMORY
)
491 data
->addr
= surface
->user_memory
;
492 data
->buffer_object
= 0;
495 if (location
& WINED3D_LOCATION_DIB
)
497 data
->addr
= surface
->dib
.bitmap_data
;
498 data
->buffer_object
= 0;
501 if (location
& WINED3D_LOCATION_SYSMEM
)
503 data
->addr
= surface
->resource
.heap_memory
;
504 data
->buffer_object
= 0;
508 ERR("Unexpected locations %s.\n", wined3d_debug_location(location
));
510 data
->buffer_object
= 0;
513 static void surface_prepare_buffer(struct wined3d_surface
*surface
)
515 struct wined3d_context
*context
;
517 const struct wined3d_gl_info
*gl_info
;
522 context
= context_acquire(surface
->resource
.device
, NULL
);
523 gl_info
= context
->gl_info
;
525 GL_EXTCALL(glGenBuffers(1, &surface
->pbo
));
526 error
= gl_info
->gl_ops
.gl
.p_glGetError();
527 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
528 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
530 TRACE("Binding PBO %u.\n", surface
->pbo
);
532 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
533 checkGLcall("glBindBuffer");
535 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER
, surface
->resource
.size
+ 4,
536 NULL
, GL_STREAM_DRAW
));
537 checkGLcall("glBufferData");
539 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
540 checkGLcall("glBindBuffer");
542 context_release(context
);
545 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
547 TRACE("surface %p.\n", surface
);
549 if (surface
->resource
.heap_memory
)
552 /* Whatever surface we have, make sure that there is memory allocated
553 * for the downloaded copy, or a PBO to map. */
554 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
555 ERR("Failed to allocate system memory.\n");
557 if (surface
->locations
& WINED3D_LOCATION_SYSMEM
)
558 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
561 void surface_prepare_map_memory(struct wined3d_surface
*surface
)
563 switch (surface
->resource
.map_binding
)
565 case WINED3D_LOCATION_SYSMEM
:
566 surface_prepare_system_memory(surface
);
569 case WINED3D_LOCATION_USER_MEMORY
:
570 if (!surface
->user_memory
)
571 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
574 case WINED3D_LOCATION_DIB
:
575 if (!surface
->dib
.bitmap_data
)
576 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
579 case WINED3D_LOCATION_BUFFER
:
580 surface_prepare_buffer(surface
);
584 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
588 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
590 /* In some conditions the surface memory must not be freed:
591 * WINED3D_TEXTURE_CONVERTED: Converting the data back would take too long
592 * WINED3D_TEXTURE_DYNAMIC_MAP: Avoid freeing the data for performance
593 * SFLAG_CLIENT: OpenGL uses our memory as backup */
594 if (surface
->resource
.map_count
|| surface
->flags
& SFLAG_CLIENT
595 || surface
->container
->flags
& (WINED3D_TEXTURE_CONVERTED
| WINED3D_TEXTURE_PIN_SYSMEM
596 | WINED3D_TEXTURE_DYNAMIC_MAP
))
599 wined3d_resource_free_sysmem(&surface
->resource
);
600 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
603 static void surface_release_client_storage(struct wined3d_surface
*surface
)
605 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
606 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
608 if (surface
->container
->texture_rgb
.name
)
610 wined3d_texture_bind_and_dirtify(surface
->container
, context
, FALSE
);
611 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
612 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
614 if (surface
->container
->texture_srgb
.name
)
616 wined3d_texture_bind_and_dirtify(surface
->container
, context
, TRUE
);
617 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
618 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
620 wined3d_texture_force_reload(surface
->container
);
622 context_release(context
);
625 static BOOL
surface_use_pbo(const struct wined3d_surface
*surface
)
627 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
628 struct wined3d_texture
*texture
= surface
->container
;
630 return texture
->resource
.pool
== WINED3D_POOL_DEFAULT
631 && surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
632 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
633 && !texture
->resource
.format
->convert
634 && !(texture
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
)
635 && !(surface
->flags
& SFLAG_NONPOW2
);
638 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
640 /* TODO: Check against the maximum texture sizes supported by the video card. */
641 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
642 unsigned int pow2Width
, pow2Height
;
644 TRACE("surface %p.\n", surface
);
646 /* Non-power2 support */
647 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
]
648 || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
650 pow2Width
= surface
->resource
.width
;
651 pow2Height
= surface
->resource
.height
;
655 /* Find the nearest pow2 match */
656 pow2Width
= pow2Height
= 1;
657 while (pow2Width
< surface
->resource
.width
)
659 while (pow2Height
< surface
->resource
.height
)
662 surface
->pow2Width
= pow2Width
;
663 surface
->pow2Height
= pow2Height
;
665 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
667 /* TODO: Add support for non power two compressed textures. */
668 if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_HEIGHT_SCALE
))
670 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
671 surface
, surface
->resource
.width
, surface
->resource
.height
);
672 return WINED3DERR_NOTAVAILABLE
;
676 if (pow2Width
!= surface
->resource
.width
677 || pow2Height
!= surface
->resource
.height
)
679 surface
->flags
|= SFLAG_NONPOW2
;
682 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
683 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
685 /* One of three options:
686 * 1: Do the same as we do with NPOT and scale the texture, (any
687 * texture ops would require the texture to be scaled which is
689 * 2: Set the texture to the maximum size (bad idea).
690 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
691 * 4: Create the surface, but allow it to be used only for DirectDraw
692 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
693 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
694 * the render target. */
695 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
|| surface
->resource
.pool
== WINED3D_POOL_MANAGED
)
697 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
698 return WINED3DERR_NOTAVAILABLE
;
701 /* We should never use this surface in combination with OpenGL! */
702 TRACE("Creating an oversized surface: %ux%u.\n",
703 surface
->pow2Width
, surface
->pow2Height
);
706 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
707 surface
->locations
= WINED3D_LOCATION_DISCARDED
;
709 if (surface_use_pbo(surface
))
710 surface
->resource
.map_binding
= WINED3D_LOCATION_BUFFER
;
715 static void surface_unmap(struct wined3d_surface
*surface
)
717 struct wined3d_device
*device
= surface
->resource
.device
;
718 const struct wined3d_gl_info
*gl_info
;
719 struct wined3d_context
*context
;
721 TRACE("surface %p.\n", surface
);
723 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
725 switch (surface
->resource
.map_binding
)
727 case WINED3D_LOCATION_SYSMEM
:
728 case WINED3D_LOCATION_USER_MEMORY
:
729 case WINED3D_LOCATION_DIB
:
732 case WINED3D_LOCATION_BUFFER
:
733 context
= context_acquire(device
, NULL
);
734 gl_info
= context
->gl_info
;
736 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
737 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER
));
738 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
739 checkGLcall("glUnmapBuffer");
740 context_release(context
);
744 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
747 if (surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_TEXTURE_RGB
))
749 TRACE("Not dirtified, nothing to do.\n");
753 if (surface
->container
->swapchain
&& surface
->container
->swapchain
->front_buffer
== surface
->container
)
754 surface_load_location(surface
, surface
->container
->resource
.draw_binding
);
755 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
756 FIXME("Depth / stencil buffer locking is not implemented.\n");
759 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
761 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
763 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
768 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
769 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
770 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
772 const struct wined3d_gl_info
*gl_info
;
773 struct wined3d_context
*context
;
774 DWORD src_mask
, dst_mask
;
777 TRACE("device %p\n", device
);
778 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
779 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
780 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
781 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
783 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
784 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
786 if (src_mask
!= dst_mask
)
788 ERR("Incompatible formats %s and %s.\n",
789 debug_d3dformat(src_surface
->resource
.format
->id
),
790 debug_d3dformat(dst_surface
->resource
.format
->id
));
796 ERR("Not a depth / stencil format: %s.\n",
797 debug_d3dformat(src_surface
->resource
.format
->id
));
802 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
803 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
804 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
805 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
807 /* Make sure the locations are up-to-date. Loading the destination
808 * surface isn't required if the entire surface is overwritten. */
809 surface_load_location(src_surface
, src_location
);
810 if (!surface_is_full_rect(dst_surface
, dst_rect
))
811 surface_load_location(dst_surface
, dst_location
);
813 context
= context_acquire(device
, NULL
);
816 context_release(context
);
817 WARN("Invalid context, skipping blit.\n");
821 gl_info
= context
->gl_info
;
823 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
824 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
826 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
827 context_set_draw_buffer(context
, GL_NONE
);
828 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
829 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
831 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
833 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
834 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
836 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
838 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
840 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
841 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
843 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
844 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
847 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
848 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
850 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
851 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
852 checkGLcall("glBlitFramebuffer()");
854 if (wined3d_settings
.strict_draw_ordering
)
855 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
857 context_release(context
);
860 /* Blit between surface locations. Onscreen on different swapchains is not supported.
861 * Depth / stencil is not supported. */
862 static void surface_blt_fbo(const struct wined3d_device
*device
, enum wined3d_texture_filter_type filter
,
863 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
864 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
866 const struct wined3d_gl_info
*gl_info
;
867 struct wined3d_context
*context
;
868 RECT src_rect
, dst_rect
;
872 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
873 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
874 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
875 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
876 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
878 src_rect
= *src_rect_in
;
879 dst_rect
= *dst_rect_in
;
883 case WINED3D_TEXF_LINEAR
:
884 gl_filter
= GL_LINEAR
;
888 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
889 case WINED3D_TEXF_NONE
:
890 case WINED3D_TEXF_POINT
:
891 gl_filter
= GL_NEAREST
;
895 /* Resolve the source surface first if needed. */
896 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
897 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
898 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
899 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
900 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
902 /* Make sure the locations are up-to-date. Loading the destination
903 * surface isn't required if the entire surface is overwritten. (And is
904 * in fact harmful if we're being called by surface_load_location() with
905 * the purpose of loading the destination surface.) */
906 surface_load_location(src_surface
, src_location
);
907 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
908 surface_load_location(dst_surface
, dst_location
);
910 if (src_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, src_surface
);
911 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, dst_surface
);
912 else context
= context_acquire(device
, NULL
);
916 context_release(context
);
917 WARN("Invalid context, skipping blit.\n");
921 gl_info
= context
->gl_info
;
923 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
925 TRACE("Source surface %p is onscreen.\n", src_surface
);
926 buffer
= surface_get_gl_buffer(src_surface
);
927 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
931 TRACE("Source surface %p is offscreen.\n", src_surface
);
932 buffer
= GL_COLOR_ATTACHMENT0
;
935 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
936 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
937 checkGLcall("glReadBuffer()");
938 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
940 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
942 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
943 buffer
= surface_get_gl_buffer(dst_surface
);
944 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
948 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
949 buffer
= GL_COLOR_ATTACHMENT0
;
952 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
953 context_set_draw_buffer(context
, buffer
);
954 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
955 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
957 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
958 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
959 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
960 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
961 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
963 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
964 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
966 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
967 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
968 checkGLcall("glBlitFramebuffer()");
970 if (wined3d_settings
.strict_draw_ordering
971 || (dst_location
== WINED3D_LOCATION_DRAWABLE
972 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
973 gl_info
->gl_ops
.gl
.p_glFlush();
975 context_release(context
);
978 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
979 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
980 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
982 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
985 /* Source and/or destination need to be on the GL side */
986 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
991 case WINED3D_BLIT_OP_COLOR_BLIT
:
992 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
994 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
998 case WINED3D_BLIT_OP_DEPTH_BLIT
:
999 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1001 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1009 if (!(src_format
->id
== dst_format
->id
1010 || (is_identity_fixup(src_format
->color_fixup
)
1011 && is_identity_fixup(dst_format
->color_fixup
))))
1017 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1018 DWORD color
, struct wined3d_color
*float_color
)
1020 const struct wined3d_format
*format
= surface
->resource
.format
;
1021 const struct wined3d_palette
*palette
;
1025 case WINED3DFMT_P8_UINT
:
1026 palette
= surface
->container
->swapchain
? surface
->container
->swapchain
->palette
: NULL
;
1030 float_color
->r
= palette
->colors
[color
].rgbRed
/ 255.0f
;
1031 float_color
->g
= palette
->colors
[color
].rgbGreen
/ 255.0f
;
1032 float_color
->b
= palette
->colors
[color
].rgbBlue
/ 255.0f
;
1036 float_color
->r
= 0.0f
;
1037 float_color
->g
= 0.0f
;
1038 float_color
->b
= 0.0f
;
1040 float_color
->a
= color
/ 255.0f
;
1043 case WINED3DFMT_B5G6R5_UNORM
:
1044 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1045 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1046 float_color
->b
= (color
& 0x1f) / 31.0f
;
1047 float_color
->a
= 1.0f
;
1050 case WINED3DFMT_B8G8R8_UNORM
:
1051 case WINED3DFMT_B8G8R8X8_UNORM
:
1052 float_color
->r
= D3DCOLOR_R(color
);
1053 float_color
->g
= D3DCOLOR_G(color
);
1054 float_color
->b
= D3DCOLOR_B(color
);
1055 float_color
->a
= 1.0f
;
1058 case WINED3DFMT_B8G8R8A8_UNORM
:
1059 float_color
->r
= D3DCOLOR_R(color
);
1060 float_color
->g
= D3DCOLOR_G(color
);
1061 float_color
->b
= D3DCOLOR_B(color
);
1062 float_color
->a
= D3DCOLOR_A(color
);
1066 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1073 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1075 const struct wined3d_format
*format
= surface
->resource
.format
;
1079 case WINED3DFMT_S1_UINT_D15_UNORM
:
1080 *float_depth
= depth
/ (float)0x00007fff;
1083 case WINED3DFMT_D16_UNORM
:
1084 *float_depth
= depth
/ (float)0x0000ffff;
1087 case WINED3DFMT_D24_UNORM_S8_UINT
:
1088 case WINED3DFMT_X8D24_UNORM
:
1089 *float_depth
= depth
/ (float)0x00ffffff;
1092 case WINED3DFMT_D32_UNORM
:
1093 *float_depth
= depth
/ (float)0xffffffff;
1097 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1104 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1106 const struct wined3d_resource
*resource
= &surface
->container
->resource
;
1107 struct wined3d_device
*device
= resource
->device
;
1108 const struct blit_shader
*blitter
;
1110 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1111 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1114 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1115 return WINED3DERR_INVALIDCALL
;
1118 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1121 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1122 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1124 struct wined3d_device
*device
= src_surface
->resource
.device
;
1126 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1127 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1128 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1129 return WINED3DERR_INVALIDCALL
;
1131 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
1133 surface_modify_ds_location(dst_surface
, dst_location
,
1134 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1139 HRESULT CDECL
wined3d_surface_get_render_target_data(struct wined3d_surface
*surface
,
1140 struct wined3d_surface
*render_target
)
1142 TRACE("surface %p, render_target %p.\n", surface
, render_target
);
1144 /* TODO: Check surface sizes, pools, etc. */
1146 if (render_target
->resource
.multisample_type
)
1147 return WINED3DERR_INVALIDCALL
;
1149 return wined3d_surface_blt(surface
, NULL
, render_target
, NULL
, 0, NULL
, WINED3D_TEXF_POINT
);
1152 /* Context activation is done by the caller. */
1153 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1155 GL_EXTCALL(glDeleteBuffers(1, &surface
->pbo
));
1156 checkGLcall("glDeleteBuffers(1, &surface->pbo)");
1159 surface_invalidate_location(surface
, WINED3D_LOCATION_BUFFER
);
1162 static ULONG
surface_resource_incref(struct wined3d_resource
*resource
)
1164 return wined3d_surface_incref(surface_from_resource(resource
));
1167 static ULONG
surface_resource_decref(struct wined3d_resource
*resource
)
1169 return wined3d_surface_decref(surface_from_resource(resource
));
1172 static void surface_unload(struct wined3d_resource
*resource
)
1174 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1175 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1176 struct wined3d_device
*device
= resource
->device
;
1177 const struct wined3d_gl_info
*gl_info
;
1178 struct wined3d_context
*context
;
1180 TRACE("surface %p.\n", surface
);
1182 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
1184 /* Default pool resources are supposed to be destroyed before Reset is called.
1185 * Implicit resources stay however. So this means we have an implicit render target
1186 * or depth stencil. The content may be destroyed, but we still have to tear down
1187 * opengl resources, so we cannot leave early.
1189 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1190 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1191 * or the depth stencil into an FBO the texture or render buffer will be removed
1192 * and all flags get lost */
1193 surface_prepare_system_memory(surface
);
1194 memset(surface
->resource
.heap_memory
, 0, surface
->resource
.size
);
1195 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
1196 surface_invalidate_location(surface
, ~WINED3D_LOCATION_SYSMEM
);
1198 /* We also get here when the ddraw swapchain is destroyed, for example
1199 * for a mode switch. In this case this surface won't necessarily be
1200 * an implicit surface. We have to mark it lost so that the
1201 * application can restore it after the mode switch. */
1202 surface
->flags
|= SFLAG_LOST
;
1206 surface_prepare_map_memory(surface
);
1207 surface_load_location(surface
, surface
->resource
.map_binding
);
1208 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
1211 context
= context_acquire(device
, NULL
);
1212 gl_info
= context
->gl_info
;
1214 /* Destroy PBOs, but load them into real sysmem before */
1216 surface_remove_pbo(surface
, gl_info
);
1218 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1219 * all application-created targets the application has to release the surface
1220 * before calling _Reset
1222 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1224 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1225 list_remove(&entry
->entry
);
1226 HeapFree(GetProcessHeap(), 0, entry
);
1228 list_init(&surface
->renderbuffers
);
1229 surface
->current_renderbuffer
= NULL
;
1231 if (surface
->rb_multisample
)
1233 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1234 surface
->rb_multisample
= 0;
1236 if (surface
->rb_resolved
)
1238 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1239 surface
->rb_resolved
= 0;
1242 context_release(context
);
1244 resource_unload(resource
);
1247 static const struct wined3d_resource_ops surface_resource_ops
=
1249 surface_resource_incref
,
1250 surface_resource_decref
,
1254 static const struct wined3d_surface_ops surface_ops
=
1256 surface_private_setup
,
1260 /*****************************************************************************
1261 * Initializes the GDI surface, aka creates the DIB section we render to
1262 * The DIB section creation is done by calling GetDC, which will create the
1263 * section and releasing the dc to allow the app to use it. The dib section
1264 * will stay until the surface is released
1266 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1267 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1268 * avoid confusion in the shared surface code.
1271 * WINED3D_OK on success
1272 * The return values of called methods on failure
1274 *****************************************************************************/
1275 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1279 TRACE("surface %p.\n", surface
);
1281 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1283 ERR("Overlays not yet supported by GDI surfaces.\n");
1284 return WINED3DERR_INVALIDCALL
;
1287 /* Sysmem textures have memory already allocated - release it,
1288 * this avoids an unnecessary memcpy. */
1289 hr
= surface_create_dib_section(surface
);
1292 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
1294 /* We don't mind the nonpow2 stuff in GDI. */
1295 surface
->pow2Width
= surface
->resource
.width
;
1296 surface
->pow2Height
= surface
->resource
.height
;
1301 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1303 TRACE("surface %p.\n", surface
);
1305 /* Tell the swapchain to update the screen. */
1306 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
1307 x11_copy_to_screen(surface
->container
->swapchain
, &surface
->lockedRect
);
1309 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
1312 static const struct wined3d_surface_ops gdi_surface_ops
=
1314 gdi_surface_private_setup
,
1318 /* This call just downloads data, the caller is responsible for binding the
1319 * correct texture. */
1320 /* Context activation is done by the caller. */
1321 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1324 const struct wined3d_format
*format
= surface
->resource
.format
;
1325 struct wined3d_bo_address data
;
1327 /* Only support read back of converted P8 surfaces. */
1328 if (surface
->container
->flags
& WINED3D_TEXTURE_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1330 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1334 surface_get_memory(surface
, &data
, dst_location
);
1336 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1338 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1339 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, data
.addr
);
1341 if (data
.buffer_object
)
1343 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1344 checkGLcall("glBindBuffer");
1345 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
1346 checkGLcall("glGetCompressedTexImageARB");
1347 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1348 checkGLcall("glBindBuffer");
1352 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
1353 surface
->texture_level
, data
.addr
));
1354 checkGLcall("glGetCompressedTexImageARB");
1360 GLenum gl_format
= format
->glFormat
;
1361 GLenum gl_type
= format
->glType
;
1365 if (surface
->flags
& SFLAG_NONPOW2
)
1367 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
1368 src_pitch
= format
->byte_count
* surface
->pow2Width
;
1369 dst_pitch
= wined3d_surface_get_pitch(surface
);
1370 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
1371 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
1378 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1379 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1381 if (data
.buffer_object
)
1383 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1384 checkGLcall("glBindBuffer");
1386 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1387 gl_format
, gl_type
, NULL
);
1388 checkGLcall("glGetTexImage");
1390 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1391 checkGLcall("glBindBuffer");
1395 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1396 gl_format
, gl_type
, mem
);
1397 checkGLcall("glGetTexImage");
1400 if (surface
->flags
& SFLAG_NONPOW2
)
1402 const BYTE
*src_data
;
1406 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1407 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1408 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1410 * We're doing this...
1412 * instead of boxing the texture :
1413 * |<-texture width ->| -->pow2width| /\
1414 * |111111111111111111| | |
1415 * |222 Texture 222222| boxed empty | texture height
1416 * |3333 Data 33333333| | |
1417 * |444444444444444444| | \/
1418 * ----------------------------------- |
1419 * | boxed empty | boxed empty | pow2height
1421 * -----------------------------------
1424 * we're repacking the data to the expected texture width
1426 * |<-texture width ->| -->pow2width| /\
1427 * |111111111111111111222222222222222| |
1428 * |222333333333333333333444444444444| texture height
1432 * | empty | pow2height
1434 * -----------------------------------
1438 * |<-texture width ->| /\
1439 * |111111111111111111|
1440 * |222222222222222222|texture height
1441 * |333333333333333333|
1442 * |444444444444444444| \/
1443 * --------------------
1445 * This also means that any references to surface memory should work with the data as if it were a
1446 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1448 * internally the texture is still stored in a boxed format so any references to textureName will
1449 * get a boxed texture with width pow2width and not a texture of width resource.width.
1451 * Performance should not be an issue, because applications normally do not lock the surfaces when
1452 * rendering. If an app does, the WINED3D_TEXTURE_DYNAMIC_MAP flag will kick in and the memory copy
1453 * won't be released, and doesn't have to be re-read. */
1455 dst_data
= data
.addr
;
1456 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
1457 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1459 memcpy(dst_data
, src_data
, dst_pitch
);
1460 src_data
+= src_pitch
;
1461 dst_data
+= dst_pitch
;
1464 HeapFree(GetProcessHeap(), 0, mem
);
1469 /* This call just uploads data, the caller is responsible for binding the
1470 * correct texture. */
1471 /* Context activation is done by the caller. */
1472 void wined3d_surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1473 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1474 BOOL srgb
, const struct wined3d_const_bo_address
*data
)
1476 UINT update_w
= src_rect
->right
- src_rect
->left
;
1477 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1479 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1480 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1481 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1483 if (surface
->resource
.map_count
)
1485 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1486 surface
->container
->flags
|= WINED3D_TEXTURE_PIN_SYSMEM
;
1489 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1491 update_h
*= format
->height_scale
.numerator
;
1492 update_h
/= format
->height_scale
.denominator
;
1495 if (data
->buffer_object
)
1497 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, data
->buffer_object
));
1498 checkGLcall("glBindBuffer");
1501 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1503 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1504 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1505 const BYTE
*addr
= data
->addr
;
1508 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1509 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1512 internal
= format
->glGammaInternal
;
1513 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1514 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
1515 internal
= format
->rtInternal
;
1517 internal
= format
->glInternal
;
1519 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
1520 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1521 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1523 if (row_length
== src_pitch
)
1525 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1526 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1532 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
1533 * can't use the unpack row length like below. */
1534 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1536 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1537 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1538 y
+= format
->block_height
;
1542 checkGLcall("glCompressedTexSubImage2DARB");
1546 const BYTE
*addr
= data
->addr
;
1548 addr
+= src_rect
->top
* src_pitch
;
1549 addr
+= src_rect
->left
* format
->byte_count
;
1551 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1552 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1553 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1555 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1556 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1557 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1558 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1559 checkGLcall("glTexSubImage2D");
1562 if (data
->buffer_object
)
1564 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
1565 checkGLcall("glBindBuffer");
1568 if (wined3d_settings
.strict_draw_ordering
)
1569 gl_info
->gl_ops
.gl
.p_glFlush();
1571 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1573 struct wined3d_device
*device
= surface
->resource
.device
;
1576 for (i
= 0; i
< device
->context_count
; ++i
)
1578 context_surface_update(device
->contexts
[i
], surface
);
1583 static BOOL
surface_check_block_align(struct wined3d_surface
*surface
, const RECT
*rect
)
1585 UINT width_mask
, height_mask
;
1587 if (!rect
->left
&& !rect
->top
1588 && rect
->right
== surface
->resource
.width
1589 && rect
->bottom
== surface
->resource
.height
)
1592 /* This assumes power of two block sizes, but NPOT block sizes would be
1594 width_mask
= surface
->resource
.format
->block_width
- 1;
1595 height_mask
= surface
->resource
.format
->block_height
- 1;
1597 if (!(rect
->left
& width_mask
) && !(rect
->top
& height_mask
)
1598 && !(rect
->right
& width_mask
) && !(rect
->bottom
& height_mask
))
1604 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1605 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1607 const struct wined3d_format
*src_format
;
1608 const struct wined3d_format
*dst_format
;
1609 const struct wined3d_gl_info
*gl_info
;
1610 struct wined3d_context
*context
;
1611 struct wined3d_bo_address data
;
1612 UINT update_w
, update_h
;
1618 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1619 dst_surface
, wine_dbgstr_point(dst_point
),
1620 src_surface
, wine_dbgstr_rect(src_rect
));
1622 src_format
= src_surface
->resource
.format
;
1623 dst_format
= dst_surface
->resource
.format
;
1625 if (src_format
->id
!= dst_format
->id
)
1627 WARN("Source and destination surfaces should have the same format.\n");
1628 return WINED3DERR_INVALIDCALL
;
1637 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1639 WARN("Invalid destination point.\n");
1640 return WINED3DERR_INVALIDCALL
;
1647 r
.right
= src_surface
->resource
.width
;
1648 r
.bottom
= src_surface
->resource
.height
;
1651 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
1652 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
1654 WARN("Invalid source rectangle.\n");
1655 return WINED3DERR_INVALIDCALL
;
1658 dst_w
= dst_surface
->resource
.width
;
1659 dst_h
= dst_surface
->resource
.height
;
1661 update_w
= src_rect
->right
- src_rect
->left
;
1662 update_h
= src_rect
->bottom
- src_rect
->top
;
1664 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1665 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1667 WARN("Destination out of bounds.\n");
1668 return WINED3DERR_INVALIDCALL
;
1671 if ((src_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(src_surface
, src_rect
))
1673 WARN("Source rectangle not block-aligned.\n");
1674 return WINED3DERR_INVALIDCALL
;
1677 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1678 if ((dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(dst_surface
, &dst_rect
))
1680 WARN("Destination rectangle not block-aligned.\n");
1681 return WINED3DERR_INVALIDCALL
;
1684 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1685 if (dst_format
->convert
|| wined3d_format_get_color_key_conversion(dst_surface
->container
, FALSE
))
1686 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1688 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
1689 gl_info
= context
->gl_info
;
1691 /* Only load the surface for partial updates. For newly allocated texture
1692 * the texture wouldn't be the current location, and we'd upload zeroes
1693 * just to overwrite them again. */
1694 if (update_w
== dst_w
&& update_h
== dst_h
)
1695 wined3d_texture_prepare_texture(dst_surface
->container
, context
, FALSE
);
1697 surface_load_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1698 wined3d_texture_bind(dst_surface
->container
, context
, FALSE
);
1700 surface_get_memory(src_surface
, &data
, src_surface
->locations
);
1701 src_pitch
= wined3d_surface_get_pitch(src_surface
);
1703 wined3d_surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
,
1704 src_pitch
, dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1706 context_invalidate_active_texture(context
);
1708 context_release(context
);
1710 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1711 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1716 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1717 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1718 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1719 /* Context activation is done by the caller. */
1720 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1722 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
1723 struct wined3d_renderbuffer_entry
*entry
;
1724 GLuint renderbuffer
= 0;
1725 unsigned int src_width
, src_height
;
1726 unsigned int width
, height
;
1728 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
1730 width
= rt
->pow2Width
;
1731 height
= rt
->pow2Height
;
1735 width
= surface
->pow2Width
;
1736 height
= surface
->pow2Height
;
1739 src_width
= surface
->pow2Width
;
1740 src_height
= surface
->pow2Height
;
1742 /* A depth stencil smaller than the render target is not valid */
1743 if (width
> src_width
|| height
> src_height
) return;
1745 /* Remove any renderbuffer set if the sizes match */
1746 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1747 || (width
== src_width
&& height
== src_height
))
1749 surface
->current_renderbuffer
= NULL
;
1753 /* Look if we've already got a renderbuffer of the correct dimensions */
1754 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1756 if (entry
->width
== width
&& entry
->height
== height
)
1758 renderbuffer
= entry
->id
;
1759 surface
->current_renderbuffer
= entry
;
1766 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
1767 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
1768 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
1769 surface
->resource
.format
->glInternal
, width
, height
);
1771 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
1772 entry
->width
= width
;
1773 entry
->height
= height
;
1774 entry
->id
= renderbuffer
;
1775 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
1777 surface
->current_renderbuffer
= entry
;
1780 checkGLcall("set_compatible_renderbuffer");
1783 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
1785 const struct wined3d_swapchain
*swapchain
= surface
->container
->swapchain
;
1787 TRACE("surface %p.\n", surface
);
1791 ERR("Surface %p is not on a swapchain.\n", surface
);
1795 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
->container
)
1797 if (swapchain
->render_to_fbo
)
1799 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1800 return GL_COLOR_ATTACHMENT0
;
1802 TRACE("Returning GL_BACK\n");
1805 else if (surface
->container
== swapchain
->front_buffer
)
1807 TRACE("Returning GL_FRONT\n");
1811 FIXME("Higher back buffer, returning GL_BACK\n");
1815 void surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
1817 DWORD location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
1820 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
1822 if (surface
->resource
.pool
== WINED3D_POOL_SCRATCH
)
1823 ERR("Not supported on scratch surfaces.\n");
1825 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
);
1827 /* Reload if either the texture and sysmem have different ideas about the
1828 * color key, or the actual key values changed. */
1829 if (ck_changed
|| ((surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
1830 && (surface
->gl_color_key
.color_space_low_value
1831 != surface
->container
->src_blt_color_key
.color_space_low_value
1832 || surface
->gl_color_key
.color_space_high_value
1833 != surface
->container
->src_blt_color_key
.color_space_high_value
)))
1835 TRACE("Reloading because of color keying\n");
1836 /* To perform the color key conversion we need a sysmem copy of
1837 * the surface. Make sure we have it. */
1839 surface_prepare_map_memory(surface
);
1840 surface_load_location(surface
, surface
->resource
.map_binding
);
1841 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
1842 /* Switching color keying on / off may change the internal format. */
1844 wined3d_texture_force_reload(surface
->container
);
1846 else if (!(surface
->locations
& location
))
1848 TRACE("Reloading because surface is dirty.\n");
1852 TRACE("surface is already in texture\n");
1856 surface_load_location(surface
, location
);
1857 surface_evict_sysmem(surface
);
1860 /* See also float_16_to_32() in wined3d_private.h */
1861 static inline unsigned short float_32_to_16(const float *in
)
1864 float tmp
= fabsf(*in
);
1865 unsigned int mantissa
;
1868 /* Deal with special numbers */
1874 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
1876 if (tmp
< powf(2, 10))
1882 } while (tmp
< powf(2, 10));
1884 else if (tmp
>= powf(2, 11))
1890 } while (tmp
>= powf(2, 11));
1893 mantissa
= (unsigned int)tmp
;
1894 if (tmp
- mantissa
>= 0.5f
)
1895 ++mantissa
; /* Round to nearest, away from zero. */
1897 exp
+= 10; /* Normalize the mantissa. */
1898 exp
+= 15; /* Exponent is encoded with excess 15. */
1900 if (exp
> 30) /* too big */
1902 ret
= 0x7c00; /* INF */
1906 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1909 mantissa
= mantissa
>> 1;
1912 ret
= mantissa
& 0x3ff;
1916 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
1919 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
1923 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
1925 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
1927 return wined3d_texture_incref(surface
->container
);
1930 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
1932 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
1934 return wined3d_texture_decref(surface
->container
);
1937 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
1939 TRACE("surface %p.\n", surface
);
1941 if (!surface
->resource
.device
->d3d_initialized
)
1943 ERR("D3D not initialized.\n");
1947 wined3d_texture_preload(surface
->container
);
1950 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
1952 TRACE("surface %p.\n", surface
);
1954 return surface
->resource
.parent
;
1957 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
1959 TRACE("surface %p.\n", surface
);
1961 return &surface
->resource
;
1964 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
1966 TRACE("surface %p, flags %#x.\n", surface
, flags
);
1970 case WINEDDGBS_CANBLT
:
1971 case WINEDDGBS_ISBLTDONE
:
1975 return WINED3DERR_INVALIDCALL
;
1979 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
1981 TRACE("surface %p, flags %#x.\n", surface
, flags
);
1983 /* XXX: DDERR_INVALIDSURFACETYPE */
1987 case WINEDDGFS_CANFLIP
:
1988 case WINEDDGFS_ISFLIPDONE
:
1992 return WINED3DERR_INVALIDCALL
;
1996 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
1998 TRACE("surface %p.\n", surface
);
2000 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2001 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2004 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2006 TRACE("surface %p.\n", surface
);
2008 surface
->flags
&= ~SFLAG_LOST
;
2012 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
2014 unsigned int alignment
;
2017 TRACE("surface %p.\n", surface
);
2020 return surface
->pitch
;
2022 alignment
= surface
->resource
.device
->surface_alignment
;
2023 pitch
= wined3d_format_calculate_pitch(surface
->resource
.format
, surface
->resource
.width
);
2024 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
2026 TRACE("Returning %u.\n", pitch
);
2031 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
2035 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
2037 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2039 WARN("Not an overlay surface.\n");
2040 return WINEDDERR_NOTAOVERLAYSURFACE
;
2043 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
2044 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
2045 surface
->overlay_destrect
.left
= x
;
2046 surface
->overlay_destrect
.top
= y
;
2047 surface
->overlay_destrect
.right
= x
+ w
;
2048 surface
->overlay_destrect
.bottom
= y
+ h
;
2053 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
2055 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
2057 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2059 TRACE("Not an overlay surface.\n");
2060 return WINEDDERR_NOTAOVERLAYSURFACE
;
2063 if (!surface
->overlay_dest
)
2065 TRACE("Overlay not visible.\n");
2068 return WINEDDERR_OVERLAYNOTVISIBLE
;
2071 *x
= surface
->overlay_destrect
.left
;
2072 *y
= surface
->overlay_destrect
.top
;
2074 TRACE("Returning position %d, %d.\n", *x
, *y
);
2079 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
2080 DWORD flags
, struct wined3d_surface
*ref
)
2082 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
2084 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2086 TRACE("Not an overlay surface.\n");
2087 return WINEDDERR_NOTAOVERLAYSURFACE
;
2093 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
2094 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
2096 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2097 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
2099 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2101 WARN("Not an overlay surface.\n");
2102 return WINEDDERR_NOTAOVERLAYSURFACE
;
2104 else if (!dst_surface
)
2106 WARN("Dest surface is NULL.\n");
2107 return WINED3DERR_INVALIDCALL
;
2112 surface
->overlay_srcrect
= *src_rect
;
2116 surface
->overlay_srcrect
.left
= 0;
2117 surface
->overlay_srcrect
.top
= 0;
2118 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
2119 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
2124 surface
->overlay_destrect
= *dst_rect
;
2128 surface
->overlay_destrect
.left
= 0;
2129 surface
->overlay_destrect
.top
= 0;
2130 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
2131 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
2134 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
2136 surface
->overlay_dest
= NULL
;
2137 list_remove(&surface
->overlay_entry
);
2140 if (flags
& WINEDDOVER_SHOW
)
2142 if (surface
->overlay_dest
!= dst_surface
)
2144 surface
->overlay_dest
= dst_surface
;
2145 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
2148 else if (flags
& WINEDDOVER_HIDE
)
2150 /* tests show that the rectangles are erased on hide */
2151 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
2152 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
2153 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
2154 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
2155 surface
->overlay_dest
= NULL
;
2161 HRESULT
wined3d_surface_update_desc(struct wined3d_surface
*surface
,
2162 const struct wined3d_gl_info
*gl_info
, void *mem
, unsigned int pitch
)
2164 struct wined3d_resource
*texture_resource
= &surface
->container
->resource
;
2165 unsigned int width
, height
;
2166 BOOL create_dib
= FALSE
;
2167 DWORD valid_location
= 0;
2170 if (surface
->flags
& SFLAG_DIBSECTION
)
2172 DeleteDC(surface
->hDC
);
2173 DeleteObject(surface
->dib
.DIBsection
);
2174 surface
->dib
.bitmap_data
= NULL
;
2175 surface
->flags
&= ~SFLAG_DIBSECTION
;
2179 surface
->locations
= 0;
2180 wined3d_resource_free_sysmem(&surface
->resource
);
2182 width
= texture_resource
->width
;
2183 height
= texture_resource
->height
;
2184 surface
->resource
.width
= width
;
2185 surface
->resource
.height
= height
;
2186 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
2187 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
2189 surface
->pow2Width
= width
;
2190 surface
->pow2Height
= height
;
2194 surface
->pow2Width
= surface
->pow2Height
= 1;
2195 while (surface
->pow2Width
< width
)
2196 surface
->pow2Width
<<= 1;
2197 while (surface
->pow2Height
< height
)
2198 surface
->pow2Height
<<= 1;
2201 if (surface
->pow2Width
!= width
|| surface
->pow2Height
!= height
)
2202 surface
->flags
|= SFLAG_NONPOW2
;
2204 surface
->flags
&= ~SFLAG_NONPOW2
;
2206 if ((surface
->user_memory
= mem
))
2208 surface
->resource
.map_binding
= WINED3D_LOCATION_USER_MEMORY
;
2209 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
2211 surface
->pitch
= pitch
;
2212 surface
->resource
.format
= texture_resource
->format
;
2213 surface
->resource
.multisample_type
= texture_resource
->multisample_type
;
2214 surface
->resource
.multisample_quality
= texture_resource
->multisample_quality
;
2216 surface
->resource
.size
= height
* surface
->pitch
;
2218 surface
->resource
.size
= wined3d_format_calculate_size(texture_resource
->format
,
2219 texture_resource
->device
->surface_alignment
, width
, height
, 1);
2221 /* The format might be changed to a format that needs conversion.
2222 * If the surface didn't use PBOs previously but could now, don't
2223 * change it - whatever made us not use PBOs might come back, e.g.
2225 if (surface
->resource
.map_binding
== WINED3D_LOCATION_BUFFER
&& !surface_use_pbo(surface
))
2226 surface
->resource
.map_binding
= create_dib
? WINED3D_LOCATION_DIB
: WINED3D_LOCATION_SYSMEM
;
2230 if (FAILED(hr
= surface_create_dib_section(surface
)))
2232 ERR("Failed to create dib section, hr %#x.\n", hr
);
2235 if (!valid_location
)
2236 valid_location
= WINED3D_LOCATION_DIB
;
2239 if (!valid_location
)
2241 surface_prepare_system_memory(surface
);
2242 valid_location
= WINED3D_LOCATION_SYSMEM
;
2245 surface_validate_location(surface
, valid_location
);
2250 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
2251 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2253 unsigned short *dst_s
;
2257 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2259 for (y
= 0; y
< h
; ++y
)
2261 src_f
= (const float *)(src
+ y
* pitch_in
);
2262 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
2263 for (x
= 0; x
< w
; ++x
)
2265 dst_s
[x
] = float_32_to_16(src_f
+ x
);
2270 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2271 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2273 static const unsigned char convert_5to8
[] =
2275 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2276 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2277 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2278 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2280 static const unsigned char convert_6to8
[] =
2282 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2283 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2284 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2285 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2286 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2287 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2288 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2289 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2293 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2295 for (y
= 0; y
< h
; ++y
)
2297 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
2298 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2299 for (x
= 0; x
< w
; ++x
)
2301 WORD pixel
= src_line
[x
];
2302 dst_line
[x
] = 0xff000000
2303 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
2304 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
2305 | convert_5to8
[(pixel
& 0x001f)];
2310 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2311 * in both cases we're just setting the X / Alpha channel to 0xff. */
2312 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2313 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2317 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2319 for (y
= 0; y
< h
; ++y
)
2321 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
2322 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2324 for (x
= 0; x
< w
; ++x
)
2326 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
2331 static inline BYTE
cliptobyte(int x
)
2333 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
2336 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2337 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2339 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2342 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2344 for (y
= 0; y
< h
; ++y
)
2346 const BYTE
*src_line
= src
+ y
* pitch_in
;
2347 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2348 for (x
= 0; x
< w
; ++x
)
2350 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2351 * C = Y - 16; D = U - 128; E = V - 128;
2352 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2353 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2354 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2355 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2356 * U and V are shared between the pixels. */
2357 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2359 d
= (int) src_line
[1] - 128;
2360 e
= (int) src_line
[3] - 128;
2362 g2
= - 100 * d
- 208 * e
+ 128;
2365 c2
= 298 * ((int) src_line
[0] - 16);
2366 dst_line
[x
] = 0xff000000
2367 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
2368 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
2369 | cliptobyte((c2
+ b2
) >> 8); /* blue */
2370 /* Scale RGB values to 0..255 range,
2371 * then clip them if still not in range (may be negative),
2372 * then shift them within DWORD if necessary. */
2378 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
2379 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2382 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2384 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
2386 for (y
= 0; y
< h
; ++y
)
2388 const BYTE
*src_line
= src
+ y
* pitch_in
;
2389 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
2390 for (x
= 0; x
< w
; ++x
)
2392 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2393 * C = Y - 16; D = U - 128; E = V - 128;
2394 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2395 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2396 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2397 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2398 * U and V are shared between the pixels. */
2399 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2401 d
= (int) src_line
[1] - 128;
2402 e
= (int) src_line
[3] - 128;
2404 g2
= - 100 * d
- 208 * e
+ 128;
2407 c2
= 298 * ((int) src_line
[0] - 16);
2408 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
2409 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
2410 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
2411 /* Scale RGB values to 0..255 range,
2412 * then clip them if still not in range (may be negative),
2413 * then shift them within DWORD if necessary. */
2419 struct d3dfmt_converter_desc
2421 enum wined3d_format_id from
, to
;
2422 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
2425 static const struct d3dfmt_converter_desc converters
[] =
2427 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
2428 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
2429 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2430 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2431 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
2432 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
2435 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
2436 enum wined3d_format_id to
)
2440 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
2442 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
2443 return &converters
[i
];
2449 static struct wined3d_texture
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
2451 struct wined3d_map_desc src_map
, dst_map
;
2452 const struct d3dfmt_converter_desc
*conv
;
2453 struct wined3d_texture
*ret
= NULL
;
2454 struct wined3d_resource_desc desc
;
2455 struct wined3d_surface
*dst
;
2457 conv
= find_converter(source
->resource
.format
->id
, to_fmt
);
2460 FIXME("Cannot find a conversion function from format %s to %s.\n",
2461 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
2465 /* FIXME: Multisampled conversion? */
2466 wined3d_resource_get_desc(&source
->resource
, &desc
);
2467 desc
.resource_type
= WINED3D_RTYPE_TEXTURE
;
2468 desc
.format
= to_fmt
;
2470 desc
.pool
= WINED3D_POOL_SCRATCH
;
2471 if (FAILED(wined3d_texture_create(source
->resource
.device
, &desc
, 1,
2472 WINED3D_SURFACE_MAPPABLE
| WINED3D_SURFACE_DISCARD
, NULL
, NULL
, &wined3d_null_parent_ops
, &ret
)))
2474 ERR("Failed to create a destination surface for conversion.\n");
2477 dst
= surface_from_resource(wined3d_texture_get_sub_resource(ret
, 0));
2479 memset(&src_map
, 0, sizeof(src_map
));
2480 memset(&dst_map
, 0, sizeof(dst_map
));
2482 if (FAILED(wined3d_surface_map(source
, &src_map
, NULL
, WINED3D_MAP_READONLY
)))
2484 ERR("Failed to lock the source surface.\n");
2485 wined3d_texture_decref(ret
);
2488 if (FAILED(wined3d_surface_map(dst
, &dst_map
, NULL
, 0)))
2490 ERR("Failed to lock the destination surface.\n");
2491 wined3d_surface_unmap(source
);
2492 wined3d_texture_decref(ret
);
2496 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
2497 source
->resource
.width
, source
->resource
.height
);
2499 wined3d_surface_unmap(dst
);
2500 wined3d_surface_unmap(source
);
2505 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
2506 unsigned int bpp
, UINT pitch
, DWORD color
)
2513 #define COLORFILL_ROW(type) \
2515 type *d = (type *)buf; \
2516 for (x = 0; x < width; ++x) \
2517 d[x] = (type)color; \
2523 COLORFILL_ROW(BYTE
);
2527 COLORFILL_ROW(WORD
);
2533 for (x
= 0; x
< width
; ++x
, d
+= 3)
2535 d
[0] = (color
) & 0xff;
2536 d
[1] = (color
>> 8) & 0xff;
2537 d
[2] = (color
>> 16) & 0xff;
2542 COLORFILL_ROW(DWORD
);
2546 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
2547 return WINED3DERR_NOTAVAILABLE
;
2550 #undef COLORFILL_ROW
2552 /* Now copy first row. */
2554 for (y
= 1; y
< height
; ++y
)
2557 memcpy(buf
, first
, width
* bpp
);
2563 struct wined3d_surface
* CDECL
wined3d_surface_from_resource(struct wined3d_resource
*resource
)
2565 return surface_from_resource(resource
);
2568 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
2570 TRACE("surface %p.\n", surface
);
2572 if (!surface
->resource
.map_count
)
2574 WARN("Trying to unmap unmapped surface.\n");
2575 return WINEDDERR_NOTLOCKED
;
2577 --surface
->resource
.map_count
;
2579 surface
->surface_ops
->surface_unmap(surface
);
2584 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
2585 struct wined3d_map_desc
*map_desc
, const RECT
*rect
, DWORD flags
)
2587 const struct wined3d_format
*format
= surface
->resource
.format
;
2588 struct wined3d_device
*device
= surface
->resource
.device
;
2589 struct wined3d_context
*context
;
2590 const struct wined3d_gl_info
*gl_info
;
2593 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
2594 surface
, map_desc
, wine_dbgstr_rect(rect
), flags
);
2596 if (surface
->resource
.map_count
)
2598 WARN("Surface is already mapped.\n");
2599 return WINED3DERR_INVALIDCALL
;
2602 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && rect
2603 && !surface_check_block_align(surface
, rect
))
2605 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
2606 wine_dbgstr_rect(rect
), format
->block_width
, format
->block_height
);
2608 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
2609 return WINED3DERR_INVALIDCALL
;
2612 ++surface
->resource
.map_count
;
2614 if (!(surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
2615 WARN("Trying to lock unlockable surface.\n");
2617 /* Performance optimization: Count how often a surface is mapped, if it is
2618 * mapped regularly do not throw away the system memory copy. This avoids
2619 * the need to download the surface from OpenGL all the time. The surface
2620 * is still downloaded if the OpenGL texture is changed. Note that this
2621 * only really makes sense for managed textures.*/
2622 if (!(surface
->container
->flags
& WINED3D_TEXTURE_DYNAMIC_MAP
)
2623 && surface
->resource
.map_binding
== WINED3D_LOCATION_SYSMEM
)
2625 if (++surface
->lockCount
> MAXLOCKCOUNT
)
2627 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
2628 surface
->container
->flags
|= WINED3D_TEXTURE_DYNAMIC_MAP
;
2632 surface_prepare_map_memory(surface
);
2633 if (flags
& WINED3D_MAP_DISCARD
)
2635 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2636 wined3d_debug_location(surface
->resource
.map_binding
));
2637 surface_validate_location(surface
, surface
->resource
.map_binding
);
2641 if (surface
->resource
.usage
& WINED3DUSAGE_DYNAMIC
)
2642 WARN_(d3d_perf
)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
2644 surface_load_location(surface
, surface
->resource
.map_binding
);
2647 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
2648 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
2650 switch (surface
->resource
.map_binding
)
2652 case WINED3D_LOCATION_SYSMEM
:
2653 base_memory
= surface
->resource
.heap_memory
;
2656 case WINED3D_LOCATION_USER_MEMORY
:
2657 base_memory
= surface
->user_memory
;
2660 case WINED3D_LOCATION_DIB
:
2661 base_memory
= surface
->dib
.bitmap_data
;
2664 case WINED3D_LOCATION_BUFFER
:
2665 context
= context_acquire(device
, NULL
);
2666 gl_info
= context
->gl_info
;
2668 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
2669 base_memory
= GL_EXTCALL(glMapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_READ_WRITE
));
2670 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
2671 checkGLcall("map PBO");
2673 context_release(context
);
2677 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
2681 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
2682 map_desc
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
2684 map_desc
->row_pitch
= wined3d_surface_get_pitch(surface
);
2685 map_desc
->slice_pitch
= 0;
2689 map_desc
->data
= base_memory
;
2690 surface
->lockedRect
.left
= 0;
2691 surface
->lockedRect
.top
= 0;
2692 surface
->lockedRect
.right
= surface
->resource
.width
;
2693 surface
->lockedRect
.bottom
= surface
->resource
.height
;
2697 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
2699 /* Compressed textures are block based, so calculate the offset of
2700 * the block that contains the top-left pixel of the locked rectangle. */
2701 map_desc
->data
= base_memory
2702 + ((rect
->top
/ format
->block_height
) * map_desc
->row_pitch
)
2703 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
2707 map_desc
->data
= base_memory
2708 + (map_desc
->row_pitch
* rect
->top
)
2709 + (rect
->left
* format
->byte_count
);
2711 surface
->lockedRect
.left
= rect
->left
;
2712 surface
->lockedRect
.top
= rect
->top
;
2713 surface
->lockedRect
.right
= rect
->right
;
2714 surface
->lockedRect
.bottom
= rect
->bottom
;
2717 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
2718 TRACE("Returning memory %p, pitch %u.\n", map_desc
->data
, map_desc
->row_pitch
);
2723 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
2727 TRACE("surface %p, dc %p.\n", surface
, dc
);
2729 /* Give more detailed info for ddraw. */
2730 if (surface
->flags
& SFLAG_DCINUSE
)
2731 return WINEDDERR_DCALREADYCREATED
;
2733 /* Can't GetDC if the surface is locked. */
2734 if (surface
->resource
.map_count
)
2735 return WINED3DERR_INVALIDCALL
;
2737 /* Create a DIB section if there isn't a dc yet. */
2740 if (surface
->flags
& SFLAG_CLIENT
)
2742 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
2743 surface_release_client_storage(surface
);
2745 hr
= surface_create_dib_section(surface
);
2747 return WINED3DERR_INVALIDCALL
;
2748 if (!(surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
2749 || surface
->container
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
2751 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
2754 surface_load_location(surface
, WINED3D_LOCATION_DIB
);
2755 surface_invalidate_location(surface
, ~WINED3D_LOCATION_DIB
);
2757 surface
->flags
|= SFLAG_DCINUSE
;
2758 surface
->resource
.map_count
++;
2761 TRACE("Returning dc %p.\n", *dc
);
2766 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
2768 TRACE("surface %p, dc %p.\n", surface
, dc
);
2770 if (!(surface
->flags
& SFLAG_DCINUSE
))
2771 return WINEDDERR_NODC
;
2773 if (surface
->hDC
!= dc
)
2775 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
2777 return WINEDDERR_NODC
;
2780 surface
->resource
.map_count
--;
2781 surface
->flags
&= ~SFLAG_DCINUSE
;
2783 if (surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
2784 || (surface
->container
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
2785 && surface
->resource
.map_binding
!= WINED3D_LOCATION_DIB
))
2787 /* The game Salammbo modifies the surface contents without mapping the surface between
2788 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
2789 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
2790 * Do not only copy the DIB to the map location, but also make sure the map location is
2791 * copied back to the DIB in the next getdc call.
2793 * The same consideration applies to user memory surfaces. */
2794 surface_load_location(surface
, surface
->resource
.map_binding
);
2795 surface_invalidate_location(surface
, WINED3D_LOCATION_DIB
);
2801 static void read_from_framebuffer(struct wined3d_surface
*surface
, DWORD dst_location
)
2803 struct wined3d_device
*device
= surface
->resource
.device
;
2804 const struct wined3d_gl_info
*gl_info
;
2805 struct wined3d_context
*context
;
2807 BYTE
*row
, *top
, *bottom
;
2809 BOOL srcIsUpsideDown
;
2810 struct wined3d_bo_address data
;
2812 surface_get_memory(surface
, &data
, dst_location
);
2814 context
= context_acquire(device
, surface
);
2815 context_apply_blit_state(context
, device
);
2816 gl_info
= context
->gl_info
;
2818 /* Select the correct read buffer, and give some debug output.
2819 * There is no need to keep track of the current read buffer or reset it, every part of the code
2820 * that reads sets the read buffer as desired.
2822 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
2824 /* Mapping the primary render target which is not on a swapchain.
2825 * Read from the back buffer. */
2826 TRACE("Mapping offscreen render target.\n");
2827 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
2828 srcIsUpsideDown
= TRUE
;
2832 /* Onscreen surfaces are always part of a swapchain */
2833 GLenum buffer
= surface_get_gl_buffer(surface
);
2834 TRACE("Mapping %#x buffer.\n", buffer
);
2835 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
2836 checkGLcall("glReadBuffer");
2837 srcIsUpsideDown
= FALSE
;
2840 if (data
.buffer_object
)
2842 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
2843 checkGLcall("glBindBuffer");
2846 /* Setup pixel store pack state -- to glReadPixels into the correct place */
2847 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
2848 checkGLcall("glPixelStorei");
2850 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0,
2851 surface
->resource
.width
, surface
->resource
.height
,
2852 surface
->resource
.format
->glFormat
,
2853 surface
->resource
.format
->glType
, data
.addr
);
2854 checkGLcall("glReadPixels");
2856 /* Reset previous pixel store pack state */
2857 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
2858 checkGLcall("glPixelStorei");
2860 if (!srcIsUpsideDown
)
2862 /* glReadPixels returns the image upside down, and there is no way to prevent this.
2863 * Flip the lines in software. */
2864 UINT pitch
= wined3d_surface_get_pitch(surface
);
2866 if (!(row
= HeapAlloc(GetProcessHeap(), 0, pitch
)))
2869 if (data
.buffer_object
)
2871 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
2872 checkGLcall("glMapBuffer");
2878 bottom
= mem
+ pitch
* (surface
->resource
.height
- 1);
2879 for (i
= 0; i
< surface
->resource
.height
/ 2; i
++)
2881 memcpy(row
, top
, pitch
);
2882 memcpy(top
, bottom
, pitch
);
2883 memcpy(bottom
, row
, pitch
);
2887 HeapFree(GetProcessHeap(), 0, row
);
2889 if (data
.buffer_object
)
2890 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
2894 if (data
.buffer_object
)
2896 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
2897 checkGLcall("glBindBuffer");
2900 context_release(context
);
2903 /* Read the framebuffer contents into a texture. Note that this function
2904 * doesn't do any kind of flipping. Using this on an onscreen surface will
2905 * result in a flipped D3D texture. */
2906 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
)
2908 struct wined3d_device
*device
= surface
->resource
.device
;
2909 const struct wined3d_gl_info
*gl_info
;
2910 struct wined3d_context
*context
;
2912 context
= context_acquire(device
, surface
);
2913 gl_info
= context
->gl_info
;
2914 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
2916 wined3d_texture_prepare_texture(surface
->container
, context
, srgb
);
2917 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
2919 TRACE("Reading back offscreen render target %p.\n", surface
);
2921 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
2922 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
2924 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(surface
));
2925 checkGLcall("glReadBuffer");
2927 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
2928 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
2929 checkGLcall("glCopyTexSubImage2D");
2931 context_release(context
);
2934 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
2938 if (surface
->rb_multisample
)
2941 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
2942 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
2943 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
2944 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
2945 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
2949 if (surface
->rb_resolved
)
2952 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
2953 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
2954 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
2955 surface
->pow2Width
, surface
->pow2Height
);
2956 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
2960 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
2962 if (front
->container
->level_count
!= 1 || front
->container
->layer_count
!= 1
2963 || back
->container
->level_count
!= 1 || back
->container
->layer_count
!= 1)
2964 ERR("Flip between surfaces %p and %p not supported.\n", front
, back
);
2966 /* Flip the surface contents */
2971 front
->hDC
= back
->hDC
;
2975 /* Flip the DIBsection */
2977 HBITMAP tmp
= front
->dib
.DIBsection
;
2978 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
2979 back
->dib
.DIBsection
= tmp
;
2982 /* Flip the surface data */
2986 tmp
= front
->dib
.bitmap_data
;
2987 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
2988 back
->dib
.bitmap_data
= tmp
;
2990 tmp
= front
->resource
.heap_memory
;
2991 front
->resource
.heap_memory
= back
->resource
.heap_memory
;
2992 back
->resource
.heap_memory
= tmp
;
2997 GLuint tmp_pbo
= front
->pbo
;
2998 front
->pbo
= back
->pbo
;
2999 back
->pbo
= tmp_pbo
;
3002 /* Flip the opengl texture */
3006 tmp
= back
->container
->texture_rgb
.name
;
3007 back
->container
->texture_rgb
.name
= front
->container
->texture_rgb
.name
;
3008 front
->container
->texture_rgb
.name
= tmp
;
3010 tmp
= back
->container
->texture_srgb
.name
;
3011 back
->container
->texture_srgb
.name
= front
->container
->texture_srgb
.name
;
3012 front
->container
->texture_srgb
.name
= tmp
;
3014 tmp
= back
->rb_multisample
;
3015 back
->rb_multisample
= front
->rb_multisample
;
3016 front
->rb_multisample
= tmp
;
3018 tmp
= back
->rb_resolved
;
3019 back
->rb_resolved
= front
->rb_resolved
;
3020 front
->rb_resolved
= tmp
;
3022 resource_unload(&back
->resource
);
3023 resource_unload(&front
->resource
);
3027 DWORD tmp_flags
= back
->flags
;
3028 back
->flags
= front
->flags
;
3029 front
->flags
= tmp_flags
;
3031 tmp_flags
= back
->locations
;
3032 back
->locations
= front
->locations
;
3033 front
->locations
= tmp_flags
;
3037 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3038 * pixel copy calls. */
3039 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3040 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3042 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3043 const struct wined3d_gl_info
*gl_info
;
3045 struct wined3d_context
*context
;
3046 BOOL upsidedown
= FALSE
;
3047 RECT dst_rect
= *dst_rect_in
;
3049 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3050 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3052 if(dst_rect
.top
> dst_rect
.bottom
) {
3053 UINT tmp
= dst_rect
.bottom
;
3054 dst_rect
.bottom
= dst_rect
.top
;
3059 context
= context_acquire(device
, src_surface
);
3060 gl_info
= context
->gl_info
;
3061 context_apply_blit_state(context
, device
);
3062 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3064 /* Bind the target texture */
3065 context_bind_texture(context
, dst_surface
->container
->target
, dst_surface
->container
->texture_rgb
.name
);
3066 if (wined3d_resource_is_offscreen(&src_surface
->container
->resource
))
3068 TRACE("Reading from an offscreen target\n");
3069 upsidedown
= !upsidedown
;
3070 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3074 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3076 checkGLcall("glReadBuffer");
3078 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
3079 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
3081 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3083 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3085 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3086 ERR("Texture filtering not supported in direct blit.\n");
3088 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3089 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3091 ERR("Texture filtering not supported in direct blit\n");
3095 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3096 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3098 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3099 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3100 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
3101 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
3102 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3107 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
3108 /* I have to process this row by row to swap the image,
3109 * otherwise it would be upside down, so stretching in y direction
3110 * doesn't cost extra time
3112 * However, stretching in x direction can be avoided if not necessary
3114 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
3115 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3117 /* Well, that stuff works, but it's very slow.
3118 * find a better way instead
3122 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
3124 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3125 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
3126 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
3131 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3132 dst_rect
.left
/* x offset */, row
/* y offset */,
3133 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
3137 checkGLcall("glCopyTexSubImage2D");
3139 context_release(context
);
3141 /* The texture is now most up to date - If the surface is a render target
3142 * and has a drawable, this path is never entered. */
3143 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3144 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3147 /* Uses the hardware to stretch and flip the image */
3148 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3149 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3151 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3152 GLuint src
, backup
= 0;
3153 float left
, right
, top
, bottom
; /* Texture coordinates */
3154 UINT fbwidth
= src_surface
->resource
.width
;
3155 UINT fbheight
= src_surface
->resource
.height
;
3156 const struct wined3d_gl_info
*gl_info
;
3157 struct wined3d_context
*context
;
3158 GLenum drawBuffer
= GL_BACK
;
3159 GLenum texture_target
;
3160 BOOL noBackBufferBackup
;
3162 BOOL upsidedown
= FALSE
;
3163 RECT dst_rect
= *dst_rect_in
;
3165 TRACE("Using hwstretch blit\n");
3166 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3167 context
= context_acquire(device
, src_surface
);
3168 gl_info
= context
->gl_info
;
3169 context_apply_blit_state(context
, device
);
3170 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3172 src_offscreen
= wined3d_resource_is_offscreen(&src_surface
->container
->resource
);
3173 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
3174 if (!noBackBufferBackup
&& !src_surface
->container
->texture_rgb
.name
)
3176 /* Get it a description */
3177 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3180 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3181 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3183 if (context
->aux_buffers
>= 2)
3185 /* Got more than one aux buffer? Use the 2nd aux buffer */
3186 drawBuffer
= GL_AUX1
;
3188 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
3190 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3191 drawBuffer
= GL_AUX0
;
3194 if (noBackBufferBackup
)
3196 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
3197 checkGLcall("glGenTextures");
3198 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3199 texture_target
= GL_TEXTURE_2D
;
3203 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3204 * we are reading from the back buffer, the backup can be used as source texture
3206 texture_target
= src_surface
->texture_target
;
3207 context_bind_texture(context
, texture_target
, src_surface
->container
->texture_rgb
.name
);
3208 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
3209 checkGLcall("glEnable(texture_target)");
3211 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3212 src_surface
->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
3215 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3216 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3218 if(dst_rect
.top
> dst_rect
.bottom
) {
3219 UINT tmp
= dst_rect
.bottom
;
3220 dst_rect
.bottom
= dst_rect
.top
;
3227 TRACE("Reading from an offscreen target\n");
3228 upsidedown
= !upsidedown
;
3229 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3233 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3236 /* TODO: Only back up the part that will be overwritten */
3237 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3239 checkGLcall("glCopyTexSubImage2D");
3241 /* No issue with overriding these - the sampler is dirty due to blit usage */
3242 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
3243 wined3d_gl_mag_filter(magLookup
, filter
));
3244 checkGLcall("glTexParameteri");
3245 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
3246 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
3247 checkGLcall("glTexParameteri");
3249 if (!src_surface
->container
->swapchain
3250 || src_surface
->container
== src_surface
->container
->swapchain
->back_buffers
[0])
3252 src
= backup
? backup
: src_surface
->container
->texture_rgb
.name
;
3256 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
3257 checkGLcall("glReadBuffer(GL_FRONT)");
3259 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
3260 checkGLcall("glGenTextures(1, &src)");
3261 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
3263 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3264 * out for power of 2 sizes
3266 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
3267 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
3268 checkGLcall("glTexImage2D");
3269 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3271 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3272 checkGLcall("glTexParameteri");
3273 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3274 checkGLcall("glTexParameteri");
3276 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
3277 checkGLcall("glReadBuffer(GL_BACK)");
3279 if (texture_target
!= GL_TEXTURE_2D
)
3281 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3282 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3283 texture_target
= GL_TEXTURE_2D
;
3286 checkGLcall("glEnd and previous");
3288 left
= src_rect
->left
;
3289 right
= src_rect
->right
;
3293 top
= src_surface
->resource
.height
- src_rect
->top
;
3294 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
3298 top
= src_surface
->resource
.height
- src_rect
->bottom
;
3299 bottom
= src_surface
->resource
.height
- src_rect
->top
;
3302 if (src_surface
->container
->flags
& WINED3D_TEXTURE_NORMALIZED_COORDS
)
3304 left
/= src_surface
->pow2Width
;
3305 right
/= src_surface
->pow2Width
;
3306 top
/= src_surface
->pow2Height
;
3307 bottom
/= src_surface
->pow2Height
;
3310 /* draw the source texture stretched and upside down. The correct surface is bound already */
3311 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
3312 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
3314 context_set_draw_buffer(context
, drawBuffer
);
3315 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
3317 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3319 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
3320 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3323 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
3324 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
3327 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
3328 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3331 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
3332 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
3333 gl_info
->gl_ops
.gl
.p_glEnd();
3334 checkGLcall("glEnd and previous");
3336 if (texture_target
!= dst_surface
->texture_target
)
3338 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3339 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
3340 texture_target
= dst_surface
->texture_target
;
3343 /* Now read the stretched and upside down image into the destination texture */
3344 context_bind_texture(context
, texture_target
, dst_surface
->container
->texture_rgb
.name
);
3345 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
3347 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
3348 0, 0, /* We blitted the image to the origin */
3349 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3350 checkGLcall("glCopyTexSubImage2D");
3352 if (drawBuffer
== GL_BACK
)
3354 /* Write the back buffer backup back. */
3357 if (texture_target
!= GL_TEXTURE_2D
)
3359 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3360 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3361 texture_target
= GL_TEXTURE_2D
;
3363 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3367 if (texture_target
!= src_surface
->texture_target
)
3369 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3370 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
3371 texture_target
= src_surface
->texture_target
;
3373 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->container
->texture_rgb
.name
);
3376 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3378 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
3379 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
3382 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
3383 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3386 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
3387 (float)fbheight
/ (float)src_surface
->pow2Height
);
3388 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
3391 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
3392 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
3393 gl_info
->gl_ops
.gl
.p_glEnd();
3395 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3396 checkGLcall("glDisable(texture_target)");
3399 if (src
!= src_surface
->container
->texture_rgb
.name
&& src
!= backup
)
3401 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
3402 checkGLcall("glDeleteTextures(1, &src)");
3406 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
3407 checkGLcall("glDeleteTextures(1, &backup)");
3410 if (wined3d_settings
.strict_draw_ordering
)
3411 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3413 context_release(context
);
3415 /* The texture is now most up to date - If the surface is a render target
3416 * and has a drawable, this path is never entered. */
3417 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3418 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3421 /* Front buffer coordinates are always full screen coordinates, but our GL
3422 * drawable is limited to the window's client area. The sysmem and texture
3423 * copies do have the full screen size. Note that GL has a bottom-left
3424 * origin, while D3D has a top-left origin. */
3425 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
3427 UINT drawable_height
;
3429 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
3431 POINT offset
= {0, 0};
3434 ScreenToClient(window
, &offset
);
3435 OffsetRect(rect
, offset
.x
, offset
.y
);
3437 GetClientRect(window
, &windowsize
);
3438 drawable_height
= windowsize
.bottom
- windowsize
.top
;
3442 drawable_height
= surface
->resource
.height
;
3445 rect
->top
= drawable_height
- rect
->top
;
3446 rect
->bottom
= drawable_height
- rect
->bottom
;
3449 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
3450 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
3451 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
3452 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
3454 const struct wined3d_gl_info
*gl_info
;
3455 struct wined3d_context
*context
;
3456 RECT src_rect
, dst_rect
;
3458 src_rect
= *src_rect_in
;
3459 dst_rect
= *dst_rect_in
;
3461 context
= context_acquire(device
, dst_surface
);
3462 gl_info
= context
->gl_info
;
3464 /* Make sure the surface is up-to-date. This should probably use
3465 * surface_load_location() and worry about the destination surface too,
3466 * unless we're overwriting it completely. */
3467 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3469 /* Activate the destination context, set it up for blitting */
3470 context_apply_blit_state(context
, device
);
3472 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
3473 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
3475 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
3479 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
3480 checkGLcall("glEnable(GL_ALPHA_TEST)");
3482 /* For P8 surfaces, the alpha component contains the palette index.
3483 * Which means that the colorkey is one of the palette entries. In
3484 * other cases pixels that should be masked away have alpha set to 0. */
3485 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3486 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
3487 (float)src_surface
->container
->src_blt_color_key
.color_space_low_value
/ 256.0f
);
3489 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
3490 checkGLcall("glAlphaFunc");
3494 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3495 checkGLcall("glDisable(GL_ALPHA_TEST)");
3498 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
3502 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3503 checkGLcall("glDisable(GL_ALPHA_TEST)");
3506 /* Leave the opengl state valid for blitting */
3507 device
->blitter
->unset_shader(context
->gl_info
);
3509 if (wined3d_settings
.strict_draw_ordering
3510 || (dst_surface
->container
->swapchain
3511 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
3512 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3514 context_release(context
);
3517 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
3519 struct wined3d_device
*device
= s
->resource
.device
;
3520 const struct blit_shader
*blitter
;
3522 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
3523 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
3526 FIXME("No blitter is capable of performing the requested color fill operation.\n");
3527 return WINED3DERR_INVALIDCALL
;
3530 return blitter
->color_fill(device
, s
, rect
, color
);
3533 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3534 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
3535 enum wined3d_texture_filter_type filter
)
3537 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3538 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->fb
.render_targets
[0]);
3539 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
3540 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
3542 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
3543 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
3544 flags
, DDBltFx
, debug_d3dtexturefiltertype(filter
));
3546 /* Get the swapchain. One of the surfaces has to be a primary surface */
3547 if (dst_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3549 WARN("Destination is in sysmem, rejecting gl blt\n");
3550 return WINED3DERR_INVALIDCALL
;
3553 dst_swapchain
= dst_surface
->container
->swapchain
;
3557 if (src_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3559 WARN("Src is in sysmem, rejecting gl blt\n");
3560 return WINED3DERR_INVALIDCALL
;
3563 src_swapchain
= src_surface
->container
->swapchain
;
3567 src_swapchain
= NULL
;
3570 /* Early sort out of cases where no render target is used */
3571 if (!dst_swapchain
&& !src_swapchain
&& src_surface
!= rt
&& dst_surface
!= rt
)
3573 TRACE("No surface is render target, not using hardware blit.\n");
3574 return WINED3DERR_INVALIDCALL
;
3577 /* No destination color keying supported */
3578 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
3580 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3581 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3582 return WINED3DERR_INVALIDCALL
;
3585 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
3587 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3588 return WINED3DERR_INVALIDCALL
;
3591 if (dst_swapchain
&& src_swapchain
)
3593 FIXME("Implement hardware blit between two different swapchains\n");
3594 return WINED3DERR_INVALIDCALL
;
3599 /* Handled with regular texture -> swapchain blit */
3600 if (src_surface
== rt
)
3601 TRACE("Blit from active render target to a swapchain\n");
3603 else if (src_swapchain
&& dst_surface
== rt
)
3605 FIXME("Implement blit from a swapchain to the active render target\n");
3606 return WINED3DERR_INVALIDCALL
;
3609 if ((src_swapchain
|| src_surface
== rt
) && !dst_swapchain
)
3611 /* Blit from render target to texture */
3614 /* P8 read back is not implemented */
3615 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3616 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3618 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3619 return WINED3DERR_INVALIDCALL
;
3622 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
3624 TRACE("Color keying not supported by frame buffer to texture blit\n");
3625 return WINED3DERR_INVALIDCALL
;
3626 /* Destination color key is checked above */
3629 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
3634 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3635 * flip the image nor scale it.
3637 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3638 * -> If the app wants an image width an unscaled width, copy it line per line
3639 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
3640 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3641 * back buffer. This is slower than reading line per line, thus not used for flipping
3642 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3643 * pixel by pixel. */
3644 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
3645 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
3647 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
3648 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
3652 TRACE("Using hardware stretching to flip / stretch the texture.\n");
3653 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
3656 surface_evict_sysmem(dst_surface
);
3660 else if (src_surface
)
3662 /* Blit from offscreen surface to render target */
3663 struct wined3d_color_key old_blt_key
= src_surface
->container
->src_blt_color_key
;
3664 DWORD old_color_key_flags
= src_surface
->container
->color_key_flags
;
3666 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
3668 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
3669 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
3670 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
3672 FIXME("Unsupported blit operation falling back to software\n");
3673 return WINED3DERR_INVALIDCALL
;
3676 /* Color keying: Check if we have to do a color keyed blt,
3677 * and if not check if a color key is activated.
3679 * Just modify the color keying parameters in the surface and restore them afterwards
3680 * The surface keeps track of the color key last used to load the opengl surface.
3681 * PreLoad will catch the change to the flags and color key and reload if necessary.
3683 if (flags
& WINEDDBLT_KEYSRC
)
3685 /* Use color key from surface */
3687 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
3689 /* Use color key from DDBltFx */
3690 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
, &DDBltFx
->ddckSrcColorkey
);
3694 /* Do not use color key */
3695 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
, NULL
);
3698 surface_blt_to_drawable(device
, filter
,
3699 flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_ALPHATEST
),
3700 src_surface
, src_rect
, dst_surface
, dst_rect
);
3702 /* Restore the color key parameters */
3703 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
,
3704 (old_color_key_flags
& WINEDDSD_CKSRCBLT
) ? &old_blt_key
: NULL
);
3706 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
3707 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
3712 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3713 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3714 return WINED3DERR_INVALIDCALL
;
3717 /* Context activation is done by the caller. */
3718 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
3719 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
3721 struct wined3d_device
*device
= surface
->resource
.device
;
3722 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
3723 GLint compare_mode
= GL_NONE
;
3724 struct blt_info info
;
3725 GLint old_binding
= 0;
3728 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
3730 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
3731 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
3732 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3733 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
3734 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
3735 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
3736 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
3737 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
3738 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
3739 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
3740 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
3742 SetRect(&rect
, 0, h
, w
, 0);
3743 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
3744 context_active_texture(context
, context
->gl_info
, 0);
3745 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
3746 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
3747 if (gl_info
->supported
[ARB_SHADOW
])
3749 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
3750 if (compare_mode
!= GL_NONE
)
3751 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
3754 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
3755 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
3757 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
3758 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
3759 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
3760 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
3761 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
3762 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
3763 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
3764 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
3765 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
3766 gl_info
->gl_ops
.gl
.p_glEnd();
3768 if (compare_mode
!= GL_NONE
)
3769 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
3770 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
3772 gl_info
->gl_ops
.gl
.p_glPopAttrib();
3774 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
3777 void surface_modify_ds_location(struct wined3d_surface
*surface
,
3778 DWORD location
, UINT w
, UINT h
)
3780 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
3782 if (((surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
3783 || (!(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
3784 wined3d_texture_set_dirty(surface
->container
);
3786 surface
->ds_current_size
.cx
= w
;
3787 surface
->ds_current_size
.cy
= h
;
3788 surface
->locations
= location
;
3791 /* Context activation is done by the caller. */
3792 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
3794 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
3795 struct wined3d_device
*device
= surface
->resource
.device
;
3798 TRACE("surface %p, new location %#x.\n", surface
, location
);
3800 /* TODO: Make this work for modes other than FBO */
3801 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
3803 if (!(surface
->locations
& location
))
3805 w
= surface
->ds_current_size
.cx
;
3806 h
= surface
->ds_current_size
.cy
;
3807 surface
->ds_current_size
.cx
= 0;
3808 surface
->ds_current_size
.cy
= 0;
3812 w
= surface
->resource
.width
;
3813 h
= surface
->resource
.height
;
3816 if (surface
->ds_current_size
.cx
== surface
->resource
.width
3817 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
3819 TRACE("Location (%#x) is already up to date.\n", location
);
3823 if (surface
->current_renderbuffer
)
3825 FIXME("Not supported with fixed up depth stencil.\n");
3829 if (surface
->locations
& WINED3D_LOCATION_DISCARDED
)
3831 TRACE("Surface was discarded, no need copy data.\n");
3834 case WINED3D_LOCATION_TEXTURE_RGB
:
3835 wined3d_texture_prepare_texture(surface
->container
, context
, FALSE
);
3837 case WINED3D_LOCATION_RB_MULTISAMPLE
:
3838 surface_prepare_rb(surface
, gl_info
, TRUE
);
3840 case WINED3D_LOCATION_DRAWABLE
:
3844 FIXME("Unhandled location %#x\n", location
);
3846 surface
->locations
&= ~WINED3D_LOCATION_DISCARDED
;
3847 surface
->locations
|= location
;
3848 surface
->ds_current_size
.cx
= surface
->resource
.width
;
3849 surface
->ds_current_size
.cy
= surface
->resource
.height
;
3853 if (!surface
->locations
)
3855 FIXME("No up to date depth stencil location.\n");
3856 surface
->locations
|= location
;
3857 surface
->ds_current_size
.cx
= surface
->resource
.width
;
3858 surface
->ds_current_size
.cy
= surface
->resource
.height
;
3862 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
3864 GLint old_binding
= 0;
3867 /* The render target is allowed to be smaller than the depth/stencil
3868 * buffer, so the onscreen depth/stencil buffer is potentially smaller
3869 * than the offscreen surface. Don't overwrite the offscreen surface
3870 * with undefined data. */
3871 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
3872 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
3874 TRACE("Copying onscreen depth buffer to depth texture.\n");
3876 if (!device
->depth_blt_texture
)
3877 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
3879 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
3880 * directly on the FBO texture. That's because we need to flip. */
3881 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
3882 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
3883 NULL
, WINED3D_LOCATION_DRAWABLE
);
3884 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
3886 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
3887 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
3891 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
3892 bind_target
= GL_TEXTURE_2D
;
3894 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
3895 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
3896 * internal format, because the internal format might include stencil
3897 * data. In principle we should copy stencil data as well, but unless
3898 * the driver supports stencil export it's hard to do, and doesn't
3899 * seem to be needed in practice. If the hardware doesn't support
3900 * writing stencil data, the glCopyTexImage2D() call might trigger
3901 * software fallbacks. */
3902 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
3903 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3904 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3905 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
3906 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
3907 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
3908 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
3909 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
3911 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
3912 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3913 context_set_draw_buffer(context
, GL_NONE
);
3915 /* Do the actual blit */
3916 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
3917 checkGLcall("depth_blt");
3919 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
3921 if (wined3d_settings
.strict_draw_ordering
)
3922 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3924 else if (location
== WINED3D_LOCATION_DRAWABLE
)
3926 TRACE("Copying depth texture to onscreen depth buffer.\n");
3928 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
3929 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
3930 NULL
, WINED3D_LOCATION_DRAWABLE
);
3931 surface_depth_blt(surface
, context
, surface
->container
->texture_rgb
.name
,
3932 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
3933 checkGLcall("depth_blt");
3935 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
3937 if (wined3d_settings
.strict_draw_ordering
)
3938 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3942 ERR("Invalid location (%#x) specified.\n", location
);
3945 surface
->locations
|= location
;
3946 surface
->ds_current_size
.cx
= surface
->resource
.width
;
3947 surface
->ds_current_size
.cy
= surface
->resource
.height
;
3950 void surface_validate_location(struct wined3d_surface
*surface
, DWORD location
)
3952 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
3954 surface
->locations
|= location
;
3957 void surface_invalidate_location(struct wined3d_surface
*surface
, DWORD location
)
3959 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
3961 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
3962 wined3d_texture_set_dirty(surface
->container
);
3963 surface
->locations
&= ~location
;
3965 if (!surface
->locations
)
3966 ERR("Surface %p does not have any up to date location.\n", surface
);
3969 static DWORD
resource_access_from_location(DWORD location
)
3973 case WINED3D_LOCATION_SYSMEM
:
3974 case WINED3D_LOCATION_USER_MEMORY
:
3975 case WINED3D_LOCATION_DIB
:
3976 case WINED3D_LOCATION_BUFFER
:
3977 return WINED3D_RESOURCE_ACCESS_CPU
;
3979 case WINED3D_LOCATION_DRAWABLE
:
3980 case WINED3D_LOCATION_TEXTURE_SRGB
:
3981 case WINED3D_LOCATION_TEXTURE_RGB
:
3982 case WINED3D_LOCATION_RB_MULTISAMPLE
:
3983 case WINED3D_LOCATION_RB_RESOLVED
:
3984 return WINED3D_RESOURCE_ACCESS_GPU
;
3987 FIXME("Unhandled location %#x.\n", location
);
3992 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
3994 struct wined3d_device
*device
= surface
->resource
.device
;
3995 struct wined3d_context
*context
;
3996 const struct wined3d_gl_info
*gl_info
;
3997 struct wined3d_bo_address dst
, src
;
3998 UINT size
= surface
->resource
.size
;
4000 surface_get_memory(surface
, &dst
, location
);
4001 surface_get_memory(surface
, &src
, surface
->locations
);
4003 if (dst
.buffer_object
)
4005 context
= context_acquire(device
, NULL
);
4006 gl_info
= context
->gl_info
;
4007 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, dst
.buffer_object
));
4008 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER
, 0, size
, src
.addr
));
4009 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
4010 checkGLcall("Upload PBO");
4011 context_release(context
);
4014 if (src
.buffer_object
)
4016 context
= context_acquire(device
, NULL
);
4017 gl_info
= context
->gl_info
;
4018 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, src
.buffer_object
));
4019 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER
, 0, size
, dst
.addr
));
4020 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
4021 checkGLcall("Download PBO");
4022 context_release(context
);
4025 memcpy(dst
.addr
, src
.addr
, size
);
4028 static void surface_load_sysmem(struct wined3d_surface
*surface
,
4029 const struct wined3d_gl_info
*gl_info
, DWORD dst_location
)
4031 if (surface
->locations
& surface_simple_locations
)
4033 surface_copy_simple_location(surface
, dst_location
);
4037 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
4038 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4040 /* Download the surface to system memory. */
4041 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4043 struct wined3d_device
*device
= surface
->resource
.device
;
4044 struct wined3d_context
*context
;
4046 /* TODO: Use already acquired context when possible. */
4047 context
= context_acquire(device
, NULL
);
4049 wined3d_texture_bind_and_dirtify(surface
->container
, context
,
4050 !(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
4051 surface_download_data(surface
, gl_info
, dst_location
);
4053 context_release(context
);
4058 if (surface
->locations
& WINED3D_LOCATION_DRAWABLE
)
4060 read_from_framebuffer(surface
, dst_location
);
4064 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4065 surface
, wined3d_debug_location(surface
->locations
));
4068 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
4069 const struct wined3d_gl_info
*gl_info
)
4073 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
4074 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
4076 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4077 return WINED3DERR_INVALIDCALL
;
4080 surface_get_rect(surface
, NULL
, &r
);
4081 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4082 surface_blt_to_drawable(surface
->resource
.device
,
4083 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
4088 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
4089 const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
4091 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4092 struct wined3d_device
*device
= surface
->resource
.device
;
4093 const struct wined3d_color_key_conversion
*conversion
;
4094 struct wined3d_texture
*texture
= surface
->container
;
4095 struct wined3d_context
*context
;
4096 UINT width
, src_pitch
, dst_pitch
;
4097 struct wined3d_bo_address data
;
4098 struct wined3d_format format
;
4099 POINT dst_point
= {0, 0};
4102 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
4103 && wined3d_resource_is_offscreen(&texture
->resource
)
4104 && (surface
->locations
& WINED3D_LOCATION_DRAWABLE
))
4106 surface_load_fb_texture(surface
, srgb
);
4111 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
4112 && (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
4113 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4114 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4115 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4118 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
4119 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
4121 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
4122 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
4127 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
4128 && (!srgb
|| (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
4129 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4130 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4131 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4133 DWORD src_location
= surface
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
4134 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
4135 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
4136 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4138 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, src_location
,
4139 &rect
, surface
, dst_location
, &rect
);
4144 /* Upload from system memory */
4148 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->resource
.map_binding
))
4149 == WINED3D_LOCATION_TEXTURE_RGB
)
4151 /* Performance warning... */
4152 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
4153 surface_prepare_map_memory(surface
);
4154 surface_load_location(surface
, surface
->resource
.map_binding
);
4159 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->resource
.map_binding
))
4160 == WINED3D_LOCATION_TEXTURE_SRGB
)
4162 /* Performance warning... */
4163 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
4164 surface_prepare_map_memory(surface
);
4165 surface_load_location(surface
, surface
->resource
.map_binding
);
4169 if (!(surface
->locations
& surface_simple_locations
))
4171 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4172 /* Lets hope we get it from somewhere... */
4173 surface_prepare_system_memory(surface
);
4174 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
4177 /* TODO: Use already acquired context when possible. */
4178 context
= context_acquire(device
, NULL
);
4180 wined3d_texture_prepare_texture(texture
, context
, srgb
);
4181 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
4183 if (texture
->color_key_flags
& WINEDDSD_CKSRCBLT
)
4185 surface
->flags
|= SFLAG_GLCKEY
;
4186 surface
->gl_color_key
= texture
->src_blt_color_key
;
4188 else surface
->flags
&= ~SFLAG_GLCKEY
;
4190 width
= surface
->resource
.width
;
4191 src_pitch
= wined3d_surface_get_pitch(surface
);
4193 format
= *texture
->resource
.format
;
4194 if ((conversion
= wined3d_format_get_color_key_conversion(texture
, TRUE
)))
4195 format
= *wined3d_get_format(gl_info
, conversion
->dst_format
);
4197 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4198 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
4199 * getting called. */
4200 if ((format
.convert
|| conversion
) && surface
->pbo
)
4202 TRACE("Removing the pbo attached to surface %p.\n", surface
);
4204 if (surface
->flags
& SFLAG_DIBSECTION
)
4205 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
4207 surface
->resource
.map_binding
= WINED3D_LOCATION_SYSMEM
;
4209 surface_prepare_map_memory(surface
);
4210 surface_load_location(surface
, surface
->resource
.map_binding
);
4211 surface_remove_pbo(surface
, gl_info
);
4214 surface_get_memory(surface
, &data
, surface
->locations
);
4217 /* This code is entered for texture formats which need a fixup. */
4218 UINT height
= surface
->resource
.height
;
4220 format
.byte_count
= format
.conv_byte_count
;
4221 dst_pitch
= wined3d_format_calculate_pitch(&format
, width
);
4222 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4224 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4226 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4227 context_release(context
);
4228 return E_OUTOFMEMORY
;
4230 format
.convert(data
.addr
, mem
, src_pitch
, src_pitch
* height
,
4231 dst_pitch
, dst_pitch
* height
, width
, height
, 1);
4232 src_pitch
= dst_pitch
;
4235 else if (conversion
)
4237 /* This code is only entered for color keying fixups */
4238 struct wined3d_palette
*palette
= NULL
;
4239 UINT height
= surface
->resource
.height
;
4241 dst_pitch
= wined3d_format_calculate_pitch(&format
, width
);
4242 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4244 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4246 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4247 context_release(context
);
4248 return E_OUTOFMEMORY
;
4250 if (texture
->swapchain
&& texture
->swapchain
->palette
)
4251 palette
= texture
->swapchain
->palette
;
4252 conversion
->convert(data
.addr
, src_pitch
, mem
, dst_pitch
,
4253 width
, height
, palette
, &texture
->src_blt_color_key
);
4254 src_pitch
= dst_pitch
;
4258 wined3d_surface_upload_data(surface
, gl_info
, &format
, &src_rect
,
4259 src_pitch
, &dst_point
, srgb
, wined3d_const_bo_address(&data
));
4261 context_release(context
);
4263 HeapFree(GetProcessHeap(), 0, mem
);
4268 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
4270 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4272 if (!(surface
->locations
& WINED3D_LOCATION_RB_MULTISAMPLE
))
4273 ERR("Trying to resolve multisampled surface %p, but location WINED3D_LOCATION_RB_MULTISAMPLE not current.\n",
4276 surface_blt_fbo(surface
->resource
.device
, WINED3D_TEXF_POINT
,
4277 surface
, WINED3D_LOCATION_RB_MULTISAMPLE
, &rect
, surface
, WINED3D_LOCATION_RB_RESOLVED
, &rect
);
4280 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
)
4282 struct wined3d_device
*device
= surface
->resource
.device
;
4283 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4286 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4288 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
4290 if (location
== WINED3D_LOCATION_TEXTURE_RGB
4291 && surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_DISCARDED
))
4293 struct wined3d_context
*context
= context_acquire(device
, NULL
);
4294 surface_load_ds_location(surface
, context
, location
);
4295 context_release(context
);
4298 else if (location
& surface
->locations
4299 && surface
->container
->resource
.draw_binding
!= WINED3D_LOCATION_DRAWABLE
)
4301 /* Already up to date, nothing to do. */
4306 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4307 wined3d_debug_location(surface
->locations
), wined3d_debug_location(location
));
4308 return WINED3DERR_INVALIDCALL
;
4312 if (surface
->locations
& location
)
4314 TRACE("Location already up to date.\n");
4318 if (WARN_ON(d3d_surface
))
4320 DWORD required_access
= resource_access_from_location(location
);
4321 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
4322 WARN("Operation requires %#x access, but surface only has %#x.\n",
4323 required_access
, surface
->resource
.access_flags
);
4326 if (!surface
->locations
)
4328 ERR("Surface %p does not have any up to date location.\n", surface
);
4329 surface
->flags
|= SFLAG_LOST
;
4330 return WINED3DERR_DEVICELOST
;
4335 case WINED3D_LOCATION_DIB
:
4336 case WINED3D_LOCATION_USER_MEMORY
:
4337 case WINED3D_LOCATION_SYSMEM
:
4338 case WINED3D_LOCATION_BUFFER
:
4339 surface_load_sysmem(surface
, gl_info
, location
);
4342 case WINED3D_LOCATION_DRAWABLE
:
4343 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
)))
4347 case WINED3D_LOCATION_RB_RESOLVED
:
4348 surface_multisample_resolve(surface
);
4351 case WINED3D_LOCATION_TEXTURE_RGB
:
4352 case WINED3D_LOCATION_TEXTURE_SRGB
:
4353 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
4358 ERR("Don't know how to handle location %#x.\n", location
);
4362 surface_validate_location(surface
, location
);
4364 if (location
!= WINED3D_LOCATION_SYSMEM
&& (surface
->locations
& WINED3D_LOCATION_SYSMEM
))
4365 surface_evict_sysmem(surface
);
4370 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
4371 /* Context activation is done by the caller. */
4372 static void ffp_blit_free(struct wined3d_device
*device
) { }
4374 /* Context activation is done by the caller. */
4375 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4377 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4379 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
4380 checkGLcall("glEnable(target)");
4385 /* Context activation is done by the caller. */
4386 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
4388 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
4389 checkGLcall("glDisable(GL_TEXTURE_2D)");
4390 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
4392 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
4393 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4395 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
4397 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
4398 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4402 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4403 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4404 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4408 case WINED3D_BLIT_OP_COLOR_BLIT
:
4409 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4412 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
4414 TRACE("Checking support for fixup:\n");
4415 dump_color_fixup_desc(src_format
->color_fixup
);
4418 /* We only support identity conversions. */
4419 if (!is_identity_fixup(src_format
->color_fixup
)
4420 || !is_identity_fixup(dst_format
->color_fixup
))
4422 TRACE("Fixups are not supported.\n");
4428 case WINED3D_BLIT_OP_COLOR_FILL
:
4429 if (dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4432 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
4434 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
4437 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
4439 TRACE("Color fill not supported\n");
4443 /* FIXME: We should reject color fills on formats with fixups,
4444 * but this would break P8 color fills for example. */
4448 case WINED3D_BLIT_OP_DEPTH_FILL
:
4452 TRACE("Unsupported blit_op=%d\n", blit_op
);
4457 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4458 const RECT
*dst_rect
, const struct wined3d_color
*color
)
4460 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4461 struct wined3d_rendertarget_view
*view
;
4462 struct wined3d_fb_state fb
= {&view
, NULL
};
4465 if (FAILED(hr
= wined3d_rendertarget_view_create_from_surface(dst_surface
,
4466 NULL
, &wined3d_null_parent_ops
, &view
)))
4468 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
4472 device_clear_render_targets(device
, 1, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
4473 wined3d_rendertarget_view_decref(view
);
4478 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4479 const RECT
*dst_rect
, float depth
)
4481 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4482 struct wined3d_fb_state fb
= {NULL
, NULL
};
4485 if (FAILED(hr
= wined3d_rendertarget_view_create_from_surface(dst_surface
,
4486 NULL
, &wined3d_null_parent_ops
, &fb
.depth_stencil
)))
4488 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
4492 device_clear_render_targets(device
, 0, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
4493 wined3d_rendertarget_view_decref(fb
.depth_stencil
);
4498 const struct blit_shader ffp_blit
= {
4504 ffp_blit_color_fill
,
4505 ffp_blit_depth_fill
,
4508 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
4513 /* Context activation is done by the caller. */
4514 static void cpu_blit_free(struct wined3d_device
*device
)
4518 /* Context activation is done by the caller. */
4519 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4524 /* Context activation is done by the caller. */
4525 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
4529 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4530 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4531 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4533 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
4541 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
4542 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
4543 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
4545 UINT row_block_count
;
4546 const BYTE
*src_row
;
4553 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
4557 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4559 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
4560 src_row
+= src_pitch
;
4561 dst_row
+= dst_pitch
;
4567 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
4569 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
4573 case WINED3DFMT_DXT1
:
4574 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4579 BYTE control_row
[4];
4582 const struct block
*s
= (const struct block
*)src_row
;
4583 struct block
*d
= (struct block
*)dst_row
;
4585 for (x
= 0; x
< row_block_count
; ++x
)
4587 d
[x
].color
[0] = s
[x
].color
[0];
4588 d
[x
].color
[1] = s
[x
].color
[1];
4589 d
[x
].control_row
[0] = s
[x
].control_row
[3];
4590 d
[x
].control_row
[1] = s
[x
].control_row
[2];
4591 d
[x
].control_row
[2] = s
[x
].control_row
[1];
4592 d
[x
].control_row
[3] = s
[x
].control_row
[0];
4594 src_row
-= src_pitch
;
4595 dst_row
+= dst_pitch
;
4599 case WINED3DFMT_DXT2
:
4600 case WINED3DFMT_DXT3
:
4601 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4607 BYTE control_row
[4];
4610 const struct block
*s
= (const struct block
*)src_row
;
4611 struct block
*d
= (struct block
*)dst_row
;
4613 for (x
= 0; x
< row_block_count
; ++x
)
4615 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
4616 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
4617 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
4618 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
4619 d
[x
].color
[0] = s
[x
].color
[0];
4620 d
[x
].color
[1] = s
[x
].color
[1];
4621 d
[x
].control_row
[0] = s
[x
].control_row
[3];
4622 d
[x
].control_row
[1] = s
[x
].control_row
[2];
4623 d
[x
].control_row
[2] = s
[x
].control_row
[1];
4624 d
[x
].control_row
[3] = s
[x
].control_row
[0];
4626 src_row
-= src_pitch
;
4627 dst_row
+= dst_pitch
;
4632 FIXME("Compressed flip not implemented for format %s.\n",
4633 debug_d3dformat(format
->id
));
4638 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
4639 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
4644 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4645 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
4646 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
4648 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
4649 const struct wined3d_format
*src_format
, *dst_format
;
4650 struct wined3d_texture
*src_texture
= NULL
;
4651 struct wined3d_map_desc dst_map
, src_map
;
4652 const BYTE
*sbase
= NULL
;
4653 HRESULT hr
= WINED3D_OK
;
4658 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4659 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
4660 flags
, fx
, debug_d3dtexturefiltertype(filter
));
4662 if (src_surface
== dst_surface
)
4664 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
4666 src_format
= dst_surface
->resource
.format
;
4667 dst_format
= src_format
;
4671 dst_format
= dst_surface
->resource
.format
;
4674 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
4676 if (!(src_texture
= surface_convert_format(src_surface
, dst_format
->id
)))
4678 /* The conv function writes a FIXME */
4679 WARN("Cannot convert source surface format to dest format.\n");
4682 src_surface
= surface_from_resource(wined3d_texture_get_sub_resource(src_texture
, 0));
4684 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
4685 src_format
= src_surface
->resource
.format
;
4689 src_format
= dst_format
;
4692 wined3d_surface_map(dst_surface
, &dst_map
, dst_rect
, 0);
4695 bpp
= dst_surface
->resource
.format
->byte_count
;
4696 srcheight
= src_rect
->bottom
- src_rect
->top
;
4697 srcwidth
= src_rect
->right
- src_rect
->left
;
4698 dstheight
= dst_rect
->bottom
- dst_rect
->top
;
4699 dstwidth
= dst_rect
->right
- dst_rect
->left
;
4700 width
= (dst_rect
->right
- dst_rect
->left
) * bpp
;
4703 sbase
= (BYTE
*)src_map
.data
4704 + ((src_rect
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
4705 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
4706 if (src_surface
!= dst_surface
)
4707 dbuf
= dst_map
.data
;
4709 dbuf
= (BYTE
*)dst_map
.data
4710 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
4711 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
4713 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
4715 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
4717 if (src_surface
== dst_surface
)
4719 FIXME("Only plain blits supported on compressed surfaces.\n");
4724 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
4726 WARN("Stretching not supported on compressed surfaces.\n");
4727 hr
= WINED3DERR_INVALIDCALL
;
4731 if (!surface_check_block_align(src_surface
, src_rect
))
4733 WARN("Source rectangle not block-aligned.\n");
4734 hr
= WINED3DERR_INVALIDCALL
;
4738 if (!surface_check_block_align(dst_surface
, dst_rect
))
4740 WARN("Destination rectangle not block-aligned.\n");
4741 hr
= WINED3DERR_INVALIDCALL
;
4745 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
4746 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
4747 src_format
, flags
, fx
);
4751 /* First, all the 'source-less' blits */
4752 if (flags
& WINEDDBLT_COLORFILL
)
4754 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->u5
.dwFillColor
);
4755 flags
&= ~WINEDDBLT_COLORFILL
;
4758 if (flags
& WINEDDBLT_DEPTHFILL
)
4760 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
4762 if (flags
& WINEDDBLT_ROP
)
4764 /* Catch some degenerate cases here. */
4768 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, 0);
4770 case 0xaa0029: /* No-op */
4773 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, ~0U);
4775 case SRCCOPY
: /* Well, we do that below? */
4778 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
4781 flags
&= ~WINEDDBLT_ROP
;
4783 if (flags
& WINEDDBLT_DDROPS
)
4785 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
4787 /* Now the 'with source' blits. */
4790 int sx
, xinc
, sy
, yinc
;
4792 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
4795 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
4796 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
4798 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
4799 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
4802 xinc
= (srcwidth
<< 16) / dstwidth
;
4803 yinc
= (srcheight
<< 16) / dstheight
;
4807 /* No effects, we can cheat here. */
4808 if (dstwidth
== srcwidth
)
4810 if (dstheight
== srcheight
)
4812 /* No stretching in either direction. This needs to be as
4813 * fast as possible. */
4816 /* Check for overlapping surfaces. */
4817 if (src_surface
!= dst_surface
|| dst_rect
->top
< src_rect
->top
4818 || dst_rect
->right
<= src_rect
->left
|| src_rect
->right
<= dst_rect
->left
)
4820 /* No overlap, or dst above src, so copy from top downwards. */
4821 for (y
= 0; y
< dstheight
; ++y
)
4823 memcpy(dbuf
, sbuf
, width
);
4824 sbuf
+= src_map
.row_pitch
;
4825 dbuf
+= dst_map
.row_pitch
;
4828 else if (dst_rect
->top
> src_rect
->top
)
4830 /* Copy from bottom upwards. */
4831 sbuf
+= src_map
.row_pitch
* dstheight
;
4832 dbuf
+= dst_map
.row_pitch
* dstheight
;
4833 for (y
= 0; y
< dstheight
; ++y
)
4835 sbuf
-= src_map
.row_pitch
;
4836 dbuf
-= dst_map
.row_pitch
;
4837 memcpy(dbuf
, sbuf
, width
);
4842 /* Src and dst overlapping on the same line, use memmove. */
4843 for (y
= 0; y
< dstheight
; ++y
)
4845 memmove(dbuf
, sbuf
, width
);
4846 sbuf
+= src_map
.row_pitch
;
4847 dbuf
+= dst_map
.row_pitch
;
4853 /* Stretching in y direction only. */
4854 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
4856 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
4857 memcpy(dbuf
, sbuf
, width
);
4858 dbuf
+= dst_map
.row_pitch
;
4864 /* Stretching in X direction. */
4866 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
4868 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
4870 if ((sy
>> 16) == (last_sy
>> 16))
4872 /* This source row is the same as last source row -
4873 * Copy the already stretched row. */
4874 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
4878 #define STRETCH_ROW(type) \
4880 const type *s = (const type *)sbuf; \
4881 type *d = (type *)dbuf; \
4882 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
4883 d[x] = s[sx >> 16]; \
4901 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
4905 s
= sbuf
+ 3 * (sx
>> 16);
4906 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
4907 d
[0] = (pixel
) & 0xff;
4908 d
[1] = (pixel
>> 8) & 0xff;
4909 d
[2] = (pixel
>> 16) & 0xff;
4915 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
4916 hr
= WINED3DERR_NOTAVAILABLE
;
4921 dbuf
+= dst_map
.row_pitch
;
4928 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
4929 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
4930 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
4931 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
4933 /* The color keying flags are checked for correctness in ddraw */
4934 if (flags
& WINEDDBLT_KEYSRC
)
4936 keylow
= src_surface
->container
->src_blt_color_key
.color_space_low_value
;
4937 keyhigh
= src_surface
->container
->src_blt_color_key
.color_space_high_value
;
4939 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
4941 keylow
= fx
->ddckSrcColorkey
.color_space_low_value
;
4942 keyhigh
= fx
->ddckSrcColorkey
.color_space_high_value
;
4945 if (flags
& WINEDDBLT_KEYDEST
)
4947 /* Destination color keys are taken from the source surface! */
4948 destkeylow
= src_surface
->container
->dst_blt_color_key
.color_space_low_value
;
4949 destkeyhigh
= src_surface
->container
->dst_blt_color_key
.color_space_high_value
;
4951 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
4953 destkeylow
= fx
->ddckDestColorkey
.color_space_low_value
;
4954 destkeyhigh
= fx
->ddckDestColorkey
.color_space_high_value
;
4964 get_color_masks(src_format
, masks
);
4969 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
4972 if (flags
& WINEDDBLT_DDFX
)
4974 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
4977 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
4978 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
4979 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
4981 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
4983 /* I don't think we need to do anything about this flag */
4984 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
4986 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
4989 dTopRight
= dTopLeft
;
4992 dBottomRight
= dBottomLeft
;
4994 dstxinc
= dstxinc
* -1;
4996 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
4999 dTopLeft
= dBottomLeft
;
5002 dTopRight
= dBottomRight
;
5004 dstyinc
= dstyinc
* -1;
5006 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
5008 /* I don't think we need to do anything about this flag */
5009 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
5011 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
5014 dBottomRight
= dTopLeft
;
5017 dBottomLeft
= dTopRight
;
5019 dstxinc
= dstxinc
* -1;
5020 dstyinc
= dstyinc
* -1;
5022 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
5025 dTopLeft
= dBottomLeft
;
5026 dBottomLeft
= dBottomRight
;
5027 dBottomRight
= dTopRight
;
5032 dstxinc
= dstxinc
* -1;
5034 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
5037 dTopLeft
= dTopRight
;
5038 dTopRight
= dBottomRight
;
5039 dBottomRight
= dBottomLeft
;
5044 dstyinc
= dstyinc
* -1;
5046 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
5048 /* I don't think we need to do anything about this flag */
5049 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
5052 flags
&= ~(WINEDDBLT_DDFX
);
5055 #define COPY_COLORKEY_FX(type) \
5058 type *d = (type *)dbuf, *dx, tmp; \
5059 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5061 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5063 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5065 tmp = s[sx >> 16]; \
5066 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5067 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5071 dx = (type *)(((BYTE *)dx) + dstxinc); \
5073 d = (type *)(((BYTE *)d) + dstyinc); \
5080 COPY_COLORKEY_FX(BYTE
);
5083 COPY_COLORKEY_FX(WORD
);
5086 COPY_COLORKEY_FX(DWORD
);
5091 BYTE
*d
= dbuf
, *dx
;
5092 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5094 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5096 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
5098 DWORD pixel
, dpixel
= 0;
5099 s
= sbuf
+ 3 * (sx
>>16);
5100 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5101 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
5102 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
5103 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
5105 dx
[0] = (pixel
) & 0xff;
5106 dx
[1] = (pixel
>> 8) & 0xff;
5107 dx
[2] = (pixel
>> 16) & 0xff;
5116 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5117 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
5118 hr
= WINED3DERR_NOTAVAILABLE
;
5120 #undef COPY_COLORKEY_FX
5126 if (flags
&& FIXME_ON(d3d_surface
))
5128 FIXME("\tUnsupported flags: %#x.\n", flags
);
5132 wined3d_surface_unmap(dst_surface
);
5133 if (src_surface
&& src_surface
!= dst_surface
)
5134 wined3d_surface_unmap(src_surface
);
5135 /* Release the converted surface, if any. */
5137 wined3d_texture_decref(src_texture
);
5142 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
5143 const RECT
*dst_rect
, const struct wined3d_color
*color
)
5145 static const RECT src_rect
;
5148 memset(&BltFx
, 0, sizeof(BltFx
));
5149 BltFx
.dwSize
= sizeof(BltFx
);
5150 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
5151 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
5152 WINEDDBLT_COLORFILL
, &BltFx
, WINED3D_TEXF_POINT
);
5155 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
5156 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
5158 FIXME("Depth filling not implemented by cpu_blit.\n");
5159 return WINED3DERR_INVALIDCALL
;
5162 const struct blit_shader cpu_blit
= {
5168 cpu_blit_color_fill
,
5169 cpu_blit_depth_fill
,
5172 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
5173 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
5174 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5176 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
5177 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5178 DWORD src_ds_flags
, dst_ds_flags
;
5179 RECT src_rect
, dst_rect
;
5180 BOOL scale
, convert
;
5182 static const DWORD simple_blit
= WINEDDBLT_ASYNC
5183 | WINEDDBLT_COLORFILL
5185 | WINEDDBLT_DEPTHFILL
5186 | WINEDDBLT_DONOTWAIT
;
5188 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5189 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
5190 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5191 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
5195 TRACE("dwSize %#x.\n", fx
->dwSize
);
5196 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
5197 TRACE("dwROP %#x.\n", fx
->dwROP
);
5198 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
5199 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
5200 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
5201 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
5202 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
5203 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
5204 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
5205 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
5206 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
5207 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
5208 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
5209 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
5210 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
5211 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
5212 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
5213 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
5214 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
5215 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
5216 TRACE("ddckDestColorkey {%#x, %#x}.\n",
5217 fx
->ddckDestColorkey
.color_space_low_value
,
5218 fx
->ddckDestColorkey
.color_space_high_value
);
5219 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
5220 fx
->ddckSrcColorkey
.color_space_low_value
,
5221 fx
->ddckSrcColorkey
.color_space_high_value
);
5224 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
5226 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5227 return WINEDDERR_SURFACEBUSY
;
5230 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
5232 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
5233 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
5234 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
5235 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
5236 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
5238 WARN("The application gave us a bad destination rectangle.\n");
5239 return WINEDDERR_INVALIDRECT
;
5244 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
5246 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
5247 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
5248 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
5249 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
5250 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
5252 WARN("Application gave us bad source rectangle for Blt.\n");
5253 return WINEDDERR_INVALIDRECT
;
5258 memset(&src_rect
, 0, sizeof(src_rect
));
5261 if (!fx
|| !(fx
->dwDDFX
))
5262 flags
&= ~WINEDDBLT_DDFX
;
5264 if (flags
& WINEDDBLT_WAIT
)
5265 flags
&= ~WINEDDBLT_WAIT
;
5267 if (flags
& WINEDDBLT_ASYNC
)
5269 static unsigned int once
;
5272 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
5273 flags
&= ~WINEDDBLT_ASYNC
;
5276 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
5277 if (flags
& WINEDDBLT_DONOTWAIT
)
5279 static unsigned int once
;
5282 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
5283 flags
&= ~WINEDDBLT_DONOTWAIT
;
5286 if (!device
->d3d_initialized
)
5288 WARN("D3D not initialized, using fallback.\n");
5292 /* We want to avoid invalidating the sysmem location for converted
5293 * surfaces, since otherwise we'd have to convert the data back when
5295 if (dst_surface
->container
->flags
& WINED3D_TEXTURE_CONVERTED
5296 || dst_surface
->container
->resource
.format
->convert
5297 || wined3d_format_get_color_key_conversion(dst_surface
->container
, TRUE
))
5299 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
5303 if (flags
& ~simple_blit
)
5305 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
5310 src_swapchain
= src_surface
->container
->swapchain
;
5312 src_swapchain
= NULL
;
5314 dst_swapchain
= dst_surface
->container
->swapchain
;
5316 /* This isn't strictly needed. FBO blits for example could deal with
5317 * cross-swapchain blits by first downloading the source to a texture
5318 * before switching to the destination context. We just have this here to
5319 * not have to deal with the issue, since cross-swapchain blits should be
5321 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
5323 FIXME("Using fallback for cross-swapchain blit.\n");
5328 && (src_rect
.right
- src_rect
.left
!= dst_rect
.right
- dst_rect
.left
5329 || src_rect
.bottom
- src_rect
.top
!= dst_rect
.bottom
- dst_rect
.top
);
5330 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
5332 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5334 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5338 if (src_ds_flags
|| dst_ds_flags
)
5340 if (flags
& WINEDDBLT_DEPTHFILL
)
5344 TRACE("Depth fill.\n");
5346 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
5347 return WINED3DERR_INVALIDCALL
;
5349 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
5354 if (src_ds_flags
!= dst_ds_flags
)
5356 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
5357 return WINED3DERR_INVALIDCALL
;
5360 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->container
->resource
.draw_binding
,
5361 &src_rect
, dst_surface
, dst_surface
->container
->resource
.draw_binding
, &dst_rect
)))
5367 /* In principle this would apply to depth blits as well, but we don't
5368 * implement those in the CPU blitter at the moment. */
5369 if ((dst_surface
->locations
& dst_surface
->resource
.map_binding
)
5370 && (!src_surface
|| (src_surface
->locations
& src_surface
->resource
.map_binding
)))
5373 TRACE("Not doing sysmem blit because of scaling.\n");
5375 TRACE("Not doing sysmem blit because of format conversion.\n");
5380 if (flags
& WINEDDBLT_COLORFILL
)
5382 struct wined3d_color color
;
5384 TRACE("Color fill.\n");
5386 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
5389 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
5394 TRACE("Color blit.\n");
5397 if ((src_surface
->locations
& WINED3D_LOCATION_SYSMEM
)
5398 && !(dst_surface
->locations
& WINED3D_LOCATION_SYSMEM
))
5401 TRACE("Not doing upload because of scaling.\n");
5403 TRACE("Not doing upload because of format conversion.\n");
5406 POINT dst_point
= {dst_rect
.left
, dst_rect
.top
};
5408 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, &src_rect
)))
5410 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
5411 surface_load_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5417 /* Use present for back -> front blits. The idea behind this is
5418 * that present is potentially faster than a blit, in particular
5419 * when FBO blits aren't available. Some ddraw applications like
5420 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
5421 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
5422 * applications can't blit directly to the frontbuffer. */
5423 if (dst_swapchain
&& dst_swapchain
->back_buffers
5424 && dst_surface
->container
== dst_swapchain
->front_buffer
5425 && src_surface
->container
== dst_swapchain
->back_buffers
[0])
5427 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
5429 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
5431 /* Set the swap effect to COPY, we don't want the backbuffer
5432 * to become undefined. */
5433 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
5434 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
5435 dst_swapchain
->desc
.swap_effect
= swap_effect
;
5440 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5441 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5442 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5444 TRACE("Using FBO blit.\n");
5446 surface_blt_fbo(device
, filter
,
5447 src_surface
, src_surface
->container
->resource
.draw_binding
, &src_rect
,
5448 dst_surface
, dst_surface
->container
->resource
.draw_binding
, &dst_rect
);
5449 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5450 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
5455 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5456 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5457 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5459 TRACE("Using arbfp blit.\n");
5461 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
5468 /* Special cases for render targets. */
5469 if (SUCCEEDED(surface_blt_special(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
)))
5474 /* For the rest call the X11 surface implementation. For render targets
5475 * this should be implemented OpenGL accelerated in surface_blt_special(),
5476 * other blits are rather rare. */
5477 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
5480 static HRESULT
surface_init(struct wined3d_surface
*surface
, struct wined3d_texture
*container
,
5481 const struct wined3d_resource_desc
*desc
, GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
)
5483 struct wined3d_device
*device
= container
->resource
.device
;
5484 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5485 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
);
5486 UINT multisample_quality
= desc
->multisample_quality
;
5487 BOOL lockable
= flags
& WINED3D_SURFACE_MAPPABLE
;
5488 unsigned int resource_size
;
5491 if (multisample_quality
> 0)
5493 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
5494 multisample_quality
= 0;
5497 /* Quick lockable sanity check.
5498 * TODO: remove this after surfaces, usage and lockability have been debugged properly
5499 * this function is too deep to need to care about things like this.
5500 * Levels need to be checked too, since they all affect what can be done. */
5503 case WINED3D_POOL_MANAGED
:
5504 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
)
5505 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
5508 case WINED3D_POOL_DEFAULT
:
5509 if (lockable
&& !(desc
->usage
& (WINED3DUSAGE_DYNAMIC
5510 | WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
5511 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
5514 case WINED3D_POOL_SCRATCH
:
5515 case WINED3D_POOL_SYSTEM_MEM
:
5519 FIXME("Unknown pool %#x.\n", desc
->pool
);
5523 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
5524 FIXME("Trying to create a render target that isn't in the default pool.\n");
5526 /* FIXME: Check that the format is supported by the device. */
5528 resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, desc
->width
, desc
->height
, 1);
5530 return WINED3DERR_INVALIDCALL
;
5532 if (device
->wined3d
->flags
& WINED3D_NO3D
)
5533 surface
->surface_ops
= &gdi_surface_ops
;
5535 surface
->surface_ops
= &surface_ops
;
5537 if (FAILED(hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
, format
,
5538 desc
->multisample_type
, multisample_quality
, desc
->usage
, desc
->pool
, desc
->width
, desc
->height
, 1,
5539 resource_size
, NULL
, &wined3d_null_parent_ops
, &surface_resource_ops
)))
5541 WARN("Failed to initialize resource, returning %#x.\n", hr
);
5545 surface
->container
= container
;
5546 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
5547 list_init(&surface
->renderbuffers
);
5548 list_init(&surface
->overlays
);
5551 if (flags
& WINED3D_SURFACE_DISCARD
)
5552 surface
->flags
|= SFLAG_DISCARD
;
5553 if (lockable
|| desc
->format
== WINED3DFMT_D16_LOCKABLE
)
5554 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
5556 surface
->texture_target
= target
;
5557 surface
->texture_level
= level
;
5558 surface
->texture_layer
= layer
;
5560 /* Call the private setup routine */
5561 if (FAILED(hr
= surface
->surface_ops
->surface_private_setup(surface
)))
5563 ERR("Private setup failed, hr %#x.\n", hr
);
5564 surface_cleanup(surface
);
5568 /* Similar to lockable rendertargets above, creating the DIB section
5569 * during surface initialization prevents the sysmem pointer from changing
5570 * after a wined3d_surface_getdc() call. */
5571 if ((desc
->usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
5572 && SUCCEEDED(surface_create_dib_section(surface
)))
5573 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
5575 if (surface
->resource
.map_binding
== WINED3D_LOCATION_DIB
)
5577 wined3d_resource_free_sysmem(&surface
->resource
);
5578 surface_validate_location(surface
, WINED3D_LOCATION_DIB
);
5579 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
5585 HRESULT
wined3d_surface_create(struct wined3d_texture
*container
, const struct wined3d_resource_desc
*desc
,
5586 GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
, struct wined3d_surface
**surface
)
5588 struct wined3d_device_parent
*device_parent
= container
->resource
.device
->device_parent
;
5589 const struct wined3d_parent_ops
*parent_ops
;
5590 struct wined3d_surface
*object
;
5594 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
5595 "multisample_type %#x, multisample_quality %u, target %#x, level %u, layer %u, flags %#x, surface %p.\n",
5596 container
, desc
->width
, desc
->height
, debug_d3dformat(desc
->format
),
5597 debug_d3dusage(desc
->usage
), desc
->usage
, debug_d3dpool(desc
->pool
),
5598 desc
->multisample_type
, desc
->multisample_quality
, target
, level
, layer
, flags
, surface
);
5600 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
5601 return E_OUTOFMEMORY
;
5603 if (FAILED(hr
= surface_init(object
, container
, desc
, target
, level
, layer
, flags
)))
5605 WARN("Failed to initialize surface, returning %#x.\n", hr
);
5606 HeapFree(GetProcessHeap(), 0, object
);
5610 if (FAILED(hr
= device_parent
->ops
->surface_created(device_parent
,
5611 wined3d_texture_get_parent(container
), object
, &parent
, &parent_ops
)))
5613 WARN("Failed to create surface parent, hr %#x.\n", hr
);
5614 wined3d_surface_destroy(object
);
5618 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object
, parent
, parent_ops
);
5620 object
->resource
.parent
= parent
;
5621 object
->resource
.parent_ops
= parent_ops
;