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
, wined3d_gl_mag_filter(filter
));
314 checkGLcall("glTexParameteri");
315 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
316 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
317 checkGLcall("glTexParameteri");
318 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
319 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
320 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
321 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
322 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
323 checkGLcall("glTexEnvi");
326 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
327 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
328 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
330 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
331 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
333 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
334 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
336 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
337 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
338 gl_info
->gl_ops
.gl
.p_glEnd();
340 /* Unbind the texture */
341 context_bind_texture(context
, info
.bind_target
, 0);
343 /* We changed the filtering settings on the texture. Inform the
344 * container about this to get the filters reset properly next draw. */
345 texture
->texture_rgb
.sampler_desc
.mag_filter
= WINED3D_TEXF_POINT
;
346 texture
->texture_rgb
.sampler_desc
.min_filter
= WINED3D_TEXF_POINT
;
347 texture
->texture_rgb
.sampler_desc
.mip_filter
= WINED3D_TEXF_NONE
;
348 texture
->texture_rgb
.sampler_desc
.srgb_decode
= FALSE
;
351 /* Works correctly only for <= 4 bpp formats. */
352 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
354 masks
[0] = ((1 << format
->red_size
) - 1) << format
->red_offset
;
355 masks
[1] = ((1 << format
->green_size
) - 1) << format
->green_offset
;
356 masks
[2] = ((1 << format
->blue_size
) - 1) << format
->blue_offset
;
359 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
361 const struct wined3d_format
*format
= surface
->resource
.format
;
367 TRACE("surface %p.\n", surface
);
369 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
371 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
372 return WINED3DERR_INVALIDCALL
;
375 switch (format
->byte_count
)
379 /* Allocate extra space to store the RGB bit masks. */
380 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
384 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
388 /* Allocate extra space for a palette. */
389 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
390 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
395 return E_OUTOFMEMORY
;
397 /* Some applications access the surface in via DWORDs, and do not take
398 * the necessary care at the end of the surface. So we need at least
399 * 4 extra bytes at the end of the surface. Check against the page size,
400 * if the last page used for the surface has at least 4 spare bytes we're
401 * safe, otherwise add an extra line to the DIB section. */
402 GetSystemInfo(&sysInfo
);
403 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
406 TRACE("Adding an extra line to the DIB section.\n");
409 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
410 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
411 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
412 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
413 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
414 * wined3d_surface_get_pitch(surface
);
415 b_info
->bmiHeader
.biPlanes
= 1;
416 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
418 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
419 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
420 b_info
->bmiHeader
.biClrUsed
= 0;
421 b_info
->bmiHeader
.biClrImportant
= 0;
423 /* Get the bit masks */
424 masks
= (DWORD
*)b_info
->bmiColors
;
425 switch (surface
->resource
.format
->id
)
427 case WINED3DFMT_B8G8R8_UNORM
:
428 b_info
->bmiHeader
.biCompression
= BI_RGB
;
431 case WINED3DFMT_B5G5R5X1_UNORM
:
432 case WINED3DFMT_B5G5R5A1_UNORM
:
433 case WINED3DFMT_B4G4R4A4_UNORM
:
434 case WINED3DFMT_B4G4R4X4_UNORM
:
435 case WINED3DFMT_B2G3R3_UNORM
:
436 case WINED3DFMT_B2G3R3A8_UNORM
:
437 case WINED3DFMT_R10G10B10A2_UNORM
:
438 case WINED3DFMT_R8G8B8A8_UNORM
:
439 case WINED3DFMT_R8G8B8X8_UNORM
:
440 case WINED3DFMT_B10G10R10A2_UNORM
:
441 case WINED3DFMT_B5G6R5_UNORM
:
442 case WINED3DFMT_R16G16B16A16_UNORM
:
443 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
444 get_color_masks(format
, masks
);
448 /* Don't know palette */
449 b_info
->bmiHeader
.biCompression
= BI_RGB
;
453 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
454 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
455 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
456 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->dib
.bitmap_data
, 0, 0);
458 if (!surface
->dib
.DIBsection
)
460 ERR("Failed to create DIB section.\n");
461 HeapFree(GetProcessHeap(), 0, b_info
);
462 return HRESULT_FROM_WIN32(GetLastError());
465 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
466 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
468 HeapFree(GetProcessHeap(), 0, b_info
);
470 /* Now allocate a DC. */
471 surface
->hDC
= CreateCompatibleDC(0);
472 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
474 surface
->flags
|= SFLAG_DIBSECTION
;
479 static void surface_get_memory(const struct wined3d_surface
*surface
, struct wined3d_bo_address
*data
,
482 if (location
& WINED3D_LOCATION_BUFFER
)
485 data
->buffer_object
= surface
->pbo
;
488 if (location
& WINED3D_LOCATION_USER_MEMORY
)
490 data
->addr
= surface
->user_memory
;
491 data
->buffer_object
= 0;
494 if (location
& WINED3D_LOCATION_DIB
)
496 data
->addr
= surface
->dib
.bitmap_data
;
497 data
->buffer_object
= 0;
500 if (location
& WINED3D_LOCATION_SYSMEM
)
502 data
->addr
= surface
->resource
.heap_memory
;
503 data
->buffer_object
= 0;
507 ERR("Unexpected locations %s.\n", wined3d_debug_location(location
));
509 data
->buffer_object
= 0;
512 static void surface_prepare_buffer(struct wined3d_surface
*surface
)
514 struct wined3d_context
*context
;
516 const struct wined3d_gl_info
*gl_info
;
521 context
= context_acquire(surface
->resource
.device
, NULL
);
522 gl_info
= context
->gl_info
;
524 GL_EXTCALL(glGenBuffers(1, &surface
->pbo
));
525 error
= gl_info
->gl_ops
.gl
.p_glGetError();
526 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
527 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
529 TRACE("Binding PBO %u.\n", surface
->pbo
);
531 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
532 checkGLcall("glBindBuffer");
534 GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER
, surface
->resource
.size
+ 4,
535 NULL
, GL_STREAM_DRAW
));
536 checkGLcall("glBufferData");
538 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
539 checkGLcall("glBindBuffer");
541 context_release(context
);
544 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
546 TRACE("surface %p.\n", surface
);
548 if (surface
->resource
.heap_memory
)
551 /* Whatever surface we have, make sure that there is memory allocated
552 * for the downloaded copy, or a PBO to map. */
553 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
554 ERR("Failed to allocate system memory.\n");
556 if (surface
->locations
& WINED3D_LOCATION_SYSMEM
)
557 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
560 void surface_prepare_map_memory(struct wined3d_surface
*surface
)
562 switch (surface
->resource
.map_binding
)
564 case WINED3D_LOCATION_SYSMEM
:
565 surface_prepare_system_memory(surface
);
568 case WINED3D_LOCATION_USER_MEMORY
:
569 if (!surface
->user_memory
)
570 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
573 case WINED3D_LOCATION_DIB
:
574 if (!surface
->dib
.bitmap_data
)
575 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
578 case WINED3D_LOCATION_BUFFER
:
579 surface_prepare_buffer(surface
);
583 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
587 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
589 /* In some conditions the surface memory must not be freed:
590 * WINED3D_TEXTURE_CONVERTED: Converting the data back would take too long
591 * WINED3D_TEXTURE_DYNAMIC_MAP: Avoid freeing the data for performance
592 * SFLAG_CLIENT: OpenGL uses our memory as backup */
593 if (surface
->resource
.map_count
|| surface
->flags
& SFLAG_CLIENT
594 || surface
->container
->flags
& (WINED3D_TEXTURE_CONVERTED
| WINED3D_TEXTURE_PIN_SYSMEM
595 | WINED3D_TEXTURE_DYNAMIC_MAP
))
598 wined3d_resource_free_sysmem(&surface
->resource
);
599 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
602 static void surface_release_client_storage(struct wined3d_surface
*surface
)
604 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
605 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
607 if (surface
->container
->texture_rgb
.name
)
609 wined3d_texture_bind_and_dirtify(surface
->container
, context
, FALSE
);
610 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
611 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
613 if (surface
->container
->texture_srgb
.name
)
615 wined3d_texture_bind_and_dirtify(surface
->container
, context
, TRUE
);
616 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
617 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
619 wined3d_texture_force_reload(surface
->container
);
621 context_release(context
);
624 static BOOL
surface_use_pbo(const struct wined3d_surface
*surface
)
626 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
627 struct wined3d_texture
*texture
= surface
->container
;
629 return texture
->resource
.pool
== WINED3D_POOL_DEFAULT
630 && surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
631 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
632 && !texture
->resource
.format
->convert
633 && !(texture
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
)
634 && !(surface
->flags
& SFLAG_NONPOW2
);
637 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
639 /* TODO: Check against the maximum texture sizes supported by the video card. */
640 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
641 unsigned int pow2Width
, pow2Height
;
643 TRACE("surface %p.\n", surface
);
645 /* Non-power2 support */
646 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
]
647 || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
649 pow2Width
= surface
->resource
.width
;
650 pow2Height
= surface
->resource
.height
;
654 /* Find the nearest pow2 match */
655 pow2Width
= pow2Height
= 1;
656 while (pow2Width
< surface
->resource
.width
)
658 while (pow2Height
< surface
->resource
.height
)
661 surface
->pow2Width
= pow2Width
;
662 surface
->pow2Height
= pow2Height
;
664 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
666 /* TODO: Add support for non power two compressed textures. */
667 if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_HEIGHT_SCALE
))
669 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
670 surface
, surface
->resource
.width
, surface
->resource
.height
);
671 return WINED3DERR_NOTAVAILABLE
;
675 if (pow2Width
!= surface
->resource
.width
676 || pow2Height
!= surface
->resource
.height
)
678 surface
->flags
|= SFLAG_NONPOW2
;
681 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
682 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
684 /* One of three options:
685 * 1: Do the same as we do with NPOT and scale the texture, (any
686 * texture ops would require the texture to be scaled which is
688 * 2: Set the texture to the maximum size (bad idea).
689 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
690 * 4: Create the surface, but allow it to be used only for DirectDraw
691 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
692 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
693 * the render target. */
694 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
|| surface
->resource
.pool
== WINED3D_POOL_MANAGED
)
696 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
697 return WINED3DERR_NOTAVAILABLE
;
700 /* We should never use this surface in combination with OpenGL! */
701 TRACE("Creating an oversized surface: %ux%u.\n",
702 surface
->pow2Width
, surface
->pow2Height
);
705 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
706 surface
->locations
= WINED3D_LOCATION_DISCARDED
;
708 if (surface_use_pbo(surface
))
709 surface
->resource
.map_binding
= WINED3D_LOCATION_BUFFER
;
714 static void surface_unmap(struct wined3d_surface
*surface
)
716 struct wined3d_device
*device
= surface
->resource
.device
;
717 const struct wined3d_gl_info
*gl_info
;
718 struct wined3d_context
*context
;
720 TRACE("surface %p.\n", surface
);
722 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
724 switch (surface
->resource
.map_binding
)
726 case WINED3D_LOCATION_SYSMEM
:
727 case WINED3D_LOCATION_USER_MEMORY
:
728 case WINED3D_LOCATION_DIB
:
731 case WINED3D_LOCATION_BUFFER
:
732 context
= context_acquire(device
, NULL
);
733 gl_info
= context
->gl_info
;
735 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
736 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER
));
737 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
738 checkGLcall("glUnmapBuffer");
739 context_release(context
);
743 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
746 if (surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_TEXTURE_RGB
))
748 TRACE("Not dirtified, nothing to do.\n");
752 if (surface
->container
->swapchain
&& surface
->container
->swapchain
->front_buffer
== surface
->container
)
753 surface_load_location(surface
, surface
->container
->resource
.draw_binding
);
754 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
755 FIXME("Depth / stencil buffer locking is not implemented.\n");
758 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
760 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
762 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
767 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
768 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
769 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
771 const struct wined3d_gl_info
*gl_info
;
772 struct wined3d_context
*context
;
773 DWORD src_mask
, dst_mask
;
776 TRACE("device %p\n", device
);
777 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
778 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
779 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
780 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
782 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
783 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
785 if (src_mask
!= dst_mask
)
787 ERR("Incompatible formats %s and %s.\n",
788 debug_d3dformat(src_surface
->resource
.format
->id
),
789 debug_d3dformat(dst_surface
->resource
.format
->id
));
795 ERR("Not a depth / stencil format: %s.\n",
796 debug_d3dformat(src_surface
->resource
.format
->id
));
801 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
802 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
803 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
804 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
806 /* Make sure the locations are up-to-date. Loading the destination
807 * surface isn't required if the entire surface is overwritten. */
808 surface_load_location(src_surface
, src_location
);
809 if (!surface_is_full_rect(dst_surface
, dst_rect
))
810 surface_load_location(dst_surface
, dst_location
);
812 context
= context_acquire(device
, NULL
);
815 context_release(context
);
816 WARN("Invalid context, skipping blit.\n");
820 gl_info
= context
->gl_info
;
822 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
823 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
825 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
826 context_set_draw_buffer(context
, GL_NONE
);
827 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
828 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
830 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
832 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
833 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
835 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
837 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
839 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
840 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
842 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
843 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
846 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
847 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
849 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
850 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
851 checkGLcall("glBlitFramebuffer()");
853 if (wined3d_settings
.strict_draw_ordering
)
854 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
856 context_release(context
);
859 /* Blit between surface locations. Onscreen on different swapchains is not supported.
860 * Depth / stencil is not supported. */
861 static void surface_blt_fbo(const struct wined3d_device
*device
, enum wined3d_texture_filter_type filter
,
862 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
863 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
865 const struct wined3d_gl_info
*gl_info
;
866 struct wined3d_context
*context
;
867 RECT src_rect
, dst_rect
;
871 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
872 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
873 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
874 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
875 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
877 src_rect
= *src_rect_in
;
878 dst_rect
= *dst_rect_in
;
882 case WINED3D_TEXF_LINEAR
:
883 gl_filter
= GL_LINEAR
;
887 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
888 case WINED3D_TEXF_NONE
:
889 case WINED3D_TEXF_POINT
:
890 gl_filter
= GL_NEAREST
;
894 /* Resolve the source surface first if needed. */
895 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
896 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
897 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
898 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
899 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
901 /* Make sure the locations are up-to-date. Loading the destination
902 * surface isn't required if the entire surface is overwritten. (And is
903 * in fact harmful if we're being called by surface_load_location() with
904 * the purpose of loading the destination surface.) */
905 surface_load_location(src_surface
, src_location
);
906 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
907 surface_load_location(dst_surface
, dst_location
);
909 if (src_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, src_surface
);
910 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, dst_surface
);
911 else context
= context_acquire(device
, NULL
);
915 context_release(context
);
916 WARN("Invalid context, skipping blit.\n");
920 gl_info
= context
->gl_info
;
922 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
924 TRACE("Source surface %p is onscreen.\n", src_surface
);
925 buffer
= surface_get_gl_buffer(src_surface
);
926 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
930 TRACE("Source surface %p is offscreen.\n", src_surface
);
931 buffer
= GL_COLOR_ATTACHMENT0
;
934 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
935 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
936 checkGLcall("glReadBuffer()");
937 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
939 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
941 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
942 buffer
= surface_get_gl_buffer(dst_surface
);
943 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
947 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
948 buffer
= GL_COLOR_ATTACHMENT0
;
951 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
952 context_set_draw_buffer(context
, buffer
);
953 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
954 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
956 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
957 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
958 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
959 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
960 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
962 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
963 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
965 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
966 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
967 checkGLcall("glBlitFramebuffer()");
969 if (wined3d_settings
.strict_draw_ordering
970 || (dst_location
== WINED3D_LOCATION_DRAWABLE
971 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
972 gl_info
->gl_ops
.gl
.p_glFlush();
974 context_release(context
);
977 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
978 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
979 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
981 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
984 /* Source and/or destination need to be on the GL side */
985 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
990 case WINED3D_BLIT_OP_COLOR_BLIT
:
991 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
993 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
997 case WINED3D_BLIT_OP_DEPTH_BLIT
:
998 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1000 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1008 if (!(src_format
->id
== dst_format
->id
1009 || (is_identity_fixup(src_format
->color_fixup
)
1010 && is_identity_fixup(dst_format
->color_fixup
))))
1016 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1017 DWORD color
, struct wined3d_color
*float_color
)
1019 const struct wined3d_format
*format
= surface
->resource
.format
;
1020 const struct wined3d_palette
*palette
;
1024 case WINED3DFMT_P8_UINT
:
1025 palette
= surface
->container
->swapchain
? surface
->container
->swapchain
->palette
: NULL
;
1029 float_color
->r
= palette
->colors
[color
].rgbRed
/ 255.0f
;
1030 float_color
->g
= palette
->colors
[color
].rgbGreen
/ 255.0f
;
1031 float_color
->b
= palette
->colors
[color
].rgbBlue
/ 255.0f
;
1035 float_color
->r
= 0.0f
;
1036 float_color
->g
= 0.0f
;
1037 float_color
->b
= 0.0f
;
1039 float_color
->a
= color
/ 255.0f
;
1042 case WINED3DFMT_B5G6R5_UNORM
:
1043 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1044 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1045 float_color
->b
= (color
& 0x1f) / 31.0f
;
1046 float_color
->a
= 1.0f
;
1049 case WINED3DFMT_B8G8R8_UNORM
:
1050 case WINED3DFMT_B8G8R8X8_UNORM
:
1051 float_color
->r
= D3DCOLOR_R(color
);
1052 float_color
->g
= D3DCOLOR_G(color
);
1053 float_color
->b
= D3DCOLOR_B(color
);
1054 float_color
->a
= 1.0f
;
1057 case WINED3DFMT_B8G8R8A8_UNORM
:
1058 float_color
->r
= D3DCOLOR_R(color
);
1059 float_color
->g
= D3DCOLOR_G(color
);
1060 float_color
->b
= D3DCOLOR_B(color
);
1061 float_color
->a
= D3DCOLOR_A(color
);
1065 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1072 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1074 const struct wined3d_format
*format
= surface
->resource
.format
;
1078 case WINED3DFMT_S1_UINT_D15_UNORM
:
1079 *float_depth
= depth
/ (float)0x00007fff;
1082 case WINED3DFMT_D16_UNORM
:
1083 *float_depth
= depth
/ (float)0x0000ffff;
1086 case WINED3DFMT_D24_UNORM_S8_UINT
:
1087 case WINED3DFMT_X8D24_UNORM
:
1088 *float_depth
= depth
/ (float)0x00ffffff;
1091 case WINED3DFMT_D32_UNORM
:
1092 *float_depth
= depth
/ (float)0xffffffff;
1096 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1103 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1105 const struct wined3d_resource
*resource
= &surface
->container
->resource
;
1106 struct wined3d_device
*device
= resource
->device
;
1107 const struct blit_shader
*blitter
;
1109 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1110 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1113 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1114 return WINED3DERR_INVALIDCALL
;
1117 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1120 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1121 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1123 struct wined3d_device
*device
= src_surface
->resource
.device
;
1125 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1126 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1127 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1128 return WINED3DERR_INVALIDCALL
;
1130 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
1132 surface_modify_ds_location(dst_surface
, dst_location
,
1133 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1138 HRESULT CDECL
wined3d_surface_get_render_target_data(struct wined3d_surface
*surface
,
1139 struct wined3d_surface
*render_target
)
1141 TRACE("surface %p, render_target %p.\n", surface
, render_target
);
1143 /* TODO: Check surface sizes, pools, etc. */
1145 if (render_target
->resource
.multisample_type
)
1146 return WINED3DERR_INVALIDCALL
;
1148 return wined3d_surface_blt(surface
, NULL
, render_target
, NULL
, 0, NULL
, WINED3D_TEXF_POINT
);
1151 /* Context activation is done by the caller. */
1152 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1154 GL_EXTCALL(glDeleteBuffers(1, &surface
->pbo
));
1155 checkGLcall("glDeleteBuffers(1, &surface->pbo)");
1158 surface_invalidate_location(surface
, WINED3D_LOCATION_BUFFER
);
1161 static ULONG
surface_resource_incref(struct wined3d_resource
*resource
)
1163 return wined3d_surface_incref(surface_from_resource(resource
));
1166 static ULONG
surface_resource_decref(struct wined3d_resource
*resource
)
1168 return wined3d_surface_decref(surface_from_resource(resource
));
1171 static void surface_unload(struct wined3d_resource
*resource
)
1173 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1174 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1175 struct wined3d_device
*device
= resource
->device
;
1176 const struct wined3d_gl_info
*gl_info
;
1177 struct wined3d_context
*context
;
1179 TRACE("surface %p.\n", surface
);
1181 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
1183 /* Default pool resources are supposed to be destroyed before Reset is called.
1184 * Implicit resources stay however. So this means we have an implicit render target
1185 * or depth stencil. The content may be destroyed, but we still have to tear down
1186 * opengl resources, so we cannot leave early.
1188 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1189 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1190 * or the depth stencil into an FBO the texture or render buffer will be removed
1191 * and all flags get lost */
1192 surface_prepare_system_memory(surface
);
1193 memset(surface
->resource
.heap_memory
, 0, surface
->resource
.size
);
1194 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
1195 surface_invalidate_location(surface
, ~WINED3D_LOCATION_SYSMEM
);
1197 /* We also get here when the ddraw swapchain is destroyed, for example
1198 * for a mode switch. In this case this surface won't necessarily be
1199 * an implicit surface. We have to mark it lost so that the
1200 * application can restore it after the mode switch. */
1201 surface
->flags
|= SFLAG_LOST
;
1205 surface_prepare_map_memory(surface
);
1206 surface_load_location(surface
, surface
->resource
.map_binding
);
1207 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
1210 context
= context_acquire(device
, NULL
);
1211 gl_info
= context
->gl_info
;
1213 /* Destroy PBOs, but load them into real sysmem before */
1215 surface_remove_pbo(surface
, gl_info
);
1217 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1218 * all application-created targets the application has to release the surface
1219 * before calling _Reset
1221 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1223 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1224 list_remove(&entry
->entry
);
1225 HeapFree(GetProcessHeap(), 0, entry
);
1227 list_init(&surface
->renderbuffers
);
1228 surface
->current_renderbuffer
= NULL
;
1230 if (surface
->rb_multisample
)
1232 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1233 surface
->rb_multisample
= 0;
1235 if (surface
->rb_resolved
)
1237 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1238 surface
->rb_resolved
= 0;
1241 context_release(context
);
1243 resource_unload(resource
);
1246 static const struct wined3d_resource_ops surface_resource_ops
=
1248 surface_resource_incref
,
1249 surface_resource_decref
,
1253 static const struct wined3d_surface_ops surface_ops
=
1255 surface_private_setup
,
1259 /*****************************************************************************
1260 * Initializes the GDI surface, aka creates the DIB section we render to
1261 * The DIB section creation is done by calling GetDC, which will create the
1262 * section and releasing the dc to allow the app to use it. The dib section
1263 * will stay until the surface is released
1265 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1266 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1267 * avoid confusion in the shared surface code.
1270 * WINED3D_OK on success
1271 * The return values of called methods on failure
1273 *****************************************************************************/
1274 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1278 TRACE("surface %p.\n", surface
);
1280 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1282 ERR("Overlays not yet supported by GDI surfaces.\n");
1283 return WINED3DERR_INVALIDCALL
;
1286 /* Sysmem textures have memory already allocated - release it,
1287 * this avoids an unnecessary memcpy. */
1288 hr
= surface_create_dib_section(surface
);
1291 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
1293 /* We don't mind the nonpow2 stuff in GDI. */
1294 surface
->pow2Width
= surface
->resource
.width
;
1295 surface
->pow2Height
= surface
->resource
.height
;
1300 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1302 TRACE("surface %p.\n", surface
);
1304 /* Tell the swapchain to update the screen. */
1305 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
1306 x11_copy_to_screen(surface
->container
->swapchain
, &surface
->lockedRect
);
1308 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
1311 static const struct wined3d_surface_ops gdi_surface_ops
=
1313 gdi_surface_private_setup
,
1317 /* This call just downloads data, the caller is responsible for binding the
1318 * correct texture. */
1319 /* Context activation is done by the caller. */
1320 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1323 const struct wined3d_format
*format
= surface
->resource
.format
;
1324 struct wined3d_bo_address data
;
1326 /* Only support read back of converted P8 surfaces. */
1327 if (surface
->container
->flags
& WINED3D_TEXTURE_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1329 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1333 surface_get_memory(surface
, &data
, dst_location
);
1335 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1337 TRACE("(%p) : Calling glGetCompressedTexImage level %d, format %#x, type %#x, data %p.\n",
1338 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, data
.addr
);
1340 if (data
.buffer_object
)
1342 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1343 checkGLcall("glBindBuffer");
1344 GL_EXTCALL(glGetCompressedTexImage(surface
->texture_target
, surface
->texture_level
, NULL
));
1345 checkGLcall("glGetCompressedTexImage");
1346 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1347 checkGLcall("glBindBuffer");
1351 GL_EXTCALL(glGetCompressedTexImage(surface
->texture_target
,
1352 surface
->texture_level
, data
.addr
));
1353 checkGLcall("glGetCompressedTexImage");
1359 GLenum gl_format
= format
->glFormat
;
1360 GLenum gl_type
= format
->glType
;
1364 if (surface
->flags
& SFLAG_NONPOW2
)
1366 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
1367 src_pitch
= format
->byte_count
* surface
->pow2Width
;
1368 dst_pitch
= wined3d_surface_get_pitch(surface
);
1369 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
1370 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
1377 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1378 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1380 if (data
.buffer_object
)
1382 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
1383 checkGLcall("glBindBuffer");
1385 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1386 gl_format
, gl_type
, NULL
);
1387 checkGLcall("glGetTexImage");
1389 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
1390 checkGLcall("glBindBuffer");
1394 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1395 gl_format
, gl_type
, mem
);
1396 checkGLcall("glGetTexImage");
1399 if (surface
->flags
& SFLAG_NONPOW2
)
1401 const BYTE
*src_data
;
1405 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1406 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1407 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1409 * We're doing this...
1411 * instead of boxing the texture :
1412 * |<-texture width ->| -->pow2width| /\
1413 * |111111111111111111| | |
1414 * |222 Texture 222222| boxed empty | texture height
1415 * |3333 Data 33333333| | |
1416 * |444444444444444444| | \/
1417 * ----------------------------------- |
1418 * | boxed empty | boxed empty | pow2height
1420 * -----------------------------------
1423 * we're repacking the data to the expected texture width
1425 * |<-texture width ->| -->pow2width| /\
1426 * |111111111111111111222222222222222| |
1427 * |222333333333333333333444444444444| texture height
1431 * | empty | pow2height
1433 * -----------------------------------
1437 * |<-texture width ->| /\
1438 * |111111111111111111|
1439 * |222222222222222222|texture height
1440 * |333333333333333333|
1441 * |444444444444444444| \/
1442 * --------------------
1444 * This also means that any references to surface memory should work with the data as if it were a
1445 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1447 * internally the texture is still stored in a boxed format so any references to textureName will
1448 * get a boxed texture with width pow2width and not a texture of width resource.width.
1450 * Performance should not be an issue, because applications normally do not lock the surfaces when
1451 * rendering. If an app does, the WINED3D_TEXTURE_DYNAMIC_MAP flag will kick in and the memory copy
1452 * won't be released, and doesn't have to be re-read. */
1454 dst_data
= data
.addr
;
1455 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
1456 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1458 memcpy(dst_data
, src_data
, dst_pitch
);
1459 src_data
+= src_pitch
;
1460 dst_data
+= dst_pitch
;
1463 HeapFree(GetProcessHeap(), 0, mem
);
1468 /* This call just uploads data, the caller is responsible for binding the
1469 * correct texture. */
1470 /* Context activation is done by the caller. */
1471 void wined3d_surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1472 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1473 BOOL srgb
, const struct wined3d_const_bo_address
*data
)
1475 UINT update_w
= src_rect
->right
- src_rect
->left
;
1476 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1478 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1479 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1480 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1482 if (surface
->resource
.map_count
)
1484 WARN("Uploading a surface that is currently mapped, setting WINED3D_TEXTURE_PIN_SYSMEM.\n");
1485 surface
->container
->flags
|= WINED3D_TEXTURE_PIN_SYSMEM
;
1488 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1490 update_h
*= format
->height_scale
.numerator
;
1491 update_h
/= format
->height_scale
.denominator
;
1494 if (data
->buffer_object
)
1496 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, data
->buffer_object
));
1497 checkGLcall("glBindBuffer");
1500 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1502 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1503 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1504 const BYTE
*addr
= data
->addr
;
1507 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1508 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1511 internal
= format
->glGammaInternal
;
1512 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1513 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
1514 internal
= format
->rtInternal
;
1516 internal
= format
->glInternal
;
1518 TRACE("glCompressedTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, "
1519 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1520 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1522 if (row_length
== src_pitch
)
1524 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1525 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1531 /* glCompressedTexSubImage2D() ignores pixel store state, so we
1532 * can't use the unpack row length like for glTexSubImage2D. */
1533 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1535 GL_EXTCALL(glCompressedTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1536 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1537 y
+= format
->block_height
;
1541 checkGLcall("glCompressedTexSubImage2D");
1545 const BYTE
*addr
= data
->addr
;
1547 addr
+= src_rect
->top
* src_pitch
;
1548 addr
+= src_rect
->left
* format
->byte_count
;
1550 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1551 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1552 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1554 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1555 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1556 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1557 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1558 checkGLcall("glTexSubImage2D");
1561 if (data
->buffer_object
)
1563 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
1564 checkGLcall("glBindBuffer");
1567 if (wined3d_settings
.strict_draw_ordering
)
1568 gl_info
->gl_ops
.gl
.p_glFlush();
1570 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1572 struct wined3d_device
*device
= surface
->resource
.device
;
1575 for (i
= 0; i
< device
->context_count
; ++i
)
1577 context_surface_update(device
->contexts
[i
], surface
);
1582 static BOOL
surface_check_block_align(struct wined3d_surface
*surface
, const RECT
*rect
)
1584 UINT width_mask
, height_mask
;
1586 if (!rect
->left
&& !rect
->top
1587 && rect
->right
== surface
->resource
.width
1588 && rect
->bottom
== surface
->resource
.height
)
1591 /* This assumes power of two block sizes, but NPOT block sizes would be
1593 width_mask
= surface
->resource
.format
->block_width
- 1;
1594 height_mask
= surface
->resource
.format
->block_height
- 1;
1596 if (!(rect
->left
& width_mask
) && !(rect
->top
& height_mask
)
1597 && !(rect
->right
& width_mask
) && !(rect
->bottom
& height_mask
))
1603 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1604 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1606 const struct wined3d_format
*src_format
;
1607 const struct wined3d_format
*dst_format
;
1608 const struct wined3d_gl_info
*gl_info
;
1609 struct wined3d_context
*context
;
1610 struct wined3d_bo_address data
;
1611 UINT update_w
, update_h
;
1617 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1618 dst_surface
, wine_dbgstr_point(dst_point
),
1619 src_surface
, wine_dbgstr_rect(src_rect
));
1621 src_format
= src_surface
->resource
.format
;
1622 dst_format
= dst_surface
->resource
.format
;
1624 if (src_format
->id
!= dst_format
->id
)
1626 WARN("Source and destination surfaces should have the same format.\n");
1627 return WINED3DERR_INVALIDCALL
;
1636 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1638 WARN("Invalid destination point.\n");
1639 return WINED3DERR_INVALIDCALL
;
1646 r
.right
= src_surface
->resource
.width
;
1647 r
.bottom
= src_surface
->resource
.height
;
1650 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
1651 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
1653 WARN("Invalid source rectangle.\n");
1654 return WINED3DERR_INVALIDCALL
;
1657 dst_w
= dst_surface
->resource
.width
;
1658 dst_h
= dst_surface
->resource
.height
;
1660 update_w
= src_rect
->right
- src_rect
->left
;
1661 update_h
= src_rect
->bottom
- src_rect
->top
;
1663 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1664 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1666 WARN("Destination out of bounds.\n");
1667 return WINED3DERR_INVALIDCALL
;
1670 if ((src_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(src_surface
, src_rect
))
1672 WARN("Source rectangle not block-aligned.\n");
1673 return WINED3DERR_INVALIDCALL
;
1676 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1677 if ((dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(dst_surface
, &dst_rect
))
1679 WARN("Destination rectangle not block-aligned.\n");
1680 return WINED3DERR_INVALIDCALL
;
1683 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1684 if (dst_format
->convert
|| wined3d_format_get_color_key_conversion(dst_surface
->container
, FALSE
))
1685 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1687 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
1688 gl_info
= context
->gl_info
;
1690 /* Only load the surface for partial updates. For newly allocated texture
1691 * the texture wouldn't be the current location, and we'd upload zeroes
1692 * just to overwrite them again. */
1693 if (update_w
== dst_w
&& update_h
== dst_h
)
1694 wined3d_texture_prepare_texture(dst_surface
->container
, context
, FALSE
);
1696 surface_load_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1697 wined3d_texture_bind(dst_surface
->container
, context
, FALSE
);
1699 surface_get_memory(src_surface
, &data
, src_surface
->locations
);
1700 src_pitch
= wined3d_surface_get_pitch(src_surface
);
1702 wined3d_surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
,
1703 src_pitch
, dst_point
, FALSE
, wined3d_const_bo_address(&data
));
1705 context_invalidate_active_texture(context
);
1707 context_release(context
);
1709 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1710 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1715 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1716 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1717 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1718 /* Context activation is done by the caller. */
1719 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1721 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
1722 struct wined3d_renderbuffer_entry
*entry
;
1723 GLuint renderbuffer
= 0;
1724 unsigned int src_width
, src_height
;
1725 unsigned int width
, height
;
1727 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
1729 width
= rt
->pow2Width
;
1730 height
= rt
->pow2Height
;
1734 width
= surface
->pow2Width
;
1735 height
= surface
->pow2Height
;
1738 src_width
= surface
->pow2Width
;
1739 src_height
= surface
->pow2Height
;
1741 /* A depth stencil smaller than the render target is not valid */
1742 if (width
> src_width
|| height
> src_height
) return;
1744 /* Remove any renderbuffer set if the sizes match */
1745 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1746 || (width
== src_width
&& height
== src_height
))
1748 surface
->current_renderbuffer
= NULL
;
1752 /* Look if we've already got a renderbuffer of the correct dimensions */
1753 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1755 if (entry
->width
== width
&& entry
->height
== height
)
1757 renderbuffer
= entry
->id
;
1758 surface
->current_renderbuffer
= entry
;
1765 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
1766 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
1767 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
1768 surface
->resource
.format
->glInternal
, width
, height
);
1770 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
1771 entry
->width
= width
;
1772 entry
->height
= height
;
1773 entry
->id
= renderbuffer
;
1774 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
1776 surface
->current_renderbuffer
= entry
;
1779 checkGLcall("set_compatible_renderbuffer");
1782 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
1784 const struct wined3d_swapchain
*swapchain
= surface
->container
->swapchain
;
1786 TRACE("surface %p.\n", surface
);
1790 ERR("Surface %p is not on a swapchain.\n", surface
);
1794 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
->container
)
1796 if (swapchain
->render_to_fbo
)
1798 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1799 return GL_COLOR_ATTACHMENT0
;
1801 TRACE("Returning GL_BACK\n");
1804 else if (surface
->container
== swapchain
->front_buffer
)
1806 TRACE("Returning GL_FRONT\n");
1810 FIXME("Higher back buffer, returning GL_BACK\n");
1814 void surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
1816 DWORD location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
1818 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
1820 if (surface
->resource
.pool
== WINED3D_POOL_SCRATCH
)
1821 ERR("Not supported on scratch surfaces.\n");
1823 if (surface
->locations
& location
)
1825 TRACE("surface is already in texture\n");
1828 TRACE("Reloading because surface is dirty.\n");
1830 surface_load_location(surface
, location
);
1831 surface_evict_sysmem(surface
);
1834 /* See also float_16_to_32() in wined3d_private.h */
1835 static inline unsigned short float_32_to_16(const float *in
)
1838 float tmp
= fabsf(*in
);
1839 unsigned int mantissa
;
1842 /* Deal with special numbers */
1848 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
1850 if (tmp
< powf(2, 10))
1856 } while (tmp
< powf(2, 10));
1858 else if (tmp
>= powf(2, 11))
1864 } while (tmp
>= powf(2, 11));
1867 mantissa
= (unsigned int)tmp
;
1868 if (tmp
- mantissa
>= 0.5f
)
1869 ++mantissa
; /* Round to nearest, away from zero. */
1871 exp
+= 10; /* Normalize the mantissa. */
1872 exp
+= 15; /* Exponent is encoded with excess 15. */
1874 if (exp
> 30) /* too big */
1876 ret
= 0x7c00; /* INF */
1880 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1883 mantissa
= mantissa
>> 1;
1886 ret
= mantissa
& 0x3ff;
1890 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
1893 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
1897 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
1899 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
1901 return wined3d_texture_incref(surface
->container
);
1904 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
1906 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
1908 return wined3d_texture_decref(surface
->container
);
1911 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
1913 TRACE("surface %p.\n", surface
);
1915 if (!surface
->resource
.device
->d3d_initialized
)
1917 ERR("D3D not initialized.\n");
1921 wined3d_texture_preload(surface
->container
);
1924 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
1926 TRACE("surface %p.\n", surface
);
1928 return surface
->resource
.parent
;
1931 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
1933 TRACE("surface %p.\n", surface
);
1935 return &surface
->resource
;
1938 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
1940 TRACE("surface %p, flags %#x.\n", surface
, flags
);
1944 case WINEDDGBS_CANBLT
:
1945 case WINEDDGBS_ISBLTDONE
:
1949 return WINED3DERR_INVALIDCALL
;
1953 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
1955 TRACE("surface %p, flags %#x.\n", surface
, flags
);
1957 /* XXX: DDERR_INVALIDSURFACETYPE */
1961 case WINEDDGFS_CANFLIP
:
1962 case WINEDDGFS_ISFLIPDONE
:
1966 return WINED3DERR_INVALIDCALL
;
1970 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
1972 TRACE("surface %p.\n", surface
);
1974 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
1975 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
1978 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
1980 TRACE("surface %p.\n", surface
);
1982 surface
->flags
&= ~SFLAG_LOST
;
1986 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
1988 unsigned int alignment
;
1991 TRACE("surface %p.\n", surface
);
1994 return surface
->pitch
;
1996 alignment
= surface
->resource
.device
->surface_alignment
;
1997 pitch
= wined3d_format_calculate_pitch(surface
->resource
.format
, surface
->resource
.width
);
1998 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
2000 TRACE("Returning %u.\n", pitch
);
2005 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
2009 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
2011 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2013 WARN("Not an overlay surface.\n");
2014 return WINEDDERR_NOTAOVERLAYSURFACE
;
2017 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
2018 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
2019 surface
->overlay_destrect
.left
= x
;
2020 surface
->overlay_destrect
.top
= y
;
2021 surface
->overlay_destrect
.right
= x
+ w
;
2022 surface
->overlay_destrect
.bottom
= y
+ h
;
2027 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
2029 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
2031 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2033 TRACE("Not an overlay surface.\n");
2034 return WINEDDERR_NOTAOVERLAYSURFACE
;
2037 if (!surface
->overlay_dest
)
2039 TRACE("Overlay not visible.\n");
2042 return WINEDDERR_OVERLAYNOTVISIBLE
;
2045 *x
= surface
->overlay_destrect
.left
;
2046 *y
= surface
->overlay_destrect
.top
;
2048 TRACE("Returning position %d, %d.\n", *x
, *y
);
2053 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
2054 DWORD flags
, struct wined3d_surface
*ref
)
2056 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
2058 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2060 TRACE("Not an overlay surface.\n");
2061 return WINEDDERR_NOTAOVERLAYSURFACE
;
2067 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
2068 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
2070 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2071 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
2073 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2075 WARN("Not an overlay surface.\n");
2076 return WINEDDERR_NOTAOVERLAYSURFACE
;
2078 else if (!dst_surface
)
2080 WARN("Dest surface is NULL.\n");
2081 return WINED3DERR_INVALIDCALL
;
2086 surface
->overlay_srcrect
= *src_rect
;
2090 surface
->overlay_srcrect
.left
= 0;
2091 surface
->overlay_srcrect
.top
= 0;
2092 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
2093 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
2098 surface
->overlay_destrect
= *dst_rect
;
2102 surface
->overlay_destrect
.left
= 0;
2103 surface
->overlay_destrect
.top
= 0;
2104 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
2105 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
2108 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
2110 surface
->overlay_dest
= NULL
;
2111 list_remove(&surface
->overlay_entry
);
2114 if (flags
& WINEDDOVER_SHOW
)
2116 if (surface
->overlay_dest
!= dst_surface
)
2118 surface
->overlay_dest
= dst_surface
;
2119 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
2122 else if (flags
& WINEDDOVER_HIDE
)
2124 /* tests show that the rectangles are erased on hide */
2125 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
2126 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
2127 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
2128 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
2129 surface
->overlay_dest
= NULL
;
2135 HRESULT
wined3d_surface_update_desc(struct wined3d_surface
*surface
,
2136 const struct wined3d_gl_info
*gl_info
, void *mem
, unsigned int pitch
)
2138 struct wined3d_resource
*texture_resource
= &surface
->container
->resource
;
2139 unsigned int width
, height
;
2140 BOOL create_dib
= FALSE
;
2141 DWORD valid_location
= 0;
2144 if (surface
->flags
& SFLAG_DIBSECTION
)
2146 DeleteDC(surface
->hDC
);
2147 DeleteObject(surface
->dib
.DIBsection
);
2148 surface
->dib
.bitmap_data
= NULL
;
2149 surface
->flags
&= ~SFLAG_DIBSECTION
;
2153 surface
->locations
= 0;
2154 wined3d_resource_free_sysmem(&surface
->resource
);
2156 width
= texture_resource
->width
;
2157 height
= texture_resource
->height
;
2158 surface
->resource
.width
= width
;
2159 surface
->resource
.height
= height
;
2160 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
2161 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
2163 surface
->pow2Width
= width
;
2164 surface
->pow2Height
= height
;
2168 surface
->pow2Width
= surface
->pow2Height
= 1;
2169 while (surface
->pow2Width
< width
)
2170 surface
->pow2Width
<<= 1;
2171 while (surface
->pow2Height
< height
)
2172 surface
->pow2Height
<<= 1;
2175 if (surface
->pow2Width
!= width
|| surface
->pow2Height
!= height
)
2176 surface
->flags
|= SFLAG_NONPOW2
;
2178 surface
->flags
&= ~SFLAG_NONPOW2
;
2180 if ((surface
->user_memory
= mem
))
2182 surface
->resource
.map_binding
= WINED3D_LOCATION_USER_MEMORY
;
2183 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
2185 surface
->pitch
= pitch
;
2186 surface
->resource
.format
= texture_resource
->format
;
2187 surface
->resource
.multisample_type
= texture_resource
->multisample_type
;
2188 surface
->resource
.multisample_quality
= texture_resource
->multisample_quality
;
2191 surface
->resource
.size
= height
* surface
->pitch
;
2195 /* User memory surfaces don't have the regular surface alignment. */
2196 surface
->resource
.size
= wined3d_format_calculate_size(texture_resource
->format
,
2197 1, width
, height
, 1);
2198 surface
->pitch
= wined3d_format_calculate_pitch(texture_resource
->format
, width
);
2201 /* The format might be changed to a format that needs conversion.
2202 * If the surface didn't use PBOs previously but could now, don't
2203 * change it - whatever made us not use PBOs might come back, e.g.
2205 if (surface
->resource
.map_binding
== WINED3D_LOCATION_BUFFER
&& !surface_use_pbo(surface
))
2206 surface
->resource
.map_binding
= create_dib
? WINED3D_LOCATION_DIB
: WINED3D_LOCATION_SYSMEM
;
2210 if (FAILED(hr
= surface_create_dib_section(surface
)))
2212 ERR("Failed to create dib section, hr %#x.\n", hr
);
2215 if (!valid_location
)
2216 valid_location
= WINED3D_LOCATION_DIB
;
2219 if (!valid_location
)
2221 surface_prepare_system_memory(surface
);
2222 valid_location
= WINED3D_LOCATION_SYSMEM
;
2225 surface_validate_location(surface
, valid_location
);
2230 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
2231 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2233 unsigned short *dst_s
;
2237 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2239 for (y
= 0; y
< h
; ++y
)
2241 src_f
= (const float *)(src
+ y
* pitch_in
);
2242 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
2243 for (x
= 0; x
< w
; ++x
)
2245 dst_s
[x
] = float_32_to_16(src_f
+ x
);
2250 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2251 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2253 static const unsigned char convert_5to8
[] =
2255 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2256 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2257 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2258 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2260 static const unsigned char convert_6to8
[] =
2262 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2263 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2264 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2265 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2266 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2267 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2268 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2269 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2273 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2275 for (y
= 0; y
< h
; ++y
)
2277 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
2278 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2279 for (x
= 0; x
< w
; ++x
)
2281 WORD pixel
= src_line
[x
];
2282 dst_line
[x
] = 0xff000000
2283 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
2284 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
2285 | convert_5to8
[(pixel
& 0x001f)];
2290 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2291 * in both cases we're just setting the X / Alpha channel to 0xff. */
2292 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2293 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2297 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2299 for (y
= 0; y
< h
; ++y
)
2301 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
2302 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2304 for (x
= 0; x
< w
; ++x
)
2306 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
2311 static inline BYTE
cliptobyte(int x
)
2313 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
2316 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2317 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2319 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2322 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2324 for (y
= 0; y
< h
; ++y
)
2326 const BYTE
*src_line
= src
+ y
* pitch_in
;
2327 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2328 for (x
= 0; x
< w
; ++x
)
2330 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2331 * C = Y - 16; D = U - 128; E = V - 128;
2332 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2333 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2334 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2335 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2336 * U and V are shared between the pixels. */
2337 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2339 d
= (int) src_line
[1] - 128;
2340 e
= (int) src_line
[3] - 128;
2342 g2
= - 100 * d
- 208 * e
+ 128;
2345 c2
= 298 * ((int) src_line
[0] - 16);
2346 dst_line
[x
] = 0xff000000
2347 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
2348 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
2349 | cliptobyte((c2
+ b2
) >> 8); /* blue */
2350 /* Scale RGB values to 0..255 range,
2351 * then clip them if still not in range (may be negative),
2352 * then shift them within DWORD if necessary. */
2358 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
2359 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2362 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2364 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
2366 for (y
= 0; y
< h
; ++y
)
2368 const BYTE
*src_line
= src
+ y
* pitch_in
;
2369 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
2370 for (x
= 0; x
< w
; ++x
)
2372 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2373 * C = Y - 16; D = U - 128; E = V - 128;
2374 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2375 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2376 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2377 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2378 * U and V are shared between the pixels. */
2379 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2381 d
= (int) src_line
[1] - 128;
2382 e
= (int) src_line
[3] - 128;
2384 g2
= - 100 * d
- 208 * e
+ 128;
2387 c2
= 298 * ((int) src_line
[0] - 16);
2388 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
2389 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
2390 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
2391 /* Scale RGB values to 0..255 range,
2392 * then clip them if still not in range (may be negative),
2393 * then shift them within DWORD if necessary. */
2399 struct d3dfmt_converter_desc
2401 enum wined3d_format_id from
, to
;
2402 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
2405 static const struct d3dfmt_converter_desc converters
[] =
2407 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
2408 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
2409 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2410 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2411 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
2412 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
2415 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
2416 enum wined3d_format_id to
)
2420 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
2422 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
2423 return &converters
[i
];
2429 static struct wined3d_texture
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
2431 struct wined3d_map_desc src_map
, dst_map
;
2432 const struct d3dfmt_converter_desc
*conv
;
2433 struct wined3d_texture
*ret
= NULL
;
2434 struct wined3d_resource_desc desc
;
2435 struct wined3d_surface
*dst
;
2437 conv
= find_converter(source
->resource
.format
->id
, to_fmt
);
2440 FIXME("Cannot find a conversion function from format %s to %s.\n",
2441 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
2445 /* FIXME: Multisampled conversion? */
2446 wined3d_resource_get_desc(&source
->resource
, &desc
);
2447 desc
.resource_type
= WINED3D_RTYPE_TEXTURE
;
2448 desc
.format
= to_fmt
;
2450 desc
.pool
= WINED3D_POOL_SCRATCH
;
2451 if (FAILED(wined3d_texture_create(source
->resource
.device
, &desc
, 1,
2452 WINED3D_SURFACE_MAPPABLE
| WINED3D_SURFACE_DISCARD
, NULL
, NULL
, &wined3d_null_parent_ops
, &ret
)))
2454 ERR("Failed to create a destination surface for conversion.\n");
2457 dst
= surface_from_resource(wined3d_texture_get_sub_resource(ret
, 0));
2459 memset(&src_map
, 0, sizeof(src_map
));
2460 memset(&dst_map
, 0, sizeof(dst_map
));
2462 if (FAILED(wined3d_surface_map(source
, &src_map
, NULL
, WINED3D_MAP_READONLY
)))
2464 ERR("Failed to lock the source surface.\n");
2465 wined3d_texture_decref(ret
);
2468 if (FAILED(wined3d_surface_map(dst
, &dst_map
, NULL
, 0)))
2470 ERR("Failed to lock the destination surface.\n");
2471 wined3d_surface_unmap(source
);
2472 wined3d_texture_decref(ret
);
2476 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
2477 source
->resource
.width
, source
->resource
.height
);
2479 wined3d_surface_unmap(dst
);
2480 wined3d_surface_unmap(source
);
2485 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
2486 unsigned int bpp
, UINT pitch
, DWORD color
)
2493 #define COLORFILL_ROW(type) \
2495 type *d = (type *)buf; \
2496 for (x = 0; x < width; ++x) \
2497 d[x] = (type)color; \
2503 COLORFILL_ROW(BYTE
);
2507 COLORFILL_ROW(WORD
);
2513 for (x
= 0; x
< width
; ++x
, d
+= 3)
2515 d
[0] = (color
) & 0xff;
2516 d
[1] = (color
>> 8) & 0xff;
2517 d
[2] = (color
>> 16) & 0xff;
2522 COLORFILL_ROW(DWORD
);
2526 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
2527 return WINED3DERR_NOTAVAILABLE
;
2530 #undef COLORFILL_ROW
2532 /* Now copy first row. */
2534 for (y
= 1; y
< height
; ++y
)
2537 memcpy(buf
, first
, width
* bpp
);
2543 struct wined3d_surface
* CDECL
wined3d_surface_from_resource(struct wined3d_resource
*resource
)
2545 return surface_from_resource(resource
);
2548 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
2550 TRACE("surface %p.\n", surface
);
2552 if (!surface
->resource
.map_count
)
2554 WARN("Trying to unmap unmapped surface.\n");
2555 return WINEDDERR_NOTLOCKED
;
2557 --surface
->resource
.map_count
;
2559 surface
->surface_ops
->surface_unmap(surface
);
2564 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
2565 struct wined3d_map_desc
*map_desc
, const RECT
*rect
, DWORD flags
)
2567 const struct wined3d_format
*format
= surface
->resource
.format
;
2568 struct wined3d_device
*device
= surface
->resource
.device
;
2569 struct wined3d_context
*context
;
2570 const struct wined3d_gl_info
*gl_info
;
2573 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
2574 surface
, map_desc
, wine_dbgstr_rect(rect
), flags
);
2576 if (surface
->resource
.map_count
)
2578 WARN("Surface is already mapped.\n");
2579 return WINED3DERR_INVALIDCALL
;
2582 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && rect
2583 && !surface_check_block_align(surface
, rect
))
2585 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
2586 wine_dbgstr_rect(rect
), format
->block_width
, format
->block_height
);
2588 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
2589 return WINED3DERR_INVALIDCALL
;
2592 ++surface
->resource
.map_count
;
2594 if (!(surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
2595 WARN("Trying to lock unlockable surface.\n");
2597 /* Performance optimization: Count how often a surface is mapped, if it is
2598 * mapped regularly do not throw away the system memory copy. This avoids
2599 * the need to download the surface from OpenGL all the time. The surface
2600 * is still downloaded if the OpenGL texture is changed. Note that this
2601 * only really makes sense for managed textures.*/
2602 if (!(surface
->container
->flags
& WINED3D_TEXTURE_DYNAMIC_MAP
)
2603 && surface
->resource
.map_binding
== WINED3D_LOCATION_SYSMEM
)
2605 if (++surface
->lockCount
> MAXLOCKCOUNT
)
2607 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
2608 surface
->container
->flags
|= WINED3D_TEXTURE_DYNAMIC_MAP
;
2612 surface_prepare_map_memory(surface
);
2613 if (flags
& WINED3D_MAP_DISCARD
)
2615 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2616 wined3d_debug_location(surface
->resource
.map_binding
));
2617 surface_validate_location(surface
, surface
->resource
.map_binding
);
2621 if (surface
->resource
.usage
& WINED3DUSAGE_DYNAMIC
)
2622 WARN_(d3d_perf
)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
2624 surface_load_location(surface
, surface
->resource
.map_binding
);
2627 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
2628 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
2630 switch (surface
->resource
.map_binding
)
2632 case WINED3D_LOCATION_SYSMEM
:
2633 base_memory
= surface
->resource
.heap_memory
;
2636 case WINED3D_LOCATION_USER_MEMORY
:
2637 base_memory
= surface
->user_memory
;
2640 case WINED3D_LOCATION_DIB
:
2641 base_memory
= surface
->dib
.bitmap_data
;
2644 case WINED3D_LOCATION_BUFFER
:
2645 context
= context_acquire(device
, NULL
);
2646 gl_info
= context
->gl_info
;
2648 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, surface
->pbo
));
2649 base_memory
= GL_EXTCALL(glMapBuffer(GL_PIXEL_UNPACK_BUFFER
, GL_READ_WRITE
));
2650 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
2651 checkGLcall("map PBO");
2653 context_release(context
);
2657 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
2661 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
2662 map_desc
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
2664 map_desc
->row_pitch
= wined3d_surface_get_pitch(surface
);
2665 map_desc
->slice_pitch
= 0;
2669 map_desc
->data
= base_memory
;
2670 surface
->lockedRect
.left
= 0;
2671 surface
->lockedRect
.top
= 0;
2672 surface
->lockedRect
.right
= surface
->resource
.width
;
2673 surface
->lockedRect
.bottom
= surface
->resource
.height
;
2677 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
2679 /* Compressed textures are block based, so calculate the offset of
2680 * the block that contains the top-left pixel of the locked rectangle. */
2681 map_desc
->data
= base_memory
2682 + ((rect
->top
/ format
->block_height
) * map_desc
->row_pitch
)
2683 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
2687 map_desc
->data
= base_memory
2688 + (map_desc
->row_pitch
* rect
->top
)
2689 + (rect
->left
* format
->byte_count
);
2691 surface
->lockedRect
.left
= rect
->left
;
2692 surface
->lockedRect
.top
= rect
->top
;
2693 surface
->lockedRect
.right
= rect
->right
;
2694 surface
->lockedRect
.bottom
= rect
->bottom
;
2697 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
2698 TRACE("Returning memory %p, pitch %u.\n", map_desc
->data
, map_desc
->row_pitch
);
2703 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
2707 TRACE("surface %p, dc %p.\n", surface
, dc
);
2709 /* Give more detailed info for ddraw. */
2710 if (surface
->flags
& SFLAG_DCINUSE
)
2711 return WINEDDERR_DCALREADYCREATED
;
2713 /* Can't GetDC if the surface is locked. */
2714 if (surface
->resource
.map_count
)
2715 return WINED3DERR_INVALIDCALL
;
2717 /* Create a DIB section if there isn't a dc yet. */
2720 if (surface
->flags
& SFLAG_CLIENT
)
2722 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
2723 surface_release_client_storage(surface
);
2725 hr
= surface_create_dib_section(surface
);
2727 return WINED3DERR_INVALIDCALL
;
2728 if (!(surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
2729 || surface
->container
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
2731 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
2734 surface_load_location(surface
, WINED3D_LOCATION_DIB
);
2735 surface_invalidate_location(surface
, ~WINED3D_LOCATION_DIB
);
2737 surface
->flags
|= SFLAG_DCINUSE
;
2738 surface
->resource
.map_count
++;
2741 TRACE("Returning dc %p.\n", *dc
);
2746 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
2748 TRACE("surface %p, dc %p.\n", surface
, dc
);
2750 if (!(surface
->flags
& SFLAG_DCINUSE
))
2751 return WINEDDERR_NODC
;
2753 if (surface
->hDC
!= dc
)
2755 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
2757 return WINEDDERR_NODC
;
2760 surface
->resource
.map_count
--;
2761 surface
->flags
&= ~SFLAG_DCINUSE
;
2763 if (surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
2764 || (surface
->container
->flags
& WINED3D_TEXTURE_PIN_SYSMEM
2765 && surface
->resource
.map_binding
!= WINED3D_LOCATION_DIB
))
2767 /* The game Salammbo modifies the surface contents without mapping the surface between
2768 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
2769 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
2770 * Do not only copy the DIB to the map location, but also make sure the map location is
2771 * copied back to the DIB in the next getdc call.
2773 * The same consideration applies to user memory surfaces. */
2774 surface_load_location(surface
, surface
->resource
.map_binding
);
2775 surface_invalidate_location(surface
, WINED3D_LOCATION_DIB
);
2781 static void read_from_framebuffer(struct wined3d_surface
*surface
, DWORD dst_location
)
2783 struct wined3d_device
*device
= surface
->resource
.device
;
2784 const struct wined3d_gl_info
*gl_info
;
2785 struct wined3d_context
*context
;
2787 BYTE
*row
, *top
, *bottom
;
2789 BOOL srcIsUpsideDown
;
2790 struct wined3d_bo_address data
;
2792 surface_get_memory(surface
, &data
, dst_location
);
2794 context
= context_acquire(device
, surface
);
2795 context_apply_blit_state(context
, device
);
2796 gl_info
= context
->gl_info
;
2798 /* Select the correct read buffer, and give some debug output.
2799 * There is no need to keep track of the current read buffer or reset it, every part of the code
2800 * that reads sets the read buffer as desired.
2802 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
2804 /* Mapping the primary render target which is not on a swapchain.
2805 * Read from the back buffer. */
2806 TRACE("Mapping offscreen render target.\n");
2807 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
2808 srcIsUpsideDown
= TRUE
;
2812 /* Onscreen surfaces are always part of a swapchain */
2813 GLenum buffer
= surface_get_gl_buffer(surface
);
2814 TRACE("Mapping %#x buffer.\n", buffer
);
2815 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
2816 checkGLcall("glReadBuffer");
2817 srcIsUpsideDown
= FALSE
;
2820 if (data
.buffer_object
)
2822 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, data
.buffer_object
));
2823 checkGLcall("glBindBuffer");
2826 /* Setup pixel store pack state -- to glReadPixels into the correct place */
2827 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
,
2828 wined3d_surface_get_pitch(surface
) / surface
->resource
.format
->byte_count
);
2829 checkGLcall("glPixelStorei");
2831 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0,
2832 surface
->resource
.width
, surface
->resource
.height
,
2833 surface
->resource
.format
->glFormat
,
2834 surface
->resource
.format
->glType
, data
.addr
);
2835 checkGLcall("glReadPixels");
2837 /* Reset previous pixel store pack state */
2838 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
2839 checkGLcall("glPixelStorei");
2841 if (!srcIsUpsideDown
)
2843 /* glReadPixels returns the image upside down, and there is no way to prevent this.
2844 * Flip the lines in software. */
2845 UINT pitch
= wined3d_surface_get_pitch(surface
);
2847 if (!(row
= HeapAlloc(GetProcessHeap(), 0, pitch
)))
2850 if (data
.buffer_object
)
2852 mem
= GL_EXTCALL(glMapBuffer(GL_PIXEL_PACK_BUFFER
, GL_READ_WRITE
));
2853 checkGLcall("glMapBuffer");
2859 bottom
= mem
+ pitch
* (surface
->resource
.height
- 1);
2860 for (i
= 0; i
< surface
->resource
.height
/ 2; i
++)
2862 memcpy(row
, top
, pitch
);
2863 memcpy(top
, bottom
, pitch
);
2864 memcpy(bottom
, row
, pitch
);
2868 HeapFree(GetProcessHeap(), 0, row
);
2870 if (data
.buffer_object
)
2871 GL_EXTCALL(glUnmapBuffer(GL_PIXEL_PACK_BUFFER
));
2875 if (data
.buffer_object
)
2877 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
2878 checkGLcall("glBindBuffer");
2881 context_release(context
);
2884 /* Read the framebuffer contents into a texture. Note that this function
2885 * doesn't do any kind of flipping. Using this on an onscreen surface will
2886 * result in a flipped D3D texture. */
2887 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
)
2889 struct wined3d_device
*device
= surface
->resource
.device
;
2890 const struct wined3d_gl_info
*gl_info
;
2891 struct wined3d_context
*context
;
2893 context
= context_acquire(device
, surface
);
2894 gl_info
= context
->gl_info
;
2895 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
2897 wined3d_texture_prepare_texture(surface
->container
, context
, srgb
);
2898 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
2900 TRACE("Reading back offscreen render target %p.\n", surface
);
2902 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
2903 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
2905 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(surface
));
2906 checkGLcall("glReadBuffer");
2908 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
2909 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
2910 checkGLcall("glCopyTexSubImage2D");
2912 context_release(context
);
2915 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
2919 if (surface
->rb_multisample
)
2922 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
2923 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
2924 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
2925 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
2926 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
2930 if (surface
->rb_resolved
)
2933 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
2934 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
2935 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
2936 surface
->pow2Width
, surface
->pow2Height
);
2937 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
2941 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
2943 if (front
->container
->level_count
!= 1 || front
->container
->layer_count
!= 1
2944 || back
->container
->level_count
!= 1 || back
->container
->layer_count
!= 1)
2945 ERR("Flip between surfaces %p and %p not supported.\n", front
, back
);
2947 /* Flip the surface contents */
2952 front
->hDC
= back
->hDC
;
2956 /* Flip the DIBsection */
2958 HBITMAP tmp
= front
->dib
.DIBsection
;
2959 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
2960 back
->dib
.DIBsection
= tmp
;
2963 /* Flip the surface data */
2967 tmp
= front
->dib
.bitmap_data
;
2968 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
2969 back
->dib
.bitmap_data
= tmp
;
2971 tmp
= front
->resource
.heap_memory
;
2972 front
->resource
.heap_memory
= back
->resource
.heap_memory
;
2973 back
->resource
.heap_memory
= tmp
;
2978 GLuint tmp_pbo
= front
->pbo
;
2979 front
->pbo
= back
->pbo
;
2980 back
->pbo
= tmp_pbo
;
2983 /* Flip the opengl texture */
2987 tmp
= back
->container
->texture_rgb
.name
;
2988 back
->container
->texture_rgb
.name
= front
->container
->texture_rgb
.name
;
2989 front
->container
->texture_rgb
.name
= tmp
;
2991 tmp
= back
->container
->texture_srgb
.name
;
2992 back
->container
->texture_srgb
.name
= front
->container
->texture_srgb
.name
;
2993 front
->container
->texture_srgb
.name
= tmp
;
2995 tmp
= back
->rb_multisample
;
2996 back
->rb_multisample
= front
->rb_multisample
;
2997 front
->rb_multisample
= tmp
;
2999 tmp
= back
->rb_resolved
;
3000 back
->rb_resolved
= front
->rb_resolved
;
3001 front
->rb_resolved
= tmp
;
3003 resource_unload(&back
->resource
);
3004 resource_unload(&front
->resource
);
3008 DWORD tmp_flags
= back
->flags
;
3009 back
->flags
= front
->flags
;
3010 front
->flags
= tmp_flags
;
3012 tmp_flags
= back
->locations
;
3013 back
->locations
= front
->locations
;
3014 front
->locations
= tmp_flags
;
3018 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3019 * pixel copy calls. */
3020 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3021 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3023 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3024 const struct wined3d_gl_info
*gl_info
;
3026 struct wined3d_context
*context
;
3027 BOOL upsidedown
= FALSE
;
3028 RECT dst_rect
= *dst_rect_in
;
3030 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3031 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3033 if(dst_rect
.top
> dst_rect
.bottom
) {
3034 UINT tmp
= dst_rect
.bottom
;
3035 dst_rect
.bottom
= dst_rect
.top
;
3040 context
= context_acquire(device
, src_surface
);
3041 gl_info
= context
->gl_info
;
3042 context_apply_blit_state(context
, device
);
3043 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3045 /* Bind the target texture */
3046 context_bind_texture(context
, dst_surface
->container
->target
, dst_surface
->container
->texture_rgb
.name
);
3047 if (wined3d_resource_is_offscreen(&src_surface
->container
->resource
))
3049 TRACE("Reading from an offscreen target\n");
3050 upsidedown
= !upsidedown
;
3051 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3055 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3057 checkGLcall("glReadBuffer");
3059 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
3060 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
3062 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3064 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3066 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3067 ERR("Texture filtering not supported in direct blit.\n");
3069 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3070 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3072 ERR("Texture filtering not supported in direct blit\n");
3076 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3077 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3079 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3080 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3081 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
3082 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
3083 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3088 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
3089 /* I have to process this row by row to swap the image,
3090 * otherwise it would be upside down, so stretching in y direction
3091 * doesn't cost extra time
3093 * However, stretching in x direction can be avoided if not necessary
3095 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
3096 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3098 /* Well, that stuff works, but it's very slow.
3099 * find a better way instead
3103 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
3105 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3106 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
3107 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
3112 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3113 dst_rect
.left
/* x offset */, row
/* y offset */,
3114 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
3118 checkGLcall("glCopyTexSubImage2D");
3120 context_release(context
);
3122 /* The texture is now most up to date - If the surface is a render target
3123 * and has a drawable, this path is never entered. */
3124 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3125 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3128 /* Uses the hardware to stretch and flip the image */
3129 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3130 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3132 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3133 GLuint src
, backup
= 0;
3134 float left
, right
, top
, bottom
; /* Texture coordinates */
3135 UINT fbwidth
= src_surface
->resource
.width
;
3136 UINT fbheight
= src_surface
->resource
.height
;
3137 const struct wined3d_gl_info
*gl_info
;
3138 struct wined3d_context
*context
;
3139 GLenum drawBuffer
= GL_BACK
;
3140 GLenum texture_target
;
3141 BOOL noBackBufferBackup
;
3143 BOOL upsidedown
= FALSE
;
3144 RECT dst_rect
= *dst_rect_in
;
3146 TRACE("Using hwstretch blit\n");
3147 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3148 context
= context_acquire(device
, src_surface
);
3149 gl_info
= context
->gl_info
;
3150 context_apply_blit_state(context
, device
);
3151 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3153 src_offscreen
= wined3d_resource_is_offscreen(&src_surface
->container
->resource
);
3154 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
3155 if (!noBackBufferBackup
&& !src_surface
->container
->texture_rgb
.name
)
3157 /* Get it a description */
3158 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3161 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3162 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3164 if (context
->aux_buffers
>= 2)
3166 /* Got more than one aux buffer? Use the 2nd aux buffer */
3167 drawBuffer
= GL_AUX1
;
3169 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
3171 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3172 drawBuffer
= GL_AUX0
;
3175 if (noBackBufferBackup
)
3177 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
3178 checkGLcall("glGenTextures");
3179 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3180 texture_target
= GL_TEXTURE_2D
;
3184 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3185 * we are reading from the back buffer, the backup can be used as source texture
3187 texture_target
= src_surface
->texture_target
;
3188 context_bind_texture(context
, texture_target
, src_surface
->container
->texture_rgb
.name
);
3189 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
3190 checkGLcall("glEnable(texture_target)");
3192 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3193 src_surface
->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
3196 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3197 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3199 if(dst_rect
.top
> dst_rect
.bottom
) {
3200 UINT tmp
= dst_rect
.bottom
;
3201 dst_rect
.bottom
= dst_rect
.top
;
3208 TRACE("Reading from an offscreen target\n");
3209 upsidedown
= !upsidedown
;
3210 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3214 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3217 /* TODO: Only back up the part that will be overwritten */
3218 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3220 checkGLcall("glCopyTexSubImage2D");
3222 /* No issue with overriding these - the sampler is dirty due to blit usage */
3223 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
, wined3d_gl_mag_filter(filter
));
3224 checkGLcall("glTexParameteri");
3225 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
3226 wined3d_gl_min_mip_filter(filter
, WINED3D_TEXF_NONE
));
3227 checkGLcall("glTexParameteri");
3229 if (!src_surface
->container
->swapchain
3230 || src_surface
->container
== src_surface
->container
->swapchain
->back_buffers
[0])
3232 src
= backup
? backup
: src_surface
->container
->texture_rgb
.name
;
3236 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
3237 checkGLcall("glReadBuffer(GL_FRONT)");
3239 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
3240 checkGLcall("glGenTextures(1, &src)");
3241 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
3243 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3244 * out for power of 2 sizes
3246 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
3247 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
3248 checkGLcall("glTexImage2D");
3249 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3251 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3252 checkGLcall("glTexParameteri");
3253 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3254 checkGLcall("glTexParameteri");
3256 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
3257 checkGLcall("glReadBuffer(GL_BACK)");
3259 if (texture_target
!= GL_TEXTURE_2D
)
3261 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3262 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3263 texture_target
= GL_TEXTURE_2D
;
3266 checkGLcall("glEnd and previous");
3268 left
= src_rect
->left
;
3269 right
= src_rect
->right
;
3273 top
= src_surface
->resource
.height
- src_rect
->top
;
3274 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
3278 top
= src_surface
->resource
.height
- src_rect
->bottom
;
3279 bottom
= src_surface
->resource
.height
- src_rect
->top
;
3282 if (src_surface
->container
->flags
& WINED3D_TEXTURE_NORMALIZED_COORDS
)
3284 left
/= src_surface
->pow2Width
;
3285 right
/= src_surface
->pow2Width
;
3286 top
/= src_surface
->pow2Height
;
3287 bottom
/= src_surface
->pow2Height
;
3290 /* draw the source texture stretched and upside down. The correct surface is bound already */
3291 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
3292 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
3294 context_set_draw_buffer(context
, drawBuffer
);
3295 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
3297 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3299 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
3300 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3303 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
3304 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
3307 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
3308 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3311 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
3312 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
3313 gl_info
->gl_ops
.gl
.p_glEnd();
3314 checkGLcall("glEnd and previous");
3316 if (texture_target
!= dst_surface
->texture_target
)
3318 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3319 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
3320 texture_target
= dst_surface
->texture_target
;
3323 /* Now read the stretched and upside down image into the destination texture */
3324 context_bind_texture(context
, texture_target
, dst_surface
->container
->texture_rgb
.name
);
3325 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
3327 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
3328 0, 0, /* We blitted the image to the origin */
3329 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3330 checkGLcall("glCopyTexSubImage2D");
3332 if (drawBuffer
== GL_BACK
)
3334 /* Write the back buffer backup back. */
3337 if (texture_target
!= GL_TEXTURE_2D
)
3339 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3340 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3341 texture_target
= GL_TEXTURE_2D
;
3343 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3347 if (texture_target
!= src_surface
->texture_target
)
3349 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3350 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
3351 texture_target
= src_surface
->texture_target
;
3353 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->container
->texture_rgb
.name
);
3356 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3358 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
3359 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
3362 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
3363 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3366 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
3367 (float)fbheight
/ (float)src_surface
->pow2Height
);
3368 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
3371 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
3372 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
3373 gl_info
->gl_ops
.gl
.p_glEnd();
3375 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3376 checkGLcall("glDisable(texture_target)");
3379 if (src
!= src_surface
->container
->texture_rgb
.name
&& src
!= backup
)
3381 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
3382 checkGLcall("glDeleteTextures(1, &src)");
3386 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
3387 checkGLcall("glDeleteTextures(1, &backup)");
3390 if (wined3d_settings
.strict_draw_ordering
)
3391 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3393 context_release(context
);
3395 /* The texture is now most up to date - If the surface is a render target
3396 * and has a drawable, this path is never entered. */
3397 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3398 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3401 /* Front buffer coordinates are always full screen coordinates, but our GL
3402 * drawable is limited to the window's client area. The sysmem and texture
3403 * copies do have the full screen size. Note that GL has a bottom-left
3404 * origin, while D3D has a top-left origin. */
3405 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
3407 UINT drawable_height
;
3409 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
3411 POINT offset
= {0, 0};
3414 ScreenToClient(window
, &offset
);
3415 OffsetRect(rect
, offset
.x
, offset
.y
);
3417 GetClientRect(window
, &windowsize
);
3418 drawable_height
= windowsize
.bottom
- windowsize
.top
;
3422 drawable_height
= surface
->resource
.height
;
3425 rect
->top
= drawable_height
- rect
->top
;
3426 rect
->bottom
= drawable_height
- rect
->bottom
;
3429 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
3430 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
3431 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
3432 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
3434 const struct wined3d_gl_info
*gl_info
;
3435 struct wined3d_context
*context
;
3436 RECT src_rect
, dst_rect
;
3438 src_rect
= *src_rect_in
;
3439 dst_rect
= *dst_rect_in
;
3441 context
= context_acquire(device
, dst_surface
);
3442 gl_info
= context
->gl_info
;
3444 /* Make sure the surface is up-to-date. This should probably use
3445 * surface_load_location() and worry about the destination surface too,
3446 * unless we're overwriting it completely. */
3447 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3449 /* Activate the destination context, set it up for blitting */
3450 context_apply_blit_state(context
, device
);
3452 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
3453 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
3455 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
3459 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
3460 checkGLcall("glEnable(GL_ALPHA_TEST)");
3462 /* For P8 surfaces, the alpha component contains the palette index.
3463 * Which means that the colorkey is one of the palette entries. In
3464 * other cases pixels that should be masked away have alpha set to 0. */
3465 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3466 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
3467 (float)src_surface
->container
->src_blt_color_key
.color_space_low_value
/ 255.0f
);
3469 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
3470 checkGLcall("glAlphaFunc");
3474 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3475 checkGLcall("glDisable(GL_ALPHA_TEST)");
3478 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
3482 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3483 checkGLcall("glDisable(GL_ALPHA_TEST)");
3486 /* Leave the opengl state valid for blitting */
3487 device
->blitter
->unset_shader(context
->gl_info
);
3489 if (wined3d_settings
.strict_draw_ordering
3490 || (dst_surface
->container
->swapchain
3491 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
3492 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3494 context_release(context
);
3497 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
3499 struct wined3d_device
*device
= s
->resource
.device
;
3500 const struct blit_shader
*blitter
;
3502 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
3503 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
3506 FIXME("No blitter is capable of performing the requested color fill operation.\n");
3507 return WINED3DERR_INVALIDCALL
;
3510 return blitter
->color_fill(device
, s
, rect
, color
);
3513 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3514 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
3515 enum wined3d_texture_filter_type filter
)
3517 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3518 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->fb
.render_targets
[0]);
3519 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
3520 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
3522 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
3523 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
3524 flags
, DDBltFx
, debug_d3dtexturefiltertype(filter
));
3526 /* Get the swapchain. One of the surfaces has to be a primary surface */
3527 if (dst_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3529 WARN("Destination is in sysmem, rejecting gl blt\n");
3530 return WINED3DERR_INVALIDCALL
;
3533 dst_swapchain
= dst_surface
->container
->swapchain
;
3537 if (src_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3539 WARN("Src is in sysmem, rejecting gl blt\n");
3540 return WINED3DERR_INVALIDCALL
;
3543 src_swapchain
= src_surface
->container
->swapchain
;
3547 src_swapchain
= NULL
;
3550 /* Early sort out of cases where no render target is used */
3551 if (!dst_swapchain
&& !src_swapchain
&& src_surface
!= rt
&& dst_surface
!= rt
)
3553 TRACE("No surface is render target, not using hardware blit.\n");
3554 return WINED3DERR_INVALIDCALL
;
3557 /* No destination color keying supported */
3558 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
3560 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3561 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3562 return WINED3DERR_INVALIDCALL
;
3565 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
3567 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3568 return WINED3DERR_INVALIDCALL
;
3571 if (dst_swapchain
&& src_swapchain
)
3573 FIXME("Implement hardware blit between two different swapchains\n");
3574 return WINED3DERR_INVALIDCALL
;
3579 /* Handled with regular texture -> swapchain blit */
3580 if (src_surface
== rt
)
3581 TRACE("Blit from active render target to a swapchain\n");
3583 else if (src_swapchain
&& dst_surface
== rt
)
3585 FIXME("Implement blit from a swapchain to the active render target\n");
3586 return WINED3DERR_INVALIDCALL
;
3589 if ((src_swapchain
|| src_surface
== rt
) && !dst_swapchain
)
3591 /* Blit from render target to texture */
3594 /* P8 read back is not implemented */
3595 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3596 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3598 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3599 return WINED3DERR_INVALIDCALL
;
3602 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
3604 TRACE("Color keying not supported by frame buffer to texture blit\n");
3605 return WINED3DERR_INVALIDCALL
;
3606 /* Destination color key is checked above */
3609 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
3614 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3615 * flip the image nor scale it.
3617 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3618 * -> If the app wants an image width an unscaled width, copy it line per line
3619 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
3620 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3621 * back buffer. This is slower than reading line per line, thus not used for flipping
3622 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3623 * pixel by pixel. */
3624 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
3625 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
3627 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
3628 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
3632 TRACE("Using hardware stretching to flip / stretch the texture.\n");
3633 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
3636 surface_evict_sysmem(dst_surface
);
3640 else if (src_surface
)
3642 /* Blit from offscreen surface to render target */
3643 struct wined3d_color_key old_blt_key
= src_surface
->container
->src_blt_color_key
;
3644 DWORD old_color_key_flags
= src_surface
->container
->color_key_flags
;
3646 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
3648 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
3649 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
3650 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
3652 FIXME("Unsupported blit operation falling back to software\n");
3653 return WINED3DERR_INVALIDCALL
;
3656 /* Color keying: Check if we have to do a color keyed blt,
3657 * and if not check if a color key is activated.
3659 * Just modify the color keying parameters in the surface and restore them afterwards
3660 * The surface keeps track of the color key last used to load the opengl surface.
3661 * PreLoad will catch the change to the flags and color key and reload if necessary.
3663 if (flags
& WINEDDBLT_KEYSRC
)
3665 /* Use color key from surface */
3667 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
3669 /* Use color key from DDBltFx */
3670 wined3d_texture_set_color_key(src_surface
->container
, WINED3D_CKEY_SRC_BLT
, &DDBltFx
->ddckSrcColorkey
);
3674 /* Do not use color key */
3675 wined3d_texture_set_color_key(src_surface
->container
, WINED3D_CKEY_SRC_BLT
, NULL
);
3678 surface_blt_to_drawable(device
, filter
,
3679 flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_ALPHATEST
),
3680 src_surface
, src_rect
, dst_surface
, dst_rect
);
3682 /* Restore the color key parameters */
3683 wined3d_texture_set_color_key(src_surface
->container
, WINED3D_CKEY_SRC_BLT
,
3684 (old_color_key_flags
& WINED3D_CKEY_SRC_BLT
) ? &old_blt_key
: NULL
);
3686 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
3687 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
3692 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3693 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3694 return WINED3DERR_INVALIDCALL
;
3697 /* Context activation is done by the caller. */
3698 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
3699 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
3701 struct wined3d_device
*device
= surface
->resource
.device
;
3702 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
3703 GLint compare_mode
= GL_NONE
;
3704 struct blt_info info
;
3705 GLint old_binding
= 0;
3708 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
3710 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
3711 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
3712 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3713 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
3714 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
3715 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
3716 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
3717 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
3718 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
3719 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
3720 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
3722 SetRect(&rect
, 0, h
, w
, 0);
3723 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
3724 context_active_texture(context
, context
->gl_info
, 0);
3725 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
3726 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
3727 if (gl_info
->supported
[ARB_SHADOW
])
3729 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
3730 if (compare_mode
!= GL_NONE
)
3731 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
3734 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
3735 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
3737 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
3738 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
3739 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
3740 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
3741 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
3742 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
3743 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
3744 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
3745 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
3746 gl_info
->gl_ops
.gl
.p_glEnd();
3748 if (compare_mode
!= GL_NONE
)
3749 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
3750 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
3752 gl_info
->gl_ops
.gl
.p_glPopAttrib();
3754 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
3757 void surface_modify_ds_location(struct wined3d_surface
*surface
,
3758 DWORD location
, UINT w
, UINT h
)
3760 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
3762 if (((surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
3763 || (!(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
3764 wined3d_texture_set_dirty(surface
->container
);
3766 surface
->ds_current_size
.cx
= w
;
3767 surface
->ds_current_size
.cy
= h
;
3768 surface
->locations
= location
;
3771 /* Context activation is done by the caller. */
3772 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
3774 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
3775 struct wined3d_device
*device
= surface
->resource
.device
;
3778 TRACE("surface %p, new location %#x.\n", surface
, location
);
3780 /* TODO: Make this work for modes other than FBO */
3781 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
3783 if (!(surface
->locations
& location
))
3785 w
= surface
->ds_current_size
.cx
;
3786 h
= surface
->ds_current_size
.cy
;
3787 surface
->ds_current_size
.cx
= 0;
3788 surface
->ds_current_size
.cy
= 0;
3792 w
= surface
->resource
.width
;
3793 h
= surface
->resource
.height
;
3796 if (surface
->ds_current_size
.cx
== surface
->resource
.width
3797 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
3799 TRACE("Location (%#x) is already up to date.\n", location
);
3803 if (surface
->current_renderbuffer
)
3805 FIXME("Not supported with fixed up depth stencil.\n");
3809 if (surface
->locations
& WINED3D_LOCATION_DISCARDED
)
3811 TRACE("Surface was discarded, no need copy data.\n");
3814 case WINED3D_LOCATION_TEXTURE_RGB
:
3815 wined3d_texture_prepare_texture(surface
->container
, context
, FALSE
);
3817 case WINED3D_LOCATION_RB_MULTISAMPLE
:
3818 surface_prepare_rb(surface
, gl_info
, TRUE
);
3820 case WINED3D_LOCATION_DRAWABLE
:
3824 FIXME("Unhandled location %#x\n", location
);
3826 surface
->locations
&= ~WINED3D_LOCATION_DISCARDED
;
3827 surface
->locations
|= location
;
3828 surface
->ds_current_size
.cx
= surface
->resource
.width
;
3829 surface
->ds_current_size
.cy
= surface
->resource
.height
;
3833 if (!surface
->locations
)
3835 FIXME("No up to date depth stencil location.\n");
3836 surface
->locations
|= location
;
3837 surface
->ds_current_size
.cx
= surface
->resource
.width
;
3838 surface
->ds_current_size
.cy
= surface
->resource
.height
;
3842 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
3844 GLint old_binding
= 0;
3847 /* The render target is allowed to be smaller than the depth/stencil
3848 * buffer, so the onscreen depth/stencil buffer is potentially smaller
3849 * than the offscreen surface. Don't overwrite the offscreen surface
3850 * with undefined data. */
3851 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
3852 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
3854 TRACE("Copying onscreen depth buffer to depth texture.\n");
3856 if (!device
->depth_blt_texture
)
3857 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
3859 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
3860 * directly on the FBO texture. That's because we need to flip. */
3861 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
3862 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
3863 NULL
, WINED3D_LOCATION_DRAWABLE
);
3864 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
3866 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
3867 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
3871 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
3872 bind_target
= GL_TEXTURE_2D
;
3874 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
3875 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
3876 * internal format, because the internal format might include stencil
3877 * data. In principle we should copy stencil data as well, but unless
3878 * the driver supports stencil export it's hard to do, and doesn't
3879 * seem to be needed in practice. If the hardware doesn't support
3880 * writing stencil data, the glCopyTexImage2D() call might trigger
3881 * software fallbacks. */
3882 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
3883 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3884 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3885 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
3886 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
3887 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
3888 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
3889 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
3891 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
3892 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3893 context_set_draw_buffer(context
, GL_NONE
);
3895 /* Do the actual blit */
3896 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
3897 checkGLcall("depth_blt");
3899 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
3901 if (wined3d_settings
.strict_draw_ordering
)
3902 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3904 else if (location
== WINED3D_LOCATION_DRAWABLE
)
3906 TRACE("Copying depth texture to onscreen depth buffer.\n");
3908 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
3909 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
3910 NULL
, WINED3D_LOCATION_DRAWABLE
);
3911 surface_depth_blt(surface
, context
, surface
->container
->texture_rgb
.name
,
3912 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
3913 checkGLcall("depth_blt");
3915 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
3917 if (wined3d_settings
.strict_draw_ordering
)
3918 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3922 ERR("Invalid location (%#x) specified.\n", location
);
3925 surface
->locations
|= location
;
3926 surface
->ds_current_size
.cx
= surface
->resource
.width
;
3927 surface
->ds_current_size
.cy
= surface
->resource
.height
;
3930 void surface_validate_location(struct wined3d_surface
*surface
, DWORD location
)
3932 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
3934 surface
->locations
|= location
;
3937 void surface_invalidate_location(struct wined3d_surface
*surface
, DWORD location
)
3939 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
3941 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
3942 wined3d_texture_set_dirty(surface
->container
);
3943 surface
->locations
&= ~location
;
3945 if (!surface
->locations
)
3946 ERR("Surface %p does not have any up to date location.\n", surface
);
3949 static DWORD
resource_access_from_location(DWORD location
)
3953 case WINED3D_LOCATION_SYSMEM
:
3954 case WINED3D_LOCATION_USER_MEMORY
:
3955 case WINED3D_LOCATION_DIB
:
3956 case WINED3D_LOCATION_BUFFER
:
3957 return WINED3D_RESOURCE_ACCESS_CPU
;
3959 case WINED3D_LOCATION_DRAWABLE
:
3960 case WINED3D_LOCATION_TEXTURE_SRGB
:
3961 case WINED3D_LOCATION_TEXTURE_RGB
:
3962 case WINED3D_LOCATION_RB_MULTISAMPLE
:
3963 case WINED3D_LOCATION_RB_RESOLVED
:
3964 return WINED3D_RESOURCE_ACCESS_GPU
;
3967 FIXME("Unhandled location %#x.\n", location
);
3972 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
3974 struct wined3d_device
*device
= surface
->resource
.device
;
3975 struct wined3d_context
*context
;
3976 const struct wined3d_gl_info
*gl_info
;
3977 struct wined3d_bo_address dst
, src
;
3978 UINT size
= surface
->resource
.size
;
3980 surface_get_memory(surface
, &dst
, location
);
3981 surface_get_memory(surface
, &src
, surface
->locations
);
3983 if (dst
.buffer_object
)
3985 context
= context_acquire(device
, NULL
);
3986 gl_info
= context
->gl_info
;
3987 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, dst
.buffer_object
));
3988 GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER
, 0, size
, src
.addr
));
3989 GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER
, 0));
3990 checkGLcall("Upload PBO");
3991 context_release(context
);
3994 if (src
.buffer_object
)
3996 context
= context_acquire(device
, NULL
);
3997 gl_info
= context
->gl_info
;
3998 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, src
.buffer_object
));
3999 GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER
, 0, size
, dst
.addr
));
4000 GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER
, 0));
4001 checkGLcall("Download PBO");
4002 context_release(context
);
4005 memcpy(dst
.addr
, src
.addr
, size
);
4008 static void surface_load_sysmem(struct wined3d_surface
*surface
,
4009 const struct wined3d_gl_info
*gl_info
, DWORD dst_location
)
4011 if (surface
->locations
& surface_simple_locations
)
4013 surface_copy_simple_location(surface
, dst_location
);
4017 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
4018 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4020 /* Download the surface to system memory. */
4021 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4023 struct wined3d_device
*device
= surface
->resource
.device
;
4024 struct wined3d_context
*context
;
4026 /* TODO: Use already acquired context when possible. */
4027 context
= context_acquire(device
, NULL
);
4029 wined3d_texture_bind_and_dirtify(surface
->container
, context
,
4030 !(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
4031 surface_download_data(surface
, gl_info
, dst_location
);
4033 context_release(context
);
4038 if (surface
->locations
& WINED3D_LOCATION_DRAWABLE
)
4040 read_from_framebuffer(surface
, dst_location
);
4044 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4045 surface
, wined3d_debug_location(surface
->locations
));
4048 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
4049 const struct wined3d_gl_info
*gl_info
)
4053 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
4054 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
4056 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4057 return WINED3DERR_INVALIDCALL
;
4060 surface_get_rect(surface
, NULL
, &r
);
4061 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4062 surface_blt_to_drawable(surface
->resource
.device
,
4063 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
4068 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
4069 const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
4071 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4072 struct wined3d_device
*device
= surface
->resource
.device
;
4073 const struct wined3d_color_key_conversion
*conversion
;
4074 struct wined3d_texture
*texture
= surface
->container
;
4075 struct wined3d_context
*context
;
4076 UINT width
, src_pitch
, dst_pitch
;
4077 struct wined3d_bo_address data
;
4078 struct wined3d_format format
;
4079 POINT dst_point
= {0, 0};
4082 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
4083 && wined3d_resource_is_offscreen(&texture
->resource
)
4084 && (surface
->locations
& WINED3D_LOCATION_DRAWABLE
))
4086 surface_load_fb_texture(surface
, srgb
);
4091 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
4092 && (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
4093 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4094 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4095 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4098 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
4099 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
4101 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
4102 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
4107 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
4108 && (!srgb
|| (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
4109 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4110 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4111 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4113 DWORD src_location
= surface
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
4114 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
4115 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
4116 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4118 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, src_location
,
4119 &rect
, surface
, dst_location
, &rect
);
4124 /* Upload from system memory */
4128 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->resource
.map_binding
))
4129 == WINED3D_LOCATION_TEXTURE_RGB
)
4131 /* Performance warning... */
4132 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
4133 surface_prepare_map_memory(surface
);
4134 surface_load_location(surface
, surface
->resource
.map_binding
);
4139 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->resource
.map_binding
))
4140 == WINED3D_LOCATION_TEXTURE_SRGB
)
4142 /* Performance warning... */
4143 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
4144 surface_prepare_map_memory(surface
);
4145 surface_load_location(surface
, surface
->resource
.map_binding
);
4149 if (!(surface
->locations
& surface_simple_locations
))
4151 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4152 /* Lets hope we get it from somewhere... */
4153 surface_prepare_system_memory(surface
);
4154 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
4157 /* TODO: Use already acquired context when possible. */
4158 context
= context_acquire(device
, NULL
);
4160 wined3d_texture_prepare_texture(texture
, context
, srgb
);
4161 wined3d_texture_bind_and_dirtify(texture
, context
, srgb
);
4163 width
= surface
->resource
.width
;
4164 src_pitch
= wined3d_surface_get_pitch(surface
);
4166 format
= *texture
->resource
.format
;
4167 if ((conversion
= wined3d_format_get_color_key_conversion(texture
, TRUE
)))
4168 format
= *wined3d_get_format(gl_info
, conversion
->dst_format
);
4170 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4171 * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
4172 * getting called. */
4173 if ((format
.convert
|| conversion
) && surface
->pbo
)
4175 TRACE("Removing the pbo attached to surface %p.\n", surface
);
4177 if (surface
->flags
& SFLAG_DIBSECTION
)
4178 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
4180 surface
->resource
.map_binding
= WINED3D_LOCATION_SYSMEM
;
4182 surface_prepare_map_memory(surface
);
4183 surface_load_location(surface
, surface
->resource
.map_binding
);
4184 surface_remove_pbo(surface
, gl_info
);
4187 surface_get_memory(surface
, &data
, surface
->locations
);
4190 /* This code is entered for texture formats which need a fixup. */
4191 UINT height
= surface
->resource
.height
;
4193 format
.byte_count
= format
.conv_byte_count
;
4194 dst_pitch
= wined3d_format_calculate_pitch(&format
, width
);
4196 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4198 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4199 context_release(context
);
4200 return E_OUTOFMEMORY
;
4202 format
.convert(data
.addr
, mem
, src_pitch
, src_pitch
* height
,
4203 dst_pitch
, dst_pitch
* height
, width
, height
, 1);
4204 src_pitch
= dst_pitch
;
4207 else if (conversion
)
4209 /* This code is only entered for color keying fixups */
4210 struct wined3d_palette
*palette
= NULL
;
4211 UINT height
= surface
->resource
.height
;
4213 dst_pitch
= wined3d_format_calculate_pitch(&format
, width
);
4214 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4216 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4218 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4219 context_release(context
);
4220 return E_OUTOFMEMORY
;
4222 if (texture
->swapchain
&& texture
->swapchain
->palette
)
4223 palette
= texture
->swapchain
->palette
;
4224 conversion
->convert(data
.addr
, src_pitch
, mem
, dst_pitch
,
4225 width
, height
, palette
, &texture
->gl_color_key
);
4226 src_pitch
= dst_pitch
;
4230 wined3d_surface_upload_data(surface
, gl_info
, &format
, &src_rect
,
4231 src_pitch
, &dst_point
, srgb
, wined3d_const_bo_address(&data
));
4233 context_release(context
);
4235 HeapFree(GetProcessHeap(), 0, mem
);
4240 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
4242 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4244 if (!(surface
->locations
& WINED3D_LOCATION_RB_MULTISAMPLE
))
4245 ERR("Trying to resolve multisampled surface %p, but location WINED3D_LOCATION_RB_MULTISAMPLE not current.\n",
4248 surface_blt_fbo(surface
->resource
.device
, WINED3D_TEXF_POINT
,
4249 surface
, WINED3D_LOCATION_RB_MULTISAMPLE
, &rect
, surface
, WINED3D_LOCATION_RB_RESOLVED
, &rect
);
4252 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
)
4254 struct wined3d_device
*device
= surface
->resource
.device
;
4255 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4258 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4260 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
4262 if (location
== WINED3D_LOCATION_TEXTURE_RGB
4263 && surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_DISCARDED
))
4265 struct wined3d_context
*context
= context_acquire(device
, NULL
);
4266 surface_load_ds_location(surface
, context
, location
);
4267 context_release(context
);
4270 else if (location
& surface
->locations
4271 && surface
->container
->resource
.draw_binding
!= WINED3D_LOCATION_DRAWABLE
)
4273 /* Already up to date, nothing to do. */
4278 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4279 wined3d_debug_location(surface
->locations
), wined3d_debug_location(location
));
4280 return WINED3DERR_INVALIDCALL
;
4284 if (surface
->locations
& location
)
4286 TRACE("Location already up to date.\n");
4290 if (WARN_ON(d3d_surface
))
4292 DWORD required_access
= resource_access_from_location(location
);
4293 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
4294 WARN("Operation requires %#x access, but surface only has %#x.\n",
4295 required_access
, surface
->resource
.access_flags
);
4298 if (!surface
->locations
)
4300 ERR("Surface %p does not have any up to date location.\n", surface
);
4301 surface
->flags
|= SFLAG_LOST
;
4302 return WINED3DERR_DEVICELOST
;
4307 case WINED3D_LOCATION_DIB
:
4308 case WINED3D_LOCATION_USER_MEMORY
:
4309 case WINED3D_LOCATION_SYSMEM
:
4310 case WINED3D_LOCATION_BUFFER
:
4311 surface_load_sysmem(surface
, gl_info
, location
);
4314 case WINED3D_LOCATION_DRAWABLE
:
4315 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
)))
4319 case WINED3D_LOCATION_RB_RESOLVED
:
4320 surface_multisample_resolve(surface
);
4323 case WINED3D_LOCATION_TEXTURE_RGB
:
4324 case WINED3D_LOCATION_TEXTURE_SRGB
:
4325 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
4330 ERR("Don't know how to handle location %#x.\n", location
);
4334 surface_validate_location(surface
, location
);
4336 if (location
!= WINED3D_LOCATION_SYSMEM
&& (surface
->locations
& WINED3D_LOCATION_SYSMEM
))
4337 surface_evict_sysmem(surface
);
4342 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
4343 /* Context activation is done by the caller. */
4344 static void ffp_blit_free(struct wined3d_device
*device
) { }
4346 /* Context activation is done by the caller. */
4347 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4349 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4351 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
4352 checkGLcall("glEnable(target)");
4357 /* Context activation is done by the caller. */
4358 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
4360 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
4361 checkGLcall("glDisable(GL_TEXTURE_2D)");
4362 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
4364 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
4365 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4367 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
4369 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
4370 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4374 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4375 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4376 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4380 case WINED3D_BLIT_OP_COLOR_BLIT
:
4381 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4384 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
4386 TRACE("Checking support for fixup:\n");
4387 dump_color_fixup_desc(src_format
->color_fixup
);
4390 /* We only support identity conversions. */
4391 if (!is_identity_fixup(src_format
->color_fixup
)
4392 || !is_identity_fixup(dst_format
->color_fixup
))
4394 TRACE("Fixups are not supported.\n");
4400 case WINED3D_BLIT_OP_COLOR_FILL
:
4401 if (dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4404 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
4406 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
4409 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
4411 TRACE("Color fill not supported\n");
4415 /* FIXME: We should reject color fills on formats with fixups,
4416 * but this would break P8 color fills for example. */
4420 case WINED3D_BLIT_OP_DEPTH_FILL
:
4424 TRACE("Unsupported blit_op=%d\n", blit_op
);
4429 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4430 const RECT
*dst_rect
, const struct wined3d_color
*color
)
4432 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4433 struct wined3d_rendertarget_view
*view
;
4434 struct wined3d_fb_state fb
= {&view
, NULL
};
4437 if (FAILED(hr
= wined3d_rendertarget_view_create_from_surface(dst_surface
,
4438 NULL
, &wined3d_null_parent_ops
, &view
)))
4440 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
4444 device_clear_render_targets(device
, 1, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
4445 wined3d_rendertarget_view_decref(view
);
4450 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4451 const RECT
*dst_rect
, float depth
)
4453 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4454 struct wined3d_fb_state fb
= {NULL
, NULL
};
4457 if (FAILED(hr
= wined3d_rendertarget_view_create_from_surface(dst_surface
,
4458 NULL
, &wined3d_null_parent_ops
, &fb
.depth_stencil
)))
4460 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
4464 device_clear_render_targets(device
, 0, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
4465 wined3d_rendertarget_view_decref(fb
.depth_stencil
);
4470 const struct blit_shader ffp_blit
= {
4476 ffp_blit_color_fill
,
4477 ffp_blit_depth_fill
,
4480 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
4485 /* Context activation is done by the caller. */
4486 static void cpu_blit_free(struct wined3d_device
*device
)
4490 /* Context activation is done by the caller. */
4491 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4496 /* Context activation is done by the caller. */
4497 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
4501 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4502 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4503 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4505 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
4513 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
4514 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
4515 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
4517 UINT row_block_count
;
4518 const BYTE
*src_row
;
4525 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
4529 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4531 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
4532 src_row
+= src_pitch
;
4533 dst_row
+= dst_pitch
;
4539 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
4541 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
4545 case WINED3DFMT_DXT1
:
4546 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4551 BYTE control_row
[4];
4554 const struct block
*s
= (const struct block
*)src_row
;
4555 struct block
*d
= (struct block
*)dst_row
;
4557 for (x
= 0; x
< row_block_count
; ++x
)
4559 d
[x
].color
[0] = s
[x
].color
[0];
4560 d
[x
].color
[1] = s
[x
].color
[1];
4561 d
[x
].control_row
[0] = s
[x
].control_row
[3];
4562 d
[x
].control_row
[1] = s
[x
].control_row
[2];
4563 d
[x
].control_row
[2] = s
[x
].control_row
[1];
4564 d
[x
].control_row
[3] = s
[x
].control_row
[0];
4566 src_row
-= src_pitch
;
4567 dst_row
+= dst_pitch
;
4571 case WINED3DFMT_DXT2
:
4572 case WINED3DFMT_DXT3
:
4573 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
].alpha_row
[0] = s
[x
].alpha_row
[3];
4588 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
4589 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
4590 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
4591 d
[x
].color
[0] = s
[x
].color
[0];
4592 d
[x
].color
[1] = s
[x
].color
[1];
4593 d
[x
].control_row
[0] = s
[x
].control_row
[3];
4594 d
[x
].control_row
[1] = s
[x
].control_row
[2];
4595 d
[x
].control_row
[2] = s
[x
].control_row
[1];
4596 d
[x
].control_row
[3] = s
[x
].control_row
[0];
4598 src_row
-= src_pitch
;
4599 dst_row
+= dst_pitch
;
4604 FIXME("Compressed flip not implemented for format %s.\n",
4605 debug_d3dformat(format
->id
));
4610 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
4611 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
4616 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
4617 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
4618 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
4620 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
4621 const struct wined3d_format
*src_format
, *dst_format
;
4622 struct wined3d_texture
*src_texture
= NULL
;
4623 struct wined3d_map_desc dst_map
, src_map
;
4624 const BYTE
*sbase
= NULL
;
4625 HRESULT hr
= WINED3D_OK
;
4630 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
4631 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
4632 flags
, fx
, debug_d3dtexturefiltertype(filter
));
4634 if (src_surface
== dst_surface
)
4636 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
4638 src_format
= dst_surface
->resource
.format
;
4639 dst_format
= src_format
;
4643 dst_format
= dst_surface
->resource
.format
;
4646 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
4648 if (!(src_texture
= surface_convert_format(src_surface
, dst_format
->id
)))
4650 /* The conv function writes a FIXME */
4651 WARN("Cannot convert source surface format to dest format.\n");
4654 src_surface
= surface_from_resource(wined3d_texture_get_sub_resource(src_texture
, 0));
4656 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
4657 src_format
= src_surface
->resource
.format
;
4661 src_format
= dst_format
;
4664 wined3d_surface_map(dst_surface
, &dst_map
, dst_rect
, 0);
4667 bpp
= dst_surface
->resource
.format
->byte_count
;
4668 srcheight
= src_rect
->bottom
- src_rect
->top
;
4669 srcwidth
= src_rect
->right
- src_rect
->left
;
4670 dstheight
= dst_rect
->bottom
- dst_rect
->top
;
4671 dstwidth
= dst_rect
->right
- dst_rect
->left
;
4672 width
= (dst_rect
->right
- dst_rect
->left
) * bpp
;
4675 sbase
= (BYTE
*)src_map
.data
4676 + ((src_rect
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
4677 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
4678 if (src_surface
!= dst_surface
)
4679 dbuf
= dst_map
.data
;
4681 dbuf
= (BYTE
*)dst_map
.data
4682 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
4683 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
4685 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
4687 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
4689 if (src_surface
== dst_surface
)
4691 FIXME("Only plain blits supported on compressed surfaces.\n");
4696 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
4698 WARN("Stretching not supported on compressed surfaces.\n");
4699 hr
= WINED3DERR_INVALIDCALL
;
4703 if (!surface_check_block_align(src_surface
, src_rect
))
4705 WARN("Source rectangle not block-aligned.\n");
4706 hr
= WINED3DERR_INVALIDCALL
;
4710 if (!surface_check_block_align(dst_surface
, dst_rect
))
4712 WARN("Destination rectangle not block-aligned.\n");
4713 hr
= WINED3DERR_INVALIDCALL
;
4717 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
4718 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
4719 src_format
, flags
, fx
);
4723 /* First, all the 'source-less' blits */
4724 if (flags
& WINEDDBLT_COLORFILL
)
4726 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->u5
.dwFillColor
);
4727 flags
&= ~WINEDDBLT_COLORFILL
;
4730 if (flags
& WINEDDBLT_DEPTHFILL
)
4732 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
4734 if (flags
& WINEDDBLT_ROP
)
4736 /* Catch some degenerate cases here. */
4740 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, 0);
4742 case 0xaa0029: /* No-op */
4745 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, ~0U);
4747 case SRCCOPY
: /* Well, we do that below? */
4750 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
4753 flags
&= ~WINEDDBLT_ROP
;
4755 if (flags
& WINEDDBLT_DDROPS
)
4757 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
4759 /* Now the 'with source' blits. */
4762 int sx
, xinc
, sy
, yinc
;
4764 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
4767 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
4768 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
4770 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
4771 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
4774 xinc
= (srcwidth
<< 16) / dstwidth
;
4775 yinc
= (srcheight
<< 16) / dstheight
;
4779 /* No effects, we can cheat here. */
4780 if (dstwidth
== srcwidth
)
4782 if (dstheight
== srcheight
)
4784 /* No stretching in either direction. This needs to be as
4785 * fast as possible. */
4788 /* Check for overlapping surfaces. */
4789 if (src_surface
!= dst_surface
|| dst_rect
->top
< src_rect
->top
4790 || dst_rect
->right
<= src_rect
->left
|| src_rect
->right
<= dst_rect
->left
)
4792 /* No overlap, or dst above src, so copy from top downwards. */
4793 for (y
= 0; y
< dstheight
; ++y
)
4795 memcpy(dbuf
, sbuf
, width
);
4796 sbuf
+= src_map
.row_pitch
;
4797 dbuf
+= dst_map
.row_pitch
;
4800 else if (dst_rect
->top
> src_rect
->top
)
4802 /* Copy from bottom upwards. */
4803 sbuf
+= src_map
.row_pitch
* dstheight
;
4804 dbuf
+= dst_map
.row_pitch
* dstheight
;
4805 for (y
= 0; y
< dstheight
; ++y
)
4807 sbuf
-= src_map
.row_pitch
;
4808 dbuf
-= dst_map
.row_pitch
;
4809 memcpy(dbuf
, sbuf
, width
);
4814 /* Src and dst overlapping on the same line, use memmove. */
4815 for (y
= 0; y
< dstheight
; ++y
)
4817 memmove(dbuf
, sbuf
, width
);
4818 sbuf
+= src_map
.row_pitch
;
4819 dbuf
+= dst_map
.row_pitch
;
4825 /* Stretching in y direction only. */
4826 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
4828 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
4829 memcpy(dbuf
, sbuf
, width
);
4830 dbuf
+= dst_map
.row_pitch
;
4836 /* Stretching in X direction. */
4838 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
4840 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
4842 if ((sy
>> 16) == (last_sy
>> 16))
4844 /* This source row is the same as last source row -
4845 * Copy the already stretched row. */
4846 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
4850 #define STRETCH_ROW(type) \
4852 const type *s = (const type *)sbuf; \
4853 type *d = (type *)dbuf; \
4854 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
4855 d[x] = s[sx >> 16]; \
4873 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
4877 s
= sbuf
+ 3 * (sx
>> 16);
4878 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
4879 d
[0] = (pixel
) & 0xff;
4880 d
[1] = (pixel
>> 8) & 0xff;
4881 d
[2] = (pixel
>> 16) & 0xff;
4887 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
4888 hr
= WINED3DERR_NOTAVAILABLE
;
4893 dbuf
+= dst_map
.row_pitch
;
4900 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
4901 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
4902 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
4903 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
4905 /* The color keying flags are checked for correctness in ddraw */
4906 if (flags
& WINEDDBLT_KEYSRC
)
4908 keylow
= src_surface
->container
->src_blt_color_key
.color_space_low_value
;
4909 keyhigh
= src_surface
->container
->src_blt_color_key
.color_space_high_value
;
4911 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
4913 keylow
= fx
->ddckSrcColorkey
.color_space_low_value
;
4914 keyhigh
= fx
->ddckSrcColorkey
.color_space_high_value
;
4917 if (flags
& WINEDDBLT_KEYDEST
)
4919 /* Destination color keys are taken from the source surface! */
4920 destkeylow
= src_surface
->container
->dst_blt_color_key
.color_space_low_value
;
4921 destkeyhigh
= src_surface
->container
->dst_blt_color_key
.color_space_high_value
;
4923 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
4925 destkeylow
= fx
->ddckDestColorkey
.color_space_low_value
;
4926 destkeyhigh
= fx
->ddckDestColorkey
.color_space_high_value
;
4936 get_color_masks(src_format
, masks
);
4941 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
4944 if (flags
& WINEDDBLT_DDFX
)
4946 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
4949 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
4950 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
4951 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
4953 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
4955 /* I don't think we need to do anything about this flag */
4956 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
4958 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
4961 dTopRight
= dTopLeft
;
4964 dBottomRight
= dBottomLeft
;
4966 dstxinc
= dstxinc
* -1;
4968 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
4971 dTopLeft
= dBottomLeft
;
4974 dTopRight
= dBottomRight
;
4976 dstyinc
= dstyinc
* -1;
4978 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
4980 /* I don't think we need to do anything about this flag */
4981 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
4983 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
4986 dBottomRight
= dTopLeft
;
4989 dBottomLeft
= dTopRight
;
4991 dstxinc
= dstxinc
* -1;
4992 dstyinc
= dstyinc
* -1;
4994 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
4997 dTopLeft
= dBottomLeft
;
4998 dBottomLeft
= dBottomRight
;
4999 dBottomRight
= dTopRight
;
5004 dstxinc
= dstxinc
* -1;
5006 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
5009 dTopLeft
= dTopRight
;
5010 dTopRight
= dBottomRight
;
5011 dBottomRight
= dBottomLeft
;
5016 dstyinc
= dstyinc
* -1;
5018 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
5020 /* I don't think we need to do anything about this flag */
5021 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
5024 flags
&= ~(WINEDDBLT_DDFX
);
5027 #define COPY_COLORKEY_FX(type) \
5030 type *d = (type *)dbuf, *dx, tmp; \
5031 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5033 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5035 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5037 tmp = s[sx >> 16]; \
5038 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5039 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5043 dx = (type *)(((BYTE *)dx) + dstxinc); \
5045 d = (type *)(((BYTE *)d) + dstyinc); \
5052 COPY_COLORKEY_FX(BYTE
);
5055 COPY_COLORKEY_FX(WORD
);
5058 COPY_COLORKEY_FX(DWORD
);
5063 BYTE
*d
= dbuf
, *dx
;
5064 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5066 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5068 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
5070 DWORD pixel
, dpixel
= 0;
5071 s
= sbuf
+ 3 * (sx
>>16);
5072 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5073 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
5074 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
5075 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
5077 dx
[0] = (pixel
) & 0xff;
5078 dx
[1] = (pixel
>> 8) & 0xff;
5079 dx
[2] = (pixel
>> 16) & 0xff;
5088 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5089 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
5090 hr
= WINED3DERR_NOTAVAILABLE
;
5092 #undef COPY_COLORKEY_FX
5098 if (flags
&& FIXME_ON(d3d_surface
))
5100 FIXME("\tUnsupported flags: %#x.\n", flags
);
5104 wined3d_surface_unmap(dst_surface
);
5105 if (src_surface
&& src_surface
!= dst_surface
)
5106 wined3d_surface_unmap(src_surface
);
5107 /* Release the converted surface, if any. */
5109 wined3d_texture_decref(src_texture
);
5114 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
5115 const RECT
*dst_rect
, const struct wined3d_color
*color
)
5117 static const RECT src_rect
;
5120 memset(&BltFx
, 0, sizeof(BltFx
));
5121 BltFx
.dwSize
= sizeof(BltFx
);
5122 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
5123 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
5124 WINEDDBLT_COLORFILL
, &BltFx
, WINED3D_TEXF_POINT
);
5127 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
5128 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
5130 FIXME("Depth filling not implemented by cpu_blit.\n");
5131 return WINED3DERR_INVALIDCALL
;
5134 const struct blit_shader cpu_blit
= {
5140 cpu_blit_color_fill
,
5141 cpu_blit_depth_fill
,
5144 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
5145 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
5146 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5148 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
5149 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5150 DWORD src_ds_flags
, dst_ds_flags
;
5151 RECT src_rect
, dst_rect
;
5152 BOOL scale
, convert
;
5154 static const DWORD simple_blit
= WINEDDBLT_ASYNC
5155 | WINEDDBLT_COLORFILL
5157 | WINEDDBLT_DEPTHFILL
5158 | WINEDDBLT_DONOTWAIT
;
5160 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5161 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
5162 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5163 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
5167 TRACE("dwSize %#x.\n", fx
->dwSize
);
5168 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
5169 TRACE("dwROP %#x.\n", fx
->dwROP
);
5170 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
5171 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
5172 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
5173 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
5174 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
5175 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
5176 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
5177 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
5178 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
5179 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
5180 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
5181 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
5182 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
5183 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
5184 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
5185 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
5186 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
5187 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
5188 TRACE("ddckDestColorkey {%#x, %#x}.\n",
5189 fx
->ddckDestColorkey
.color_space_low_value
,
5190 fx
->ddckDestColorkey
.color_space_high_value
);
5191 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
5192 fx
->ddckSrcColorkey
.color_space_low_value
,
5193 fx
->ddckSrcColorkey
.color_space_high_value
);
5196 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
5198 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5199 return WINEDDERR_SURFACEBUSY
;
5202 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
5204 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
5205 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
5206 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
5207 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
5208 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
5210 WARN("The application gave us a bad destination rectangle.\n");
5211 return WINEDDERR_INVALIDRECT
;
5216 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
5218 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
5219 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
5220 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
5221 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
5222 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
5224 WARN("Application gave us bad source rectangle for Blt.\n");
5225 return WINEDDERR_INVALIDRECT
;
5230 memset(&src_rect
, 0, sizeof(src_rect
));
5233 if (!fx
|| !(fx
->dwDDFX
))
5234 flags
&= ~WINEDDBLT_DDFX
;
5236 if (flags
& WINEDDBLT_WAIT
)
5237 flags
&= ~WINEDDBLT_WAIT
;
5239 if (flags
& WINEDDBLT_ASYNC
)
5241 static unsigned int once
;
5244 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
5245 flags
&= ~WINEDDBLT_ASYNC
;
5248 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
5249 if (flags
& WINEDDBLT_DONOTWAIT
)
5251 static unsigned int once
;
5254 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
5255 flags
&= ~WINEDDBLT_DONOTWAIT
;
5258 if (!device
->d3d_initialized
)
5260 WARN("D3D not initialized, using fallback.\n");
5264 /* We want to avoid invalidating the sysmem location for converted
5265 * surfaces, since otherwise we'd have to convert the data back when
5267 if (dst_surface
->container
->flags
& WINED3D_TEXTURE_CONVERTED
5268 || dst_surface
->container
->resource
.format
->convert
5269 || wined3d_format_get_color_key_conversion(dst_surface
->container
, TRUE
))
5271 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
5275 if (flags
& ~simple_blit
)
5277 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
5282 src_swapchain
= src_surface
->container
->swapchain
;
5284 src_swapchain
= NULL
;
5286 dst_swapchain
= dst_surface
->container
->swapchain
;
5288 /* This isn't strictly needed. FBO blits for example could deal with
5289 * cross-swapchain blits by first downloading the source to a texture
5290 * before switching to the destination context. We just have this here to
5291 * not have to deal with the issue, since cross-swapchain blits should be
5293 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
5295 FIXME("Using fallback for cross-swapchain blit.\n");
5300 && (src_rect
.right
- src_rect
.left
!= dst_rect
.right
- dst_rect
.left
5301 || src_rect
.bottom
- src_rect
.top
!= dst_rect
.bottom
- dst_rect
.top
);
5302 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
5304 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5306 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5310 if (src_ds_flags
|| dst_ds_flags
)
5312 if (flags
& WINEDDBLT_DEPTHFILL
)
5316 TRACE("Depth fill.\n");
5318 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
5319 return WINED3DERR_INVALIDCALL
;
5321 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
5326 if (src_ds_flags
!= dst_ds_flags
)
5328 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
5329 return WINED3DERR_INVALIDCALL
;
5332 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->container
->resource
.draw_binding
,
5333 &src_rect
, dst_surface
, dst_surface
->container
->resource
.draw_binding
, &dst_rect
)))
5339 /* In principle this would apply to depth blits as well, but we don't
5340 * implement those in the CPU blitter at the moment. */
5341 if ((dst_surface
->locations
& dst_surface
->resource
.map_binding
)
5342 && (!src_surface
|| (src_surface
->locations
& src_surface
->resource
.map_binding
)))
5345 TRACE("Not doing sysmem blit because of scaling.\n");
5347 TRACE("Not doing sysmem blit because of format conversion.\n");
5352 if (flags
& WINEDDBLT_COLORFILL
)
5354 struct wined3d_color color
;
5356 TRACE("Color fill.\n");
5358 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
5361 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
5366 TRACE("Color blit.\n");
5369 if ((src_surface
->locations
& WINED3D_LOCATION_SYSMEM
)
5370 && !(dst_surface
->locations
& WINED3D_LOCATION_SYSMEM
))
5373 TRACE("Not doing upload because of scaling.\n");
5375 TRACE("Not doing upload because of format conversion.\n");
5378 POINT dst_point
= {dst_rect
.left
, dst_rect
.top
};
5380 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, &src_rect
)))
5382 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
5383 surface_load_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5389 /* Use present for back -> front blits. The idea behind this is
5390 * that present is potentially faster than a blit, in particular
5391 * when FBO blits aren't available. Some ddraw applications like
5392 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
5393 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
5394 * applications can't blit directly to the frontbuffer. */
5395 if (dst_swapchain
&& dst_swapchain
->back_buffers
5396 && dst_surface
->container
== dst_swapchain
->front_buffer
5397 && src_surface
->container
== dst_swapchain
->back_buffers
[0])
5399 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
5401 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
5403 /* Set the swap effect to COPY, we don't want the backbuffer
5404 * to become undefined. */
5405 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
5406 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
5407 dst_swapchain
->desc
.swap_effect
= swap_effect
;
5412 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5413 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5414 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5416 TRACE("Using FBO blit.\n");
5418 surface_blt_fbo(device
, filter
,
5419 src_surface
, src_surface
->container
->resource
.draw_binding
, &src_rect
,
5420 dst_surface
, dst_surface
->container
->resource
.draw_binding
, &dst_rect
);
5421 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5422 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
5427 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5428 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5429 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5431 TRACE("Using arbfp blit.\n");
5433 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
5440 /* Special cases for render targets. */
5441 if (SUCCEEDED(surface_blt_special(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
)))
5446 /* For the rest call the X11 surface implementation. For render targets
5447 * this should be implemented OpenGL accelerated in surface_blt_special(),
5448 * other blits are rather rare. */
5449 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
5452 static HRESULT
surface_init(struct wined3d_surface
*surface
, struct wined3d_texture
*container
,
5453 const struct wined3d_resource_desc
*desc
, GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
)
5455 struct wined3d_device
*device
= container
->resource
.device
;
5456 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5457 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
);
5458 UINT multisample_quality
= desc
->multisample_quality
;
5459 BOOL lockable
= flags
& WINED3D_SURFACE_MAPPABLE
;
5460 unsigned int resource_size
;
5463 if (multisample_quality
> 0)
5465 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
5466 multisample_quality
= 0;
5469 /* Quick lockable sanity check.
5470 * TODO: remove this after surfaces, usage and lockability have been debugged properly
5471 * this function is too deep to need to care about things like this.
5472 * Levels need to be checked too, since they all affect what can be done. */
5475 case WINED3D_POOL_MANAGED
:
5476 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
)
5477 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
5480 case WINED3D_POOL_DEFAULT
:
5481 if (lockable
&& !(desc
->usage
& (WINED3DUSAGE_DYNAMIC
5482 | WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
5483 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
5486 case WINED3D_POOL_SCRATCH
:
5487 case WINED3D_POOL_SYSTEM_MEM
:
5491 FIXME("Unknown pool %#x.\n", desc
->pool
);
5495 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
5496 FIXME("Trying to create a render target that isn't in the default pool.\n");
5498 /* FIXME: Check that the format is supported by the device. */
5500 resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, desc
->width
, desc
->height
, 1);
5502 return WINED3DERR_INVALIDCALL
;
5504 if (device
->wined3d
->flags
& WINED3D_NO3D
)
5505 surface
->surface_ops
= &gdi_surface_ops
;
5507 surface
->surface_ops
= &surface_ops
;
5509 if (FAILED(hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
, format
,
5510 desc
->multisample_type
, multisample_quality
, desc
->usage
, desc
->pool
, desc
->width
, desc
->height
, 1,
5511 resource_size
, NULL
, &wined3d_null_parent_ops
, &surface_resource_ops
)))
5513 WARN("Failed to initialize resource, returning %#x.\n", hr
);
5517 surface
->container
= container
;
5518 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
5519 list_init(&surface
->renderbuffers
);
5520 list_init(&surface
->overlays
);
5523 if (flags
& WINED3D_SURFACE_DISCARD
)
5524 surface
->flags
|= SFLAG_DISCARD
;
5525 if (lockable
|| desc
->format
== WINED3DFMT_D16_LOCKABLE
)
5526 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
5528 surface
->texture_target
= target
;
5529 surface
->texture_level
= level
;
5530 surface
->texture_layer
= layer
;
5532 /* Call the private setup routine */
5533 if (FAILED(hr
= surface
->surface_ops
->surface_private_setup(surface
)))
5535 ERR("Private setup failed, hr %#x.\n", hr
);
5536 surface_cleanup(surface
);
5540 /* Similar to lockable rendertargets above, creating the DIB section
5541 * during surface initialization prevents the sysmem pointer from changing
5542 * after a wined3d_surface_getdc() call. */
5543 if ((desc
->usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
5544 && SUCCEEDED(surface_create_dib_section(surface
)))
5545 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
5547 if (surface
->resource
.map_binding
== WINED3D_LOCATION_DIB
)
5549 wined3d_resource_free_sysmem(&surface
->resource
);
5550 surface_validate_location(surface
, WINED3D_LOCATION_DIB
);
5551 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
5557 HRESULT
wined3d_surface_create(struct wined3d_texture
*container
, const struct wined3d_resource_desc
*desc
,
5558 GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
, struct wined3d_surface
**surface
)
5560 struct wined3d_device_parent
*device_parent
= container
->resource
.device
->device_parent
;
5561 const struct wined3d_parent_ops
*parent_ops
;
5562 struct wined3d_surface
*object
;
5566 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
5567 "multisample_type %#x, multisample_quality %u, target %#x, level %u, layer %u, flags %#x, surface %p.\n",
5568 container
, desc
->width
, desc
->height
, debug_d3dformat(desc
->format
),
5569 debug_d3dusage(desc
->usage
), desc
->usage
, debug_d3dpool(desc
->pool
),
5570 desc
->multisample_type
, desc
->multisample_quality
, target
, level
, layer
, flags
, surface
);
5572 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
5573 return E_OUTOFMEMORY
;
5575 if (FAILED(hr
= surface_init(object
, container
, desc
, target
, level
, layer
, flags
)))
5577 WARN("Failed to initialize surface, returning %#x.\n", hr
);
5578 HeapFree(GetProcessHeap(), 0, object
);
5582 if (FAILED(hr
= device_parent
->ops
->surface_created(device_parent
,
5583 wined3d_texture_get_parent(container
), object
, &parent
, &parent_ops
)))
5585 WARN("Failed to create surface parent, hr %#x.\n", hr
);
5586 wined3d_surface_destroy(object
);
5590 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object
, parent
, parent_ops
);
5592 object
->resource
.parent
= parent
;
5593 object
->resource
.parent_ops
= parent_ops
;