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 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
);
36 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
37 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
38 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
);
39 static HRESULT
IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
40 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*fx
,
41 WINED3DTEXTUREFILTERTYPE filter
);
43 static void surface_cleanup(struct wined3d_surface
*surface
)
45 struct wined3d_surface
*overlay
, *cur
;
47 TRACE("surface %p.\n", surface
);
49 if (surface
->texture_name
|| (surface
->flags
& SFLAG_PBO
)
50 || surface
->rb_multisample
|| surface
->rb_resolved
51 || !list_empty(&surface
->renderbuffers
))
53 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
54 const struct wined3d_gl_info
*gl_info
;
55 struct wined3d_context
*context
;
57 context
= context_acquire(surface
->resource
.device
, NULL
);
58 gl_info
= context
->gl_info
;
62 if (surface
->texture_name
)
64 TRACE("Deleting texture %u.\n", surface
->texture_name
);
65 glDeleteTextures(1, &surface
->texture_name
);
68 if (surface
->flags
& SFLAG_PBO
)
70 TRACE("Deleting PBO %u.\n", surface
->pbo
);
71 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
74 if (surface
->rb_multisample
)
76 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
77 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
80 if (surface
->rb_resolved
)
82 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
83 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
86 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
88 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
89 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
90 HeapFree(GetProcessHeap(), 0, entry
);
95 context_release(context
);
98 if (surface
->flags
& SFLAG_DIBSECTION
)
100 DeleteDC(surface
->hDC
);
101 DeleteObject(surface
->dib
.DIBsection
);
102 surface
->dib
.bitmap_data
= NULL
;
103 surface
->resource
.allocatedMemory
= NULL
;
106 if (surface
->flags
& SFLAG_USERPTR
)
107 wined3d_surface_set_mem(surface
, NULL
);
108 if (surface
->overlay_dest
)
109 list_remove(&surface
->overlay_entry
);
111 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
113 list_remove(&overlay
->overlay_entry
);
114 overlay
->overlay_dest
= NULL
;
117 resource_cleanup(&surface
->resource
);
120 void surface_update_draw_binding(struct wined3d_surface
*surface
)
122 if (!surface_is_offscreen(surface
) || wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
)
123 surface
->draw_binding
= SFLAG_INDRAWABLE
;
124 else if (surface
->resource
.multisample_type
)
125 surface
->draw_binding
= SFLAG_INRB_MULTISAMPLE
;
127 surface
->draw_binding
= SFLAG_INTEXTURE
;
130 void surface_set_container(struct wined3d_surface
*surface
, enum wined3d_container_type type
, void *container
)
132 TRACE("surface %p, container %p.\n", surface
, container
);
134 if (!container
&& type
!= WINED3D_CONTAINER_NONE
)
135 ERR("Setting NULL container of type %#x.\n", type
);
137 if (type
== WINED3D_CONTAINER_SWAPCHAIN
)
139 surface
->get_drawable_size
= get_drawable_size_swapchain
;
143 switch (wined3d_settings
.offscreen_rendering_mode
)
146 surface
->get_drawable_size
= get_drawable_size_fbo
;
150 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
154 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
159 surface
->container
.type
= type
;
160 surface
->container
.u
.base
= container
;
161 surface_update_draw_binding(surface
);
168 enum tex_types tex_type
;
169 GLfloat coords
[4][3];
180 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
182 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
183 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
184 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
185 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
188 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
190 GLfloat (*coords
)[3] = info
->coords
;
196 FIXME("Unsupported texture target %#x\n", target
);
197 /* Fall back to GL_TEXTURE_2D */
199 info
->binding
= GL_TEXTURE_BINDING_2D
;
200 info
->bind_target
= GL_TEXTURE_2D
;
201 info
->tex_type
= tex_2d
;
202 coords
[0][0] = (float)rect
->left
/ w
;
203 coords
[0][1] = (float)rect
->top
/ h
;
206 coords
[1][0] = (float)rect
->right
/ w
;
207 coords
[1][1] = (float)rect
->top
/ h
;
210 coords
[2][0] = (float)rect
->left
/ w
;
211 coords
[2][1] = (float)rect
->bottom
/ h
;
214 coords
[3][0] = (float)rect
->right
/ w
;
215 coords
[3][1] = (float)rect
->bottom
/ h
;
219 case GL_TEXTURE_RECTANGLE_ARB
:
220 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
221 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
222 info
->tex_type
= tex_rect
;
223 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
224 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
225 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
226 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
229 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
230 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
231 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
232 info
->tex_type
= tex_cube
;
233 cube_coords_float(rect
, w
, h
, &f
);
235 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
236 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
237 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
238 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
241 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
242 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
243 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
244 info
->tex_type
= tex_cube
;
245 cube_coords_float(rect
, w
, h
, &f
);
247 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
248 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
249 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
250 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
253 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
254 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
255 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
256 info
->tex_type
= tex_cube
;
257 cube_coords_float(rect
, w
, h
, &f
);
259 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
260 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
261 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
262 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
265 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
266 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
267 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
268 info
->tex_type
= tex_cube
;
269 cube_coords_float(rect
, w
, h
, &f
);
271 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
272 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
273 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
274 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
277 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
278 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
279 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
280 info
->tex_type
= tex_cube
;
281 cube_coords_float(rect
, w
, h
, &f
);
283 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
284 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
285 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
286 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
289 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
290 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
291 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
292 info
->tex_type
= tex_cube
;
293 cube_coords_float(rect
, w
, h
, &f
);
295 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
296 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
297 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
298 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
303 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
306 *rect_out
= *rect_in
;
311 rect_out
->right
= surface
->resource
.width
;
312 rect_out
->bottom
= surface
->resource
.height
;
316 /* GL locking and context activation is done by the caller */
317 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
318 const RECT
*src_rect
, const RECT
*dst_rect
, WINED3DTEXTUREFILTERTYPE Filter
)
320 struct blt_info info
;
322 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
324 glEnable(info
.bind_target
);
325 checkGLcall("glEnable(bind_target)");
327 context_bind_texture(context
, info
.bind_target
, src_surface
->texture_name
);
329 /* Filtering for StretchRect */
330 glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
331 wined3d_gl_mag_filter(magLookup
, Filter
));
332 checkGLcall("glTexParameteri");
333 glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
334 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
335 checkGLcall("glTexParameteri");
336 glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
337 glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
338 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
339 glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
340 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
341 checkGLcall("glTexEnvi");
344 glBegin(GL_TRIANGLE_STRIP
);
345 glTexCoord3fv(info
.coords
[0]);
346 glVertex2i(dst_rect
->left
, dst_rect
->top
);
348 glTexCoord3fv(info
.coords
[1]);
349 glVertex2i(dst_rect
->right
, dst_rect
->top
);
351 glTexCoord3fv(info
.coords
[2]);
352 glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
354 glTexCoord3fv(info
.coords
[3]);
355 glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
358 /* Unbind the texture */
359 context_bind_texture(context
, info
.bind_target
, 0);
361 /* We changed the filtering settings on the texture. Inform the
362 * container about this to get the filters reset properly next draw. */
363 if (src_surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
365 struct wined3d_texture
*texture
= src_surface
->container
.u
.texture
;
366 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
367 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
368 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3DTEXF_NONE
;
369 texture
->texture_rgb
.states
[WINED3DTEXSTA_SRGBTEXTURE
] = FALSE
;
373 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
375 const struct wined3d_format
*format
= surface
->resource
.format
;
383 TRACE("surface %p.\n", surface
);
385 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
387 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
388 return WINED3DERR_INVALIDCALL
;
391 switch (format
->byte_count
)
395 /* Allocate extra space to store the RGB bit masks. */
396 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
400 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
404 /* Allocate extra space for a palette. */
405 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
406 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
411 return E_OUTOFMEMORY
;
413 /* Some applications access the surface in via DWORDs, and do not take
414 * the necessary care at the end of the surface. So we need at least
415 * 4 extra bytes at the end of the surface. Check against the page size,
416 * if the last page used for the surface has at least 4 spare bytes we're
417 * safe, otherwise add an extra line to the DIB section. */
418 GetSystemInfo(&sysInfo
);
419 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
422 TRACE("Adding an extra line to the DIB section.\n");
425 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
426 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
427 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
428 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
429 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
430 * wined3d_surface_get_pitch(surface
);
431 b_info
->bmiHeader
.biPlanes
= 1;
432 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
434 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
435 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
436 b_info
->bmiHeader
.biClrUsed
= 0;
437 b_info
->bmiHeader
.biClrImportant
= 0;
439 /* Get the bit masks */
440 masks
= (DWORD
*)b_info
->bmiColors
;
441 switch (surface
->resource
.format
->id
)
443 case WINED3DFMT_B8G8R8_UNORM
:
444 usage
= DIB_RGB_COLORS
;
445 b_info
->bmiHeader
.biCompression
= BI_RGB
;
448 case WINED3DFMT_B5G5R5X1_UNORM
:
449 case WINED3DFMT_B5G5R5A1_UNORM
:
450 case WINED3DFMT_B4G4R4A4_UNORM
:
451 case WINED3DFMT_B4G4R4X4_UNORM
:
452 case WINED3DFMT_B2G3R3_UNORM
:
453 case WINED3DFMT_B2G3R3A8_UNORM
:
454 case WINED3DFMT_R10G10B10A2_UNORM
:
455 case WINED3DFMT_R8G8B8A8_UNORM
:
456 case WINED3DFMT_R8G8B8X8_UNORM
:
457 case WINED3DFMT_B10G10R10A2_UNORM
:
458 case WINED3DFMT_B5G6R5_UNORM
:
459 case WINED3DFMT_R16G16B16A16_UNORM
:
461 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
462 masks
[0] = format
->red_mask
;
463 masks
[1] = format
->green_mask
;
464 masks
[2] = format
->blue_mask
;
468 /* Don't know palette */
469 b_info
->bmiHeader
.biCompression
= BI_RGB
;
474 if (!(dc
= GetDC(0)))
476 HeapFree(GetProcessHeap(), 0, b_info
);
477 return HRESULT_FROM_WIN32(GetLastError());
480 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
481 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
482 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
483 surface
->dib
.DIBsection
= CreateDIBSection(dc
, b_info
, usage
, &surface
->dib
.bitmap_data
, 0, 0);
486 if (!surface
->dib
.DIBsection
)
488 ERR("Failed to create DIB section.\n");
489 HeapFree(GetProcessHeap(), 0, b_info
);
490 return HRESULT_FROM_WIN32(GetLastError());
493 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
494 /* Copy the existing surface to the dib section. */
495 if (surface
->resource
.allocatedMemory
)
497 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
,
498 surface
->resource
.height
* wined3d_surface_get_pitch(surface
));
502 /* This is to make maps read the GL texture although memory is allocated. */
503 surface
->flags
&= ~SFLAG_INSYSMEM
;
505 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
507 HeapFree(GetProcessHeap(), 0, b_info
);
509 /* Now allocate a DC. */
510 surface
->hDC
= CreateCompatibleDC(0);
511 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
512 TRACE("Using wined3d palette %p.\n", surface
->palette
);
513 SelectPalette(surface
->hDC
, surface
->palette
? surface
->palette
->hpal
: 0, FALSE
);
515 surface
->flags
|= SFLAG_DIBSECTION
;
517 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
518 surface
->resource
.heapMemory
= NULL
;
523 static BOOL
surface_need_pbo(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
525 if (surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
527 if (!(surface
->flags
& SFLAG_DYNLOCK
))
529 if (surface
->flags
& (SFLAG_CONVERTED
| SFLAG_NONPOW2
| SFLAG_PIN_SYSMEM
))
531 if (!gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
])
537 static void surface_load_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
539 struct wined3d_context
*context
;
542 context
= context_acquire(surface
->resource
.device
, NULL
);
545 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
546 error
= glGetError();
547 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
548 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
550 TRACE("Binding PBO %u.\n", surface
->pbo
);
552 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
553 checkGLcall("glBindBufferARB");
555 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->resource
.size
+ 4,
556 surface
->resource
.allocatedMemory
, GL_STREAM_DRAW_ARB
));
557 checkGLcall("glBufferDataARB");
559 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
560 checkGLcall("glBindBufferARB");
562 /* We don't need the system memory anymore and we can't even use it for PBOs. */
563 if (!(surface
->flags
& SFLAG_CLIENT
))
565 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
566 surface
->resource
.heapMemory
= NULL
;
568 surface
->resource
.allocatedMemory
= NULL
;
569 surface
->flags
|= SFLAG_PBO
;
571 context_release(context
);
574 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
576 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
578 TRACE("surface %p.\n", surface
);
580 if (!(surface
->flags
& SFLAG_PBO
) && surface_need_pbo(surface
, gl_info
))
581 surface_load_pbo(surface
, gl_info
);
582 else if (!(surface
->resource
.allocatedMemory
|| surface
->flags
& SFLAG_PBO
))
584 /* Whatever surface we have, make sure that there is memory allocated
585 * for the downloaded copy, or a PBO to map. */
586 if (!surface
->resource
.heapMemory
)
587 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
589 surface
->resource
.allocatedMemory
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
590 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
592 if (surface
->flags
& SFLAG_INSYSMEM
)
593 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
597 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
599 if (surface
->flags
& SFLAG_DONOTFREE
)
602 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
603 surface
->resource
.allocatedMemory
= NULL
;
604 surface
->resource
.heapMemory
= NULL
;
605 surface_modify_location(surface
, SFLAG_INSYSMEM
, FALSE
);
608 /* Context activation is done by the caller. */
609 static void surface_bind_and_dirtify(struct wined3d_surface
*surface
,
610 struct wined3d_context
*context
, BOOL srgb
)
612 struct wined3d_device
*device
= surface
->resource
.device
;
613 DWORD active_sampler
;
615 /* We don't need a specific texture unit, but after binding the texture
616 * the current unit is dirty. Read the unit back instead of switching to
617 * 0, this avoids messing around with the state manager's GL states. The
618 * current texture unit should always be a valid one.
620 * To be more specific, this is tricky because we can implicitly be
621 * called from sampler() in state.c. This means we can't touch anything
622 * other than whatever happens to be the currently active texture, or we
623 * would risk marking already applied sampler states dirty again. */
624 active_sampler
= device
->rev_tex_unit_map
[context
->active_texture
];
626 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
627 device_invalidate_state(device
, STATE_SAMPLER(active_sampler
));
628 surface_bind(surface
, context
, srgb
);
631 static void surface_force_reload(struct wined3d_surface
*surface
)
633 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
636 static void surface_release_client_storage(struct wined3d_surface
*surface
)
638 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
641 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
642 if (surface
->texture_name
)
644 surface_bind_and_dirtify(surface
, context
, FALSE
);
645 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
646 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
648 if (surface
->texture_name_srgb
)
650 surface_bind_and_dirtify(surface
, context
, TRUE
);
651 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
652 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
654 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
657 context_release(context
);
659 surface_modify_location(surface
, SFLAG_INSRGBTEX
, FALSE
);
660 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
661 surface_force_reload(surface
);
664 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
666 /* TODO: Check against the maximum texture sizes supported by the video card. */
667 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
668 unsigned int pow2Width
, pow2Height
;
670 TRACE("surface %p.\n", surface
);
672 surface
->texture_name
= 0;
673 surface
->texture_target
= GL_TEXTURE_2D
;
675 /* Non-power2 support */
676 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
678 pow2Width
= surface
->resource
.width
;
679 pow2Height
= surface
->resource
.height
;
683 /* Find the nearest pow2 match */
684 pow2Width
= pow2Height
= 1;
685 while (pow2Width
< surface
->resource
.width
)
687 while (pow2Height
< surface
->resource
.height
)
690 surface
->pow2Width
= pow2Width
;
691 surface
->pow2Height
= pow2Height
;
693 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
695 /* TODO: Add support for non power two compressed textures. */
696 if (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
698 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
699 surface
, surface
->resource
.width
, surface
->resource
.height
);
700 return WINED3DERR_NOTAVAILABLE
;
704 if (pow2Width
!= surface
->resource
.width
705 || pow2Height
!= surface
->resource
.height
)
707 surface
->flags
|= SFLAG_NONPOW2
;
710 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
711 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
713 /* One of three options:
714 * 1: Do the same as we do with NPOT and scale the texture, (any
715 * texture ops would require the texture to be scaled which is
717 * 2: Set the texture to the maximum size (bad idea).
718 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
719 * 4: Create the surface, but allow it to be used only for DirectDraw
720 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
721 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
722 * the render target. */
723 if (surface
->resource
.pool
== WINED3DPOOL_DEFAULT
|| surface
->resource
.pool
== WINED3DPOOL_MANAGED
)
725 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
726 return WINED3DERR_NOTAVAILABLE
;
729 /* We should never use this surface in combination with OpenGL! */
730 TRACE("Creating an oversized surface: %ux%u.\n",
731 surface
->pow2Width
, surface
->pow2Height
);
735 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
736 * and EXT_PALETTED_TEXTURE is used in combination with texture
737 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
738 * EXT_PALETTED_TEXTURE doesn't work in combination with
739 * ARB_TEXTURE_RECTANGLE. */
740 if (surface
->flags
& SFLAG_NONPOW2
&& gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
741 && !(surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
742 && gl_info
->supported
[EXT_PALETTED_TEXTURE
]
743 && wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
))
745 surface
->texture_target
= GL_TEXTURE_RECTANGLE_ARB
;
746 surface
->pow2Width
= surface
->resource
.width
;
747 surface
->pow2Height
= surface
->resource
.height
;
748 surface
->flags
&= ~(SFLAG_NONPOW2
| SFLAG_NORMCOORD
);
752 switch (wined3d_settings
.offscreen_rendering_mode
)
755 surface
->get_drawable_size
= get_drawable_size_fbo
;
759 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
763 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
764 return WINED3DERR_INVALIDCALL
;
767 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
768 surface
->flags
|= SFLAG_LOST
;
773 static void surface_realize_palette(struct wined3d_surface
*surface
)
775 struct wined3d_palette
*palette
= surface
->palette
;
777 TRACE("surface %p.\n", surface
);
779 if (!palette
) return;
781 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
782 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
784 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
786 /* Make sure the texture is up to date. This call doesn't do
787 * anything if the texture is already up to date. */
788 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
790 /* We want to force a palette refresh, so mark the drawable as not being up to date */
791 if (!surface_is_offscreen(surface
))
792 surface_modify_location(surface
, SFLAG_INDRAWABLE
, FALSE
);
796 if (!(surface
->flags
& SFLAG_INSYSMEM
))
798 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
799 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
801 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
805 if (surface
->flags
& SFLAG_DIBSECTION
)
810 TRACE("Updating the DC's palette.\n");
812 for (i
= 0; i
< 256; ++i
)
814 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
815 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
816 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
817 col
[i
].rgbReserved
= 0;
819 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
822 /* Propagate the changes to the drawable when we have a palette. */
823 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
824 surface_load_location(surface
, surface
->draw_binding
, NULL
);
827 static HRESULT
surface_draw_overlay(struct wined3d_surface
*surface
)
831 /* If there's no destination surface there is nothing to do. */
832 if (!surface
->overlay_dest
)
835 /* Blt calls ModifyLocation on the dest surface, which in turn calls
836 * DrawOverlay to update the overlay. Prevent an endless recursion. */
837 if (surface
->overlay_dest
->flags
& SFLAG_INOVERLAYDRAW
)
840 surface
->overlay_dest
->flags
|= SFLAG_INOVERLAYDRAW
;
841 hr
= wined3d_surface_blt(surface
->overlay_dest
, &surface
->overlay_destrect
, surface
,
842 &surface
->overlay_srcrect
, WINEDDBLT_WAIT
, NULL
, WINED3DTEXF_LINEAR
);
843 surface
->overlay_dest
->flags
&= ~SFLAG_INOVERLAYDRAW
;
848 static void surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
850 struct wined3d_device
*device
= surface
->resource
.device
;
851 const RECT
*pass_rect
= rect
;
853 TRACE("surface %p, rect %s, flags %#x.\n",
854 surface
, wine_dbgstr_rect(rect
), flags
);
856 if (flags
& WINED3DLOCK_DISCARD
)
858 TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n");
859 surface_prepare_system_memory(surface
);
860 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
864 /* surface_load_location() does not check if the rectangle specifies
865 * the full surface. Most callers don't need that, so do it here. */
866 if (rect
&& !rect
->top
&& !rect
->left
867 && rect
->right
== surface
->resource
.width
868 && rect
->bottom
== surface
->resource
.height
)
870 surface_load_location(surface
, SFLAG_INSYSMEM
, pass_rect
);
873 if (surface
->flags
& SFLAG_PBO
)
875 const struct wined3d_gl_info
*gl_info
;
876 struct wined3d_context
*context
;
878 context
= context_acquire(device
, NULL
);
879 gl_info
= context
->gl_info
;
882 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
883 checkGLcall("glBindBufferARB");
885 /* This shouldn't happen but could occur if some other function
886 * didn't handle the PBO properly. */
887 if (surface
->resource
.allocatedMemory
)
888 ERR("The surface already has PBO memory allocated.\n");
890 surface
->resource
.allocatedMemory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
891 checkGLcall("glMapBufferARB");
893 /* Make sure the PBO isn't set anymore in order not to break non-PBO
895 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
896 checkGLcall("glBindBufferARB");
899 context_release(context
);
902 if (!(flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)))
905 surface_add_dirty_rect(surface
, NULL
);
908 struct wined3d_box b
;
912 b
.right
= rect
->right
;
913 b
.bottom
= rect
->bottom
;
916 surface_add_dirty_rect(surface
, &b
);
921 static void surface_unmap(struct wined3d_surface
*surface
)
923 struct wined3d_device
*device
= surface
->resource
.device
;
926 TRACE("surface %p.\n", surface
);
928 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
930 if (surface
->flags
& SFLAG_PBO
)
932 const struct wined3d_gl_info
*gl_info
;
933 struct wined3d_context
*context
;
935 TRACE("Freeing PBO memory.\n");
937 context
= context_acquire(device
, NULL
);
938 gl_info
= context
->gl_info
;
941 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
942 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
943 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
944 checkGLcall("glUnmapBufferARB");
946 context_release(context
);
948 surface
->resource
.allocatedMemory
= NULL
;
951 TRACE("dirtyfied %u.\n", surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
) ? 0 : 1);
953 if (surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
))
955 TRACE("Not dirtified, nothing to do.\n");
959 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
960 || (device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
962 if (!surface
->dirtyRect
.left
&& !surface
->dirtyRect
.top
963 && surface
->dirtyRect
.right
== surface
->resource
.width
964 && surface
->dirtyRect
.bottom
== surface
->resource
.height
)
970 /* TODO: Proper partial rectangle tracking. */
972 surface
->flags
|= SFLAG_INSYSMEM
;
975 surface_load_location(surface
, surface
->draw_binding
, fullsurface
? NULL
: &surface
->dirtyRect
);
977 /* Partial rectangle tracking is not commonly implemented, it is only
978 * done for render targets. INSYSMEM was set before to tell
979 * surface_load_location() where to read the rectangle from.
980 * Indrawable is set because all modifications from the partial
981 * sysmem copy are written back to the drawable, thus the surface is
982 * merged again in the drawable. The sysmem copy is not fully up to
983 * date because only a subrectangle was read in Map(). */
986 surface_modify_location(surface
, surface
->draw_binding
, TRUE
);
987 surface_evict_sysmem(surface
);
990 surface
->dirtyRect
.left
= surface
->resource
.width
;
991 surface
->dirtyRect
.top
= surface
->resource
.height
;
992 surface
->dirtyRect
.right
= 0;
993 surface
->dirtyRect
.bottom
= 0;
995 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
997 FIXME("Depth / stencil buffer locking is not implemented.\n");
1001 /* Overlays have to be redrawn manually after changes with the GL implementation */
1002 if (surface
->overlay_dest
)
1003 surface_draw_overlay(surface
);
1006 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
1008 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
1010 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
1015 static void wined3d_surface_depth_blt_fbo(const struct wined3d_device
*device
, struct wined3d_surface
*src_surface
,
1016 const RECT
*src_rect
, struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
)
1018 const struct wined3d_gl_info
*gl_info
;
1019 struct wined3d_context
*context
;
1020 DWORD src_mask
, dst_mask
;
1023 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
1024 device
, src_surface
, wine_dbgstr_rect(src_rect
),
1025 dst_surface
, wine_dbgstr_rect(dst_rect
));
1027 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1028 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1030 if (src_mask
!= dst_mask
)
1032 ERR("Incompatible formats %s and %s.\n",
1033 debug_d3dformat(src_surface
->resource
.format
->id
),
1034 debug_d3dformat(dst_surface
->resource
.format
->id
));
1040 ERR("Not a depth / stencil format: %s.\n",
1041 debug_d3dformat(src_surface
->resource
.format
->id
));
1046 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
1047 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
1048 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
1049 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
1051 /* Make sure the locations are up-to-date. Loading the destination
1052 * surface isn't required if the entire surface is overwritten. */
1053 surface_load_location(src_surface
, SFLAG_INTEXTURE
, NULL
);
1054 if (!surface_is_full_rect(dst_surface
, dst_rect
))
1055 surface_load_location(dst_surface
, SFLAG_INTEXTURE
, NULL
);
1057 context
= context_acquire(device
, NULL
);
1058 if (!context
->valid
)
1060 context_release(context
);
1061 WARN("Invalid context, skipping blit.\n");
1065 gl_info
= context
->gl_info
;
1069 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, SFLAG_INTEXTURE
);
1070 glReadBuffer(GL_NONE
);
1071 checkGLcall("glReadBuffer()");
1072 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1074 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, SFLAG_INTEXTURE
);
1075 context_set_draw_buffer(context
, GL_NONE
);
1076 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1078 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
1080 glDepthMask(GL_TRUE
);
1081 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
1083 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
1085 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
1087 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
1088 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
1091 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
1094 glDisable(GL_SCISSOR_TEST
);
1095 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
1097 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
1098 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
1099 checkGLcall("glBlitFramebuffer()");
1103 if (wined3d_settings
.strict_draw_ordering
)
1104 wglFlush(); /* Flush to ensure ordering across contexts. */
1106 context_release(context
);
1109 /* Blit between surface locations. Onscreen on different swapchains is not supported.
1110 * Depth / stencil is not supported. */
1111 static void surface_blt_fbo(const struct wined3d_device
*device
, const WINED3DTEXTUREFILTERTYPE filter
,
1112 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
1113 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
1115 const struct wined3d_gl_info
*gl_info
;
1116 struct wined3d_context
*context
;
1117 RECT src_rect
, dst_rect
;
1121 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
1122 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1123 src_surface
, debug_surflocation(src_location
), wine_dbgstr_rect(src_rect_in
));
1124 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1125 dst_surface
, debug_surflocation(dst_location
), wine_dbgstr_rect(dst_rect_in
));
1127 src_rect
= *src_rect_in
;
1128 dst_rect
= *dst_rect_in
;
1132 case WINED3DTEXF_LINEAR
:
1133 gl_filter
= GL_LINEAR
;
1137 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
1138 case WINED3DTEXF_NONE
:
1139 case WINED3DTEXF_POINT
:
1140 gl_filter
= GL_NEAREST
;
1144 /* Resolve the source surface first if needed. */
1145 if (src_location
== SFLAG_INRB_MULTISAMPLE
1146 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
1147 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
1148 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
1149 src_location
= SFLAG_INRB_RESOLVED
;
1151 /* Make sure the locations are up-to-date. Loading the destination
1152 * surface isn't required if the entire surface is overwritten. (And is
1153 * in fact harmful if we're being called by surface_load_location() with
1154 * the purpose of loading the destination surface.) */
1155 surface_load_location(src_surface
, src_location
, NULL
);
1156 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
1157 surface_load_location(dst_surface
, dst_location
, NULL
);
1159 if (src_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, src_surface
);
1160 else if (dst_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, dst_surface
);
1161 else context
= context_acquire(device
, NULL
);
1163 if (!context
->valid
)
1165 context_release(context
);
1166 WARN("Invalid context, skipping blit.\n");
1170 gl_info
= context
->gl_info
;
1172 if (src_location
== SFLAG_INDRAWABLE
)
1174 TRACE("Source surface %p is onscreen.\n", src_surface
);
1175 buffer
= surface_get_gl_buffer(src_surface
);
1176 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
1180 TRACE("Source surface %p is offscreen.\n", src_surface
);
1181 buffer
= GL_COLOR_ATTACHMENT0
;
1185 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
1186 glReadBuffer(buffer
);
1187 checkGLcall("glReadBuffer()");
1188 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1191 if (dst_location
== SFLAG_INDRAWABLE
)
1193 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
1194 buffer
= surface_get_gl_buffer(dst_surface
);
1195 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
1199 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
1200 buffer
= GL_COLOR_ATTACHMENT0
;
1204 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
1205 context_set_draw_buffer(context
, buffer
);
1206 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1207 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
1209 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
1210 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
1211 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
1212 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
1213 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
1215 glDisable(GL_SCISSOR_TEST
);
1216 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
1218 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
1219 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
1220 checkGLcall("glBlitFramebuffer()");
1224 if (wined3d_settings
.strict_draw_ordering
1225 || (dst_location
== SFLAG_INDRAWABLE
1226 && dst_surface
->container
.u
.swapchain
->front_buffer
== dst_surface
))
1229 context_release(context
);
1232 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
1233 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
1234 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
1236 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
1239 /* Source and/or destination need to be on the GL side */
1240 if (src_pool
== WINED3DPOOL_SYSTEMMEM
|| dst_pool
== WINED3DPOOL_SYSTEMMEM
)
1245 case WINED3D_BLIT_OP_COLOR_BLIT
:
1246 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
1248 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1252 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1253 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1255 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1263 if (!(src_format
->id
== dst_format
->id
1264 || (is_identity_fixup(src_format
->color_fixup
)
1265 && is_identity_fixup(dst_format
->color_fixup
))))
1271 /* This function checks if the primary render target uses the 8bit paletted format. */
1272 static BOOL
primary_render_target_is_p8(const struct wined3d_device
*device
)
1274 if (device
->fb
.render_targets
&& device
->fb
.render_targets
[0])
1276 const struct wined3d_surface
*render_target
= device
->fb
.render_targets
[0];
1277 if ((render_target
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1278 && (render_target
->resource
.format
->id
== WINED3DFMT_P8_UINT
))
1284 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1285 DWORD color
, struct wined3d_color
*float_color
)
1287 const struct wined3d_format
*format
= surface
->resource
.format
;
1288 const struct wined3d_device
*device
= surface
->resource
.device
;
1292 case WINED3DFMT_P8_UINT
:
1293 if (surface
->palette
)
1295 float_color
->r
= surface
->palette
->palents
[color
].peRed
/ 255.0f
;
1296 float_color
->g
= surface
->palette
->palents
[color
].peGreen
/ 255.0f
;
1297 float_color
->b
= surface
->palette
->palents
[color
].peBlue
/ 255.0f
;
1301 float_color
->r
= 0.0f
;
1302 float_color
->g
= 0.0f
;
1303 float_color
->b
= 0.0f
;
1305 float_color
->a
= primary_render_target_is_p8(device
) ? color
/ 255.0f
: 1.0f
;
1308 case WINED3DFMT_B5G6R5_UNORM
:
1309 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1310 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1311 float_color
->b
= (color
& 0x1f) / 31.0f
;
1312 float_color
->a
= 1.0f
;
1315 case WINED3DFMT_B8G8R8_UNORM
:
1316 case WINED3DFMT_B8G8R8X8_UNORM
:
1317 float_color
->r
= D3DCOLOR_R(color
);
1318 float_color
->g
= D3DCOLOR_G(color
);
1319 float_color
->b
= D3DCOLOR_B(color
);
1320 float_color
->a
= 1.0f
;
1323 case WINED3DFMT_B8G8R8A8_UNORM
:
1324 float_color
->r
= D3DCOLOR_R(color
);
1325 float_color
->g
= D3DCOLOR_G(color
);
1326 float_color
->b
= D3DCOLOR_B(color
);
1327 float_color
->a
= D3DCOLOR_A(color
);
1331 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1338 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1340 const struct wined3d_format
*format
= surface
->resource
.format
;
1344 case WINED3DFMT_S1_UINT_D15_UNORM
:
1345 *float_depth
= depth
/ (float)0x00007fff;
1348 case WINED3DFMT_D16_UNORM
:
1349 *float_depth
= depth
/ (float)0x0000ffff;
1352 case WINED3DFMT_D24_UNORM_S8_UINT
:
1353 case WINED3DFMT_X8D24_UNORM
:
1354 *float_depth
= depth
/ (float)0x00ffffff;
1357 case WINED3DFMT_D32_UNORM
:
1358 *float_depth
= depth
/ (float)0xffffffff;
1362 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1369 /* Do not call while under the GL lock. */
1370 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1372 const struct wined3d_resource
*resource
= &surface
->resource
;
1373 struct wined3d_device
*device
= resource
->device
;
1374 const struct blit_shader
*blitter
;
1376 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1377 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1380 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1381 return WINED3DERR_INVALIDCALL
;
1384 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1387 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
1388 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
)
1390 struct wined3d_device
*device
= src_surface
->resource
.device
;
1392 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1393 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1394 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1395 return WINED3DERR_INVALIDCALL
;
1397 wined3d_surface_depth_blt_fbo(device
, src_surface
, src_rect
, dst_surface
, dst_rect
);
1399 surface_modify_ds_location(dst_surface
, SFLAG_INTEXTURE
,
1400 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1405 /* Do not call while under the GL lock. */
1406 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
1407 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
1408 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
)
1410 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
1411 struct wined3d_device
*device
= dst_surface
->resource
.device
;
1412 DWORD src_ds_flags
, dst_ds_flags
;
1413 RECT src_rect
, dst_rect
;
1414 BOOL scale
, convert
;
1416 static const DWORD simple_blit
= WINEDDBLT_ASYNC
1417 | WINEDDBLT_COLORFILL
1419 | WINEDDBLT_DEPTHFILL
1420 | WINEDDBLT_DONOTWAIT
;
1422 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1423 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
1424 flags
, fx
, debug_d3dtexturefiltertype(filter
));
1425 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
1429 TRACE("dwSize %#x.\n", fx
->dwSize
);
1430 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
1431 TRACE("dwROP %#x.\n", fx
->dwROP
);
1432 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
1433 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
1434 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
1435 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
1436 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
1437 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
1438 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
1439 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
1440 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
1441 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
1442 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
1443 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
1444 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
1445 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
1446 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
1447 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
1448 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
1449 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
1450 TRACE("ddckDestColorkey {%#x, %#x}.\n",
1451 fx
->ddckDestColorkey
.color_space_low_value
,
1452 fx
->ddckDestColorkey
.color_space_high_value
);
1453 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
1454 fx
->ddckSrcColorkey
.color_space_low_value
,
1455 fx
->ddckSrcColorkey
.color_space_high_value
);
1458 if ((dst_surface
->flags
& SFLAG_LOCKED
) || (src_surface
&& (src_surface
->flags
& SFLAG_LOCKED
)))
1460 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1461 return WINEDDERR_SURFACEBUSY
;
1464 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
1466 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
1467 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
1468 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
1469 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
1470 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
1472 WARN("The application gave us a bad destination rectangle.\n");
1473 return WINEDDERR_INVALIDRECT
;
1478 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
1480 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
1481 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
1482 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
1483 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
1484 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
1486 WARN("Application gave us bad source rectangle for Blt.\n");
1487 return WINEDDERR_INVALIDRECT
;
1492 memset(&src_rect
, 0, sizeof(src_rect
));
1495 if (!fx
|| !(fx
->dwDDFX
))
1496 flags
&= ~WINEDDBLT_DDFX
;
1498 if (flags
& WINEDDBLT_WAIT
)
1499 flags
&= ~WINEDDBLT_WAIT
;
1501 if (flags
& WINEDDBLT_ASYNC
)
1503 static unsigned int once
;
1506 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1507 flags
&= ~WINEDDBLT_ASYNC
;
1510 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1511 if (flags
& WINEDDBLT_DONOTWAIT
)
1513 static unsigned int once
;
1516 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1517 flags
&= ~WINEDDBLT_DONOTWAIT
;
1520 if (!device
->d3d_initialized
)
1522 WARN("D3D not initialized, using fallback.\n");
1526 /* We want to avoid invalidating the sysmem location for converted
1527 * surfaces, since otherwise we'd have to convert the data back when
1529 if (dst_surface
->flags
& SFLAG_CONVERTED
)
1531 WARN("Converted surface, using CPU blit.\n");
1532 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
1535 if (flags
& ~simple_blit
)
1537 WARN("Using fallback for complex blit (%#x).\n", flags
);
1541 if (src_surface
&& src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1542 src_swapchain
= src_surface
->container
.u
.swapchain
;
1544 src_swapchain
= NULL
;
1546 if (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1547 dst_swapchain
= dst_surface
->container
.u
.swapchain
;
1549 dst_swapchain
= NULL
;
1551 /* This isn't strictly needed. FBO blits for example could deal with
1552 * cross-swapchain blits by first downloading the source to a texture
1553 * before switching to the destination context. We just have this here to
1554 * not have to deal with the issue, since cross-swapchain blits should be
1556 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
1558 FIXME("Using fallback for cross-swapchain blit.\n");
1563 && (src_rect
.right
- src_rect
.left
!= dst_rect
.right
- dst_rect
.left
1564 || src_rect
.bottom
- src_rect
.top
!= dst_rect
.bottom
- dst_rect
.top
);
1565 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
1567 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1569 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1573 if (src_ds_flags
|| dst_ds_flags
)
1575 if (flags
& WINEDDBLT_DEPTHFILL
)
1579 TRACE("Depth fill.\n");
1581 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
1582 return WINED3DERR_INVALIDCALL
;
1584 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
1589 /* Accessing depth / stencil surfaces is supposed to fail while in
1590 * a scene, except for fills, which seem to work. */
1591 if (device
->inScene
)
1593 WARN("Rejecting depth / stencil access while in scene.\n");
1594 return WINED3DERR_INVALIDCALL
;
1597 if (src_ds_flags
!= dst_ds_flags
)
1599 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1600 return WINED3DERR_INVALIDCALL
;
1603 if (src_rect
.top
|| src_rect
.left
1604 || src_rect
.bottom
!= src_surface
->resource
.height
1605 || src_rect
.right
!= src_surface
->resource
.width
)
1607 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
1608 wine_dbgstr_rect(&src_rect
));
1609 return WINED3DERR_INVALIDCALL
;
1612 if (dst_rect
.top
|| dst_rect
.left
1613 || dst_rect
.bottom
!= dst_surface
->resource
.height
1614 || dst_rect
.right
!= dst_surface
->resource
.width
)
1616 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
1617 wine_dbgstr_rect(&src_rect
));
1618 return WINED3DERR_INVALIDCALL
;
1623 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
1624 return WINED3DERR_INVALIDCALL
;
1627 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
1633 /* In principle this would apply to depth blits as well, but we don't
1634 * implement those in the CPU blitter at the moment. */
1635 if ((dst_surface
->flags
& SFLAG_INSYSMEM
)
1636 && (!src_surface
|| (src_surface
->flags
& SFLAG_INSYSMEM
)))
1639 TRACE("Not doing sysmem blit because of scaling.\n");
1641 TRACE("Not doing sysmem blit because of format conversion.\n");
1643 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
1646 if (flags
& WINEDDBLT_COLORFILL
)
1648 struct wined3d_color color
;
1650 TRACE("Color fill.\n");
1652 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
1655 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
1660 TRACE("Color blit.\n");
1663 if ((src_surface
->flags
& SFLAG_INSYSMEM
) && !(dst_surface
->flags
& SFLAG_INSYSMEM
))
1666 TRACE("Not doing upload because of scaling.\n");
1668 TRACE("Not doing upload because of format conversion.\n");
1671 POINT dst_point
= {dst_rect
.left
, dst_rect
.top
};
1673 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, &src_rect
)))
1675 if (!surface_is_offscreen(dst_surface
))
1676 surface_load_location(dst_surface
, dst_surface
->draw_binding
, NULL
);
1682 /* Use present for back -> front blits. The idea behind this is
1683 * that present is potentially faster than a blit, in particular
1684 * when FBO blits aren't available. Some ddraw applications like
1685 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
1686 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
1687 * applications can't blit directly to the frontbuffer. */
1688 if (dst_swapchain
&& dst_swapchain
->back_buffers
1689 && dst_surface
== dst_swapchain
->front_buffer
1690 && src_surface
== dst_swapchain
->back_buffers
[0])
1692 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
1694 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1696 /* Set the swap effect to COPY, we don't want the backbuffer
1697 * to become undefined. */
1698 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
1699 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
1700 dst_swapchain
->desc
.swap_effect
= swap_effect
;
1705 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1706 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1707 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1709 TRACE("Using FBO blit.\n");
1711 surface_blt_fbo(device
, filter
,
1712 src_surface
, src_surface
->draw_binding
, &src_rect
,
1713 dst_surface
, dst_surface
->draw_binding
, &dst_rect
);
1714 surface_modify_location(dst_surface
, dst_surface
->draw_binding
, TRUE
);
1718 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1719 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1720 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1722 TRACE("Using arbfp blit.\n");
1724 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
1732 /* Special cases for render targets. */
1733 if ((dst_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1734 || (src_surface
&& (src_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)))
1736 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface
, &dst_rect
,
1737 src_surface
, &src_rect
, flags
, fx
, filter
)))
1743 /* For the rest call the X11 surface implementation. For render targets
1744 * this should be implemented OpenGL accelerated in BltOverride, other
1745 * blits are rather rare. */
1746 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
1749 HRESULT CDECL
wined3d_surface_get_render_target_data(struct wined3d_surface
*surface
,
1750 struct wined3d_surface
*render_target
)
1752 TRACE("surface %p, render_target %p.\n", surface
, render_target
);
1754 /* TODO: Check surface sizes, pools, etc. */
1756 if (render_target
->resource
.multisample_type
)
1757 return WINED3DERR_INVALIDCALL
;
1759 return wined3d_surface_blt(surface
, NULL
, render_target
, NULL
, 0, NULL
, WINED3DTEXF_POINT
);
1762 /* Context activation is done by the caller. */
1763 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1765 if (surface
->flags
& SFLAG_DIBSECTION
)
1767 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1771 if (!surface
->resource
.heapMemory
)
1772 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
1773 else if (!(surface
->flags
& SFLAG_CLIENT
))
1774 ERR("Surface %p has heapMemory %p and flags %#x.\n",
1775 surface
, surface
->resource
.heapMemory
, surface
->flags
);
1777 surface
->resource
.allocatedMemory
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
1778 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
1782 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
1783 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1784 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0,
1785 surface
->resource
.size
, surface
->resource
.allocatedMemory
));
1786 checkGLcall("glGetBufferSubDataARB");
1787 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1788 checkGLcall("glDeleteBuffersARB");
1792 surface
->flags
&= ~SFLAG_PBO
;
1795 /* Do not call while under the GL lock. */
1796 static void surface_unload(struct wined3d_resource
*resource
)
1798 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1799 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1800 struct wined3d_device
*device
= resource
->device
;
1801 const struct wined3d_gl_info
*gl_info
;
1802 struct wined3d_context
*context
;
1804 TRACE("surface %p.\n", surface
);
1806 if (resource
->pool
== WINED3DPOOL_DEFAULT
)
1808 /* Default pool resources are supposed to be destroyed before Reset is called.
1809 * Implicit resources stay however. So this means we have an implicit render target
1810 * or depth stencil. The content may be destroyed, but we still have to tear down
1811 * opengl resources, so we cannot leave early.
1813 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1814 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1815 * or the depth stencil into an FBO the texture or render buffer will be removed
1816 * and all flags get lost
1818 if (!(surface
->flags
& SFLAG_PBO
))
1819 surface_init_sysmem(surface
);
1820 /* We also get here when the ddraw swapchain is destroyed, for example
1821 * for a mode switch. In this case this surface won't necessarily be
1822 * an implicit surface. We have to mark it lost so that the
1823 * application can restore it after the mode switch. */
1824 surface
->flags
|= SFLAG_LOST
;
1828 /* Load the surface into system memory */
1829 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
1830 surface_modify_location(surface
, surface
->draw_binding
, FALSE
);
1832 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
1833 surface_modify_location(surface
, SFLAG_INSRGBTEX
, FALSE
);
1834 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1836 context
= context_acquire(device
, NULL
);
1837 gl_info
= context
->gl_info
;
1839 /* Destroy PBOs, but load them into real sysmem before */
1840 if (surface
->flags
& SFLAG_PBO
)
1841 surface_remove_pbo(surface
, gl_info
);
1843 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1844 * all application-created targets the application has to release the surface
1845 * before calling _Reset
1847 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1850 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1852 list_remove(&entry
->entry
);
1853 HeapFree(GetProcessHeap(), 0, entry
);
1855 list_init(&surface
->renderbuffers
);
1856 surface
->current_renderbuffer
= NULL
;
1860 /* If we're in a texture, the texture name belongs to the texture.
1861 * Otherwise, destroy it. */
1862 if (surface
->container
.type
!= WINED3D_CONTAINER_TEXTURE
)
1864 glDeleteTextures(1, &surface
->texture_name
);
1865 surface
->texture_name
= 0;
1866 glDeleteTextures(1, &surface
->texture_name_srgb
);
1867 surface
->texture_name_srgb
= 0;
1869 if (surface
->rb_multisample
)
1871 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1872 surface
->rb_multisample
= 0;
1874 if (surface
->rb_resolved
)
1876 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1877 surface
->rb_resolved
= 0;
1882 context_release(context
);
1884 resource_unload(resource
);
1887 static const struct wined3d_resource_ops surface_resource_ops
=
1892 static const struct wined3d_surface_ops surface_ops
=
1894 surface_private_setup
,
1895 surface_realize_palette
,
1900 /*****************************************************************************
1901 * Initializes the GDI surface, aka creates the DIB section we render to
1902 * The DIB section creation is done by calling GetDC, which will create the
1903 * section and releasing the dc to allow the app to use it. The dib section
1904 * will stay until the surface is released
1906 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1907 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1908 * avoid confusion in the shared surface code.
1911 * WINED3D_OK on success
1912 * The return values of called methods on failure
1914 *****************************************************************************/
1915 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1919 TRACE("surface %p.\n", surface
);
1921 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1923 ERR("Overlays not yet supported by GDI surfaces.\n");
1924 return WINED3DERR_INVALIDCALL
;
1927 /* Sysmem textures have memory already allocated - release it,
1928 * this avoids an unnecessary memcpy. */
1929 hr
= surface_create_dib_section(surface
);
1932 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
1933 surface
->resource
.heapMemory
= NULL
;
1934 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1937 /* We don't mind the nonpow2 stuff in GDI. */
1938 surface
->pow2Width
= surface
->resource
.width
;
1939 surface
->pow2Height
= surface
->resource
.height
;
1944 static void gdi_surface_realize_palette(struct wined3d_surface
*surface
)
1946 struct wined3d_palette
*palette
= surface
->palette
;
1948 TRACE("surface %p.\n", surface
);
1950 if (!palette
) return;
1952 if (surface
->flags
& SFLAG_DIBSECTION
)
1957 TRACE("Updating the DC's palette.\n");
1959 for (i
= 0; i
< 256; ++i
)
1961 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
1962 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
1963 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
1964 col
[i
].rgbReserved
= 0;
1966 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
1969 /* Update the image because of the palette change. Some games like e.g.
1970 * Red Alert call SetEntries a lot to implement fading. */
1971 /* Tell the swapchain to update the screen. */
1972 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1974 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
1975 if (surface
== swapchain
->front_buffer
)
1977 x11_copy_to_screen(swapchain
, NULL
);
1982 static void gdi_surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
1984 TRACE("surface %p, rect %s, flags %#x.\n",
1985 surface
, wine_dbgstr_rect(rect
), flags
);
1987 if (!(surface
->flags
& SFLAG_DIBSECTION
))
1989 /* This happens on gdi surfaces if the application set a user pointer
1990 * and resets it. Recreate the DIB section. */
1991 surface_create_dib_section(surface
);
1992 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1996 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1998 TRACE("surface %p.\n", surface
);
2000 /* Tell the swapchain to update the screen. */
2001 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
2003 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2004 if (surface
== swapchain
->front_buffer
)
2006 x11_copy_to_screen(swapchain
, &surface
->lockedRect
);
2010 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
2013 static const struct wined3d_surface_ops gdi_surface_ops
=
2015 gdi_surface_private_setup
,
2016 gdi_surface_realize_palette
,
2021 void surface_set_texture_name(struct wined3d_surface
*surface
, GLuint new_name
, BOOL srgb
)
2026 TRACE("surface %p, new_name %u, srgb %#x.\n", surface
, new_name
, srgb
);
2030 name
= &surface
->texture_name_srgb
;
2031 flag
= SFLAG_INSRGBTEX
;
2035 name
= &surface
->texture_name
;
2036 flag
= SFLAG_INTEXTURE
;
2039 if (!*name
&& new_name
)
2041 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2042 * surface has no texture name yet. See if we can get rid of this. */
2043 if (surface
->flags
& flag
)
2045 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag
));
2046 surface_modify_location(surface
, flag
, FALSE
);
2051 surface_force_reload(surface
);
2054 void surface_set_texture_target(struct wined3d_surface
*surface
, GLenum target
)
2056 TRACE("surface %p, target %#x.\n", surface
, target
);
2058 if (surface
->texture_target
!= target
)
2060 if (target
== GL_TEXTURE_RECTANGLE_ARB
)
2062 surface
->flags
&= ~SFLAG_NORMCOORD
;
2064 else if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
2066 surface
->flags
|= SFLAG_NORMCOORD
;
2069 surface
->texture_target
= target
;
2070 surface_force_reload(surface
);
2073 /* Context activation is done by the caller. */
2074 void surface_bind(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
2076 TRACE("surface %p, context %p, srgb %#x.\n", surface
, context
, srgb
);
2078 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
2080 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
2082 TRACE("Passing to container (%p).\n", texture
);
2083 texture
->texture_ops
->texture_bind(texture
, context
, srgb
);
2087 if (surface
->texture_level
)
2089 ERR("Standalone surface %p is non-zero texture level %u.\n",
2090 surface
, surface
->texture_level
);
2094 ERR("Trying to bind standalone surface %p as sRGB.\n", surface
);
2098 if (!surface
->texture_name
)
2100 glGenTextures(1, &surface
->texture_name
);
2101 checkGLcall("glGenTextures");
2103 TRACE("Surface %p given name %u.\n", surface
, surface
->texture_name
);
2105 context_bind_texture(context
, surface
->texture_target
, surface
->texture_name
);
2106 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2107 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2108 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
2109 glTexParameteri(surface
->texture_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2110 glTexParameteri(surface
->texture_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2111 checkGLcall("glTexParameteri");
2115 context_bind_texture(context
, surface
->texture_target
, surface
->texture_name
);
2122 /* This call just downloads data, the caller is responsible for binding the
2123 * correct texture. */
2124 /* Context activation is done by the caller. */
2125 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
2127 const struct wined3d_format
*format
= surface
->resource
.format
;
2129 /* Only support read back of converted P8 surfaces. */
2130 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
2132 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
2138 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
2140 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2141 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
,
2142 surface
->resource
.allocatedMemory
);
2144 if (surface
->flags
& SFLAG_PBO
)
2146 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
2147 checkGLcall("glBindBufferARB");
2148 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
2149 checkGLcall("glGetCompressedTexImageARB");
2150 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
2151 checkGLcall("glBindBufferARB");
2155 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
2156 surface
->texture_level
, surface
->resource
.allocatedMemory
));
2157 checkGLcall("glGetCompressedTexImageARB");
2165 GLenum gl_format
= format
->glFormat
;
2166 GLenum gl_type
= format
->glType
;
2170 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2171 if (format
->id
== WINED3DFMT_P8_UINT
&& primary_render_target_is_p8(surface
->resource
.device
))
2173 gl_format
= GL_ALPHA
;
2174 gl_type
= GL_UNSIGNED_BYTE
;
2177 if (surface
->flags
& SFLAG_NONPOW2
)
2179 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
2180 src_pitch
= format
->byte_count
* surface
->pow2Width
;
2181 dst_pitch
= wined3d_surface_get_pitch(surface
);
2182 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
2183 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
2187 mem
= surface
->resource
.allocatedMemory
;
2190 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2191 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
2193 if (surface
->flags
& SFLAG_PBO
)
2195 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
2196 checkGLcall("glBindBufferARB");
2198 glGetTexImage(surface
->texture_target
, surface
->texture_level
, gl_format
, gl_type
, NULL
);
2199 checkGLcall("glGetTexImage");
2201 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
2202 checkGLcall("glBindBufferARB");
2206 glGetTexImage(surface
->texture_target
, surface
->texture_level
, gl_format
, gl_type
, mem
);
2207 checkGLcall("glGetTexImage");
2211 if (surface
->flags
& SFLAG_NONPOW2
)
2213 const BYTE
*src_data
;
2217 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2218 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2219 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2221 * We're doing this...
2223 * instead of boxing the texture :
2224 * |<-texture width ->| -->pow2width| /\
2225 * |111111111111111111| | |
2226 * |222 Texture 222222| boxed empty | texture height
2227 * |3333 Data 33333333| | |
2228 * |444444444444444444| | \/
2229 * ----------------------------------- |
2230 * | boxed empty | boxed empty | pow2height
2232 * -----------------------------------
2235 * we're repacking the data to the expected texture width
2237 * |<-texture width ->| -->pow2width| /\
2238 * |111111111111111111222222222222222| |
2239 * |222333333333333333333444444444444| texture height
2243 * | empty | pow2height
2245 * -----------------------------------
2249 * |<-texture width ->| /\
2250 * |111111111111111111|
2251 * |222222222222222222|texture height
2252 * |333333333333333333|
2253 * |444444444444444444| \/
2254 * --------------------
2256 * this also means that any references to allocatedMemory should work with the data as if were a
2257 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2259 * internally the texture is still stored in a boxed format so any references to textureName will
2260 * get a boxed texture with width pow2width and not a texture of width resource.width.
2262 * Performance should not be an issue, because applications normally do not lock the surfaces when
2263 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2264 * and doesn't have to be re-read. */
2266 dst_data
= surface
->resource
.allocatedMemory
;
2267 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
2268 for (y
= 1; y
< surface
->resource
.height
; ++y
)
2270 /* skip the first row */
2271 src_data
+= src_pitch
;
2272 dst_data
+= dst_pitch
;
2273 memcpy(dst_data
, src_data
, dst_pitch
);
2276 HeapFree(GetProcessHeap(), 0, mem
);
2280 /* Surface has now been downloaded */
2281 surface
->flags
|= SFLAG_INSYSMEM
;
2284 /* This call just uploads data, the caller is responsible for binding the
2285 * correct texture. */
2286 /* Context activation is done by the caller. */
2287 static void surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2288 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
2289 BOOL srgb
, const struct wined3d_bo_address
*data
)
2291 UINT update_w
= src_rect
->right
- src_rect
->left
;
2292 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
2294 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
2295 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
2296 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
2298 if (surface
->flags
& SFLAG_LOCKED
)
2300 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
2301 surface
->flags
|= SFLAG_PIN_SYSMEM
;
2304 if (format
->heightscale
!= 1.0f
&& format
->heightscale
!= 0.0f
)
2305 update_h
*= format
->heightscale
;
2309 if (data
->buffer_object
)
2311 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
2312 checkGLcall("glBindBufferARB");
2315 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
2317 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1);
2318 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
2319 const BYTE
*addr
= data
->addr
;
2322 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
2323 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
2326 internal
= format
->glGammaInternal
;
2327 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2328 internal
= format
->rtInternal
;
2330 internal
= format
->glInternal
;
2332 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2333 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
2334 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
2336 if (row_length
== src_pitch
)
2338 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
2339 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
2345 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2346 * can't use the unpack row length like below. */
2347 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
2349 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
2350 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
2351 y
+= format
->block_height
;
2355 checkGLcall("glCompressedTexSubImage2DARB");
2359 const BYTE
*addr
= data
->addr
;
2361 addr
+= src_rect
->top
* src_pitch
;
2362 addr
+= src_rect
->left
* format
->byte_count
;
2364 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2365 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
2366 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
2368 glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
2369 glTexSubImage2D(surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
2370 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
2371 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
2372 checkGLcall("glTexSubImage2D");
2375 if (data
->buffer_object
)
2377 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
2378 checkGLcall("glBindBufferARB");
2383 if (wined3d_settings
.strict_draw_ordering
)
2386 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
2388 struct wined3d_device
*device
= surface
->resource
.device
;
2391 for (i
= 0; i
< device
->context_count
; ++i
)
2393 context_surface_update(device
->contexts
[i
], surface
);
2398 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
2399 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
2401 const struct wined3d_format
*src_format
;
2402 const struct wined3d_format
*dst_format
;
2403 const struct wined3d_gl_info
*gl_info
;
2404 struct wined3d_context
*context
;
2405 struct wined3d_bo_address data
;
2406 struct wined3d_format format
;
2407 UINT update_w
, update_h
;
2408 CONVERT_TYPES convert
;
2415 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2416 dst_surface
, wine_dbgstr_point(dst_point
),
2417 src_surface
, wine_dbgstr_rect(src_rect
));
2419 src_format
= src_surface
->resource
.format
;
2420 dst_format
= dst_surface
->resource
.format
;
2422 if (src_format
->id
!= dst_format
->id
)
2424 WARN("Source and destination surfaces should have the same format.\n");
2425 return WINED3DERR_INVALIDCALL
;
2434 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
2436 WARN("Invalid destination point.\n");
2437 return WINED3DERR_INVALIDCALL
;
2444 r
.right
= src_surface
->resource
.width
;
2445 r
.bottom
= src_surface
->resource
.height
;
2448 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
2449 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
2451 WARN("Invalid source rectangle.\n");
2452 return WINED3DERR_INVALIDCALL
;
2455 src_w
= src_surface
->resource
.width
;
2456 src_h
= src_surface
->resource
.height
;
2458 dst_w
= dst_surface
->resource
.width
;
2459 dst_h
= dst_surface
->resource
.height
;
2461 update_w
= src_rect
->right
- src_rect
->left
;
2462 update_h
= src_rect
->bottom
- src_rect
->top
;
2464 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
2465 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
2467 WARN("Destination out of bounds.\n");
2468 return WINED3DERR_INVALIDCALL
;
2471 /* NPOT block sizes would be silly. */
2472 if ((src_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
2473 && ((update_w
& (src_format
->block_width
- 1) || update_h
& (src_format
->block_height
- 1))
2474 && (src_w
!= update_w
|| dst_w
!= update_w
|| src_h
!= update_h
|| dst_h
!= update_h
)))
2476 WARN("Update rect not block-aligned.\n");
2477 return WINED3DERR_INVALIDCALL
;
2480 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2481 d3dfmt_get_conv(dst_surface
, FALSE
, TRUE
, &format
, &convert
);
2482 if (convert
!= NO_CONVERSION
|| format
.convert
)
2484 RECT dst_rect
= {dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
};
2485 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3DTEXF_POINT
);
2488 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
2489 gl_info
= context
->gl_info
;
2491 /* Only load the surface for partial updates. For newly allocated texture
2492 * the texture wouldn't be the current location, and we'd upload zeroes
2493 * just to overwrite them again. */
2494 if (update_w
== dst_w
&& update_h
== dst_h
)
2495 surface_prepare_texture(dst_surface
, context
, FALSE
);
2497 surface_load_location(dst_surface
, SFLAG_INTEXTURE
, NULL
);
2498 surface_bind(dst_surface
, context
, FALSE
);
2500 data
.buffer_object
= src_surface
->pbo
;
2501 data
.addr
= src_surface
->resource
.allocatedMemory
;
2502 src_pitch
= wined3d_surface_get_pitch(src_surface
);
2504 surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
, src_pitch
, dst_point
, FALSE
, &data
);
2506 invalidate_active_texture(dst_surface
->resource
.device
, context
);
2508 context_release(context
);
2510 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
2514 /* This call just allocates the texture, the caller is responsible for binding
2515 * the correct texture. */
2516 /* Context activation is done by the caller. */
2517 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2518 const struct wined3d_format
*format
, BOOL srgb
)
2520 BOOL enable_client_storage
= FALSE
;
2521 GLsizei width
= surface
->pow2Width
;
2522 GLsizei height
= surface
->pow2Height
;
2523 const BYTE
*mem
= NULL
;
2528 internal
= format
->glGammaInternal
;
2530 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2532 internal
= format
->rtInternal
;
2536 internal
= format
->glInternal
;
2539 if (format
->heightscale
!= 1.0f
&& format
->heightscale
!= 0.0f
) height
*= format
->heightscale
;
2541 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
2542 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
2543 internal
, width
, height
, format
->glFormat
, format
->glType
);
2547 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
2549 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
2550 || !surface
->resource
.allocatedMemory
)
2552 /* In some cases we want to disable client storage.
2553 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2554 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2555 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2556 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2558 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2559 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2560 surface
->flags
&= ~SFLAG_CLIENT
;
2561 enable_client_storage
= TRUE
;
2565 surface
->flags
|= SFLAG_CLIENT
;
2567 /* Point OpenGL to our allocated texture memory. Do not use
2568 * resource.allocatedMemory here because it might point into a
2569 * PBO. Instead use heapMemory, but get the alignment right. */
2570 mem
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
2571 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
2575 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
2577 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
2578 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
2579 checkGLcall("glCompressedTexImage2DARB");
2583 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
2584 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
2585 checkGLcall("glTexImage2D");
2588 if(enable_client_storage
) {
2589 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2590 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2595 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2596 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2597 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2598 /* GL locking is done by the caller */
2599 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
2601 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
2602 struct wined3d_renderbuffer_entry
*entry
;
2603 GLuint renderbuffer
= 0;
2604 unsigned int src_width
, src_height
;
2605 unsigned int width
, height
;
2607 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
2609 width
= rt
->pow2Width
;
2610 height
= rt
->pow2Height
;
2614 width
= surface
->pow2Width
;
2615 height
= surface
->pow2Height
;
2618 src_width
= surface
->pow2Width
;
2619 src_height
= surface
->pow2Height
;
2621 /* A depth stencil smaller than the render target is not valid */
2622 if (width
> src_width
|| height
> src_height
) return;
2624 /* Remove any renderbuffer set if the sizes match */
2625 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
2626 || (width
== src_width
&& height
== src_height
))
2628 surface
->current_renderbuffer
= NULL
;
2632 /* Look if we've already got a renderbuffer of the correct dimensions */
2633 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
2635 if (entry
->width
== width
&& entry
->height
== height
)
2637 renderbuffer
= entry
->id
;
2638 surface
->current_renderbuffer
= entry
;
2645 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
2646 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
2647 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
2648 surface
->resource
.format
->glInternal
, width
, height
);
2650 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
2651 entry
->width
= width
;
2652 entry
->height
= height
;
2653 entry
->id
= renderbuffer
;
2654 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
2656 surface
->current_renderbuffer
= entry
;
2659 checkGLcall("set_compatible_renderbuffer");
2662 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
2664 const struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2666 TRACE("surface %p.\n", surface
);
2668 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
)
2670 ERR("Surface %p is not on a swapchain.\n", surface
);
2674 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
)
2676 if (swapchain
->render_to_fbo
)
2678 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2679 return GL_COLOR_ATTACHMENT0
;
2681 TRACE("Returning GL_BACK\n");
2684 else if (surface
== swapchain
->front_buffer
)
2686 TRACE("Returning GL_FRONT\n");
2690 FIXME("Higher back buffer, returning GL_BACK\n");
2694 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2695 void surface_add_dirty_rect(struct wined3d_surface
*surface
, const struct wined3d_box
*dirty_rect
)
2697 TRACE("surface %p, dirty_rect %p.\n", surface
, dirty_rect
);
2699 if (!(surface
->flags
& SFLAG_INSYSMEM
) && (surface
->flags
& SFLAG_INTEXTURE
))
2700 /* No partial locking for textures yet. */
2701 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2703 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
2706 surface
->dirtyRect
.left
= min(surface
->dirtyRect
.left
, dirty_rect
->left
);
2707 surface
->dirtyRect
.top
= min(surface
->dirtyRect
.top
, dirty_rect
->top
);
2708 surface
->dirtyRect
.right
= max(surface
->dirtyRect
.right
, dirty_rect
->right
);
2709 surface
->dirtyRect
.bottom
= max(surface
->dirtyRect
.bottom
, dirty_rect
->bottom
);
2713 surface
->dirtyRect
.left
= 0;
2714 surface
->dirtyRect
.top
= 0;
2715 surface
->dirtyRect
.right
= surface
->resource
.width
;
2716 surface
->dirtyRect
.bottom
= surface
->resource
.height
;
2719 /* if the container is a texture then mark it dirty. */
2720 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
2722 TRACE("Passing to container.\n");
2723 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
2727 HRESULT
surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
2729 DWORD flag
= srgb
? SFLAG_INSRGBTEX
: SFLAG_INTEXTURE
;
2732 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
2734 if (surface
->resource
.pool
== WINED3DPOOL_SCRATCH
)
2736 ERR("Not supported on scratch surfaces.\n");
2737 return WINED3DERR_INVALIDCALL
;
2740 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
2742 /* Reload if either the texture and sysmem have different ideas about the
2743 * color key, or the actual key values changed. */
2744 if (ck_changed
|| ((surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
2745 && (surface
->gl_color_key
.color_space_low_value
!= surface
->src_blt_color_key
.color_space_low_value
2746 || surface
->gl_color_key
.color_space_high_value
!= surface
->src_blt_color_key
.color_space_high_value
)))
2748 TRACE("Reloading because of color keying\n");
2749 /* To perform the color key conversion we need a sysmem copy of
2750 * the surface. Make sure we have it. */
2752 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2753 /* Make sure the texture is reloaded because of the color key change,
2754 * this kills performance though :( */
2755 /* TODO: This is not necessarily needed with hw palettized texture support. */
2756 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
2757 /* Switching color keying on / off may change the internal format. */
2759 surface_force_reload(surface
);
2761 else if (!(surface
->flags
& flag
))
2763 TRACE("Reloading because surface is dirty.\n");
2767 TRACE("surface is already in texture\n");
2771 /* No partial locking for textures yet. */
2772 surface_load_location(surface
, flag
, NULL
);
2773 surface_evict_sysmem(surface
);
2778 /* See also float_16_to_32() in wined3d_private.h */
2779 static inline unsigned short float_32_to_16(const float *in
)
2782 float tmp
= fabsf(*in
);
2783 unsigned int mantissa
;
2786 /* Deal with special numbers */
2792 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2794 if (tmp
< powf(2, 10))
2800 } while (tmp
< powf(2, 10));
2802 else if (tmp
>= powf(2, 11))
2808 } while (tmp
>= powf(2, 11));
2811 mantissa
= (unsigned int)tmp
;
2812 if (tmp
- mantissa
>= 0.5f
)
2813 ++mantissa
; /* Round to nearest, away from zero. */
2815 exp
+= 10; /* Normalize the mantissa. */
2816 exp
+= 15; /* Exponent is encoded with excess 15. */
2818 if (exp
> 30) /* too big */
2820 ret
= 0x7c00; /* INF */
2824 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2827 mantissa
= mantissa
>> 1;
2830 ret
= mantissa
& 0x3ff;
2834 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2837 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2841 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2845 TRACE("Surface %p, container %p of type %#x.\n",
2846 surface
, surface
->container
.u
.base
, surface
->container
.type
);
2848 switch (surface
->container
.type
)
2850 case WINED3D_CONTAINER_TEXTURE
:
2851 return wined3d_texture_incref(surface
->container
.u
.texture
);
2853 case WINED3D_CONTAINER_SWAPCHAIN
:
2854 return wined3d_swapchain_incref(surface
->container
.u
.swapchain
);
2857 ERR("Unhandled container type %#x.\n", surface
->container
.type
);
2858 case WINED3D_CONTAINER_NONE
:
2862 refcount
= InterlockedIncrement(&surface
->resource
.ref
);
2863 TRACE("%p increasing refcount to %u.\n", surface
, refcount
);
2868 /* Do not call while under the GL lock. */
2869 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2873 TRACE("Surface %p, container %p of type %#x.\n",
2874 surface
, surface
->container
.u
.base
, surface
->container
.type
);
2876 switch (surface
->container
.type
)
2878 case WINED3D_CONTAINER_TEXTURE
:
2879 return wined3d_texture_decref(surface
->container
.u
.texture
);
2881 case WINED3D_CONTAINER_SWAPCHAIN
:
2882 return wined3d_swapchain_decref(surface
->container
.u
.swapchain
);
2885 ERR("Unhandled container type %#x.\n", surface
->container
.type
);
2886 case WINED3D_CONTAINER_NONE
:
2890 refcount
= InterlockedDecrement(&surface
->resource
.ref
);
2891 TRACE("%p decreasing refcount to %u.\n", surface
, refcount
);
2895 surface_cleanup(surface
);
2896 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
2898 TRACE("Destroyed surface %p.\n", surface
);
2899 HeapFree(GetProcessHeap(), 0, surface
);
2905 DWORD CDECL
wined3d_surface_set_priority(struct wined3d_surface
*surface
, DWORD priority
)
2907 return resource_set_priority(&surface
->resource
, priority
);
2910 DWORD CDECL
wined3d_surface_get_priority(const struct wined3d_surface
*surface
)
2912 return resource_get_priority(&surface
->resource
);
2915 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2917 TRACE("surface %p.\n", surface
);
2919 if (!surface
->resource
.device
->d3d_initialized
)
2921 ERR("D3D not initialized.\n");
2925 surface_internal_preload(surface
, SRGB_ANY
);
2928 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2930 TRACE("surface %p.\n", surface
);
2932 return surface
->resource
.parent
;
2935 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2937 TRACE("surface %p.\n", surface
);
2939 return &surface
->resource
;
2942 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2944 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2948 case WINEDDGBS_CANBLT
:
2949 case WINEDDGBS_ISBLTDONE
:
2953 return WINED3DERR_INVALIDCALL
;
2957 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2959 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2961 /* XXX: DDERR_INVALIDSURFACETYPE */
2965 case WINEDDGFS_CANFLIP
:
2966 case WINEDDGFS_ISFLIPDONE
:
2970 return WINED3DERR_INVALIDCALL
;
2974 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2976 TRACE("surface %p.\n", surface
);
2978 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2979 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2982 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2984 TRACE("surface %p.\n", surface
);
2986 surface
->flags
&= ~SFLAG_LOST
;
2990 HRESULT CDECL
wined3d_surface_set_palette(struct wined3d_surface
*surface
, struct wined3d_palette
*palette
)
2992 TRACE("surface %p, palette %p.\n", surface
, palette
);
2994 if (surface
->palette
== palette
)
2996 TRACE("Nop palette change.\n");
3000 if (surface
->palette
&& (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
3001 surface
->palette
->flags
&= ~WINEDDPCAPS_PRIMARYSURFACE
;
3003 surface
->palette
= palette
;
3007 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
3008 palette
->flags
|= WINEDDPCAPS_PRIMARYSURFACE
;
3010 surface
->surface_ops
->surface_realize_palette(surface
);
3016 HRESULT CDECL
wined3d_surface_set_color_key(struct wined3d_surface
*surface
,
3017 DWORD flags
, const struct wined3d_color_key
*color_key
)
3019 TRACE("surface %p, flags %#x, color_key %p.\n", surface
, flags
, color_key
);
3021 if (flags
& WINEDDCKEY_COLORSPACE
)
3023 FIXME(" colorkey value not supported (%08x) !\n", flags
);
3024 return WINED3DERR_INVALIDCALL
;
3027 /* Dirtify the surface, but only if a key was changed. */
3030 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
3032 case WINEDDCKEY_DESTBLT
:
3033 surface
->dst_blt_color_key
= *color_key
;
3034 surface
->CKeyFlags
|= WINEDDSD_CKDESTBLT
;
3037 case WINEDDCKEY_DESTOVERLAY
:
3038 surface
->dst_overlay_color_key
= *color_key
;
3039 surface
->CKeyFlags
|= WINEDDSD_CKDESTOVERLAY
;
3042 case WINEDDCKEY_SRCOVERLAY
:
3043 surface
->src_overlay_color_key
= *color_key
;
3044 surface
->CKeyFlags
|= WINEDDSD_CKSRCOVERLAY
;
3047 case WINEDDCKEY_SRCBLT
:
3048 surface
->src_blt_color_key
= *color_key
;
3049 surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
3055 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
3057 case WINEDDCKEY_DESTBLT
:
3058 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTBLT
;
3061 case WINEDDCKEY_DESTOVERLAY
:
3062 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTOVERLAY
;
3065 case WINEDDCKEY_SRCOVERLAY
:
3066 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCOVERLAY
;
3069 case WINEDDCKEY_SRCBLT
:
3070 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
3078 struct wined3d_palette
* CDECL
wined3d_surface_get_palette(const struct wined3d_surface
*surface
)
3080 TRACE("surface %p.\n", surface
);
3082 return surface
->palette
;
3085 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
3087 const struct wined3d_format
*format
= surface
->resource
.format
;
3090 TRACE("surface %p.\n", surface
);
3092 if (format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
3094 /* Since compressed formats are block based, pitch means the amount of
3095 * bytes to the next row of block rather than the next row of pixels. */
3096 UINT row_block_count
= (surface
->resource
.width
+ format
->block_width
- 1) / format
->block_width
;
3097 pitch
= row_block_count
* format
->block_byte_count
;
3101 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
3102 pitch
= surface
->resource
.format
->byte_count
* surface
->resource
.width
; /* Bytes / row */
3103 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
3106 TRACE("Returning %u.\n", pitch
);
3111 HRESULT CDECL
wined3d_surface_set_mem(struct wined3d_surface
*surface
, void *mem
)
3113 TRACE("surface %p, mem %p.\n", surface
, mem
);
3115 if (surface
->flags
& (SFLAG_LOCKED
| SFLAG_DCINUSE
))
3117 WARN("Surface is locked or the DC is in use.\n");
3118 return WINED3DERR_INVALIDCALL
;
3121 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3122 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
3124 ERR("Not supported on render targets.\n");
3125 return WINED3DERR_INVALIDCALL
;
3128 if (mem
&& mem
!= surface
->resource
.allocatedMemory
)
3130 void *release
= NULL
;
3132 /* Do I have to copy the old surface content? */
3133 if (surface
->flags
& SFLAG_DIBSECTION
)
3135 DeleteDC(surface
->hDC
);
3136 DeleteObject(surface
->dib
.DIBsection
);
3137 surface
->dib
.bitmap_data
= NULL
;
3138 surface
->resource
.allocatedMemory
= NULL
;
3139 surface
->hDC
= NULL
;
3140 surface
->flags
&= ~SFLAG_DIBSECTION
;
3142 else if (!(surface
->flags
& SFLAG_USERPTR
))
3144 release
= surface
->resource
.heapMemory
;
3145 surface
->resource
.heapMemory
= NULL
;
3147 surface
->resource
.allocatedMemory
= mem
;
3148 surface
->flags
|= SFLAG_USERPTR
;
3150 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3151 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3153 /* For client textures OpenGL has to be notified. */
3154 if (surface
->flags
& SFLAG_CLIENT
)
3155 surface_release_client_storage(surface
);
3157 /* Now free the old memory if any. */
3158 HeapFree(GetProcessHeap(), 0, release
);
3160 else if (surface
->flags
& SFLAG_USERPTR
)
3162 /* HeapMemory should be NULL already. */
3163 if (surface
->resource
.heapMemory
)
3164 ERR("User pointer surface has heap memory allocated.\n");
3168 surface
->resource
.allocatedMemory
= NULL
;
3169 surface
->flags
&= ~(SFLAG_USERPTR
| SFLAG_INSYSMEM
);
3171 if (surface
->flags
& SFLAG_CLIENT
)
3172 surface_release_client_storage(surface
);
3174 surface_prepare_system_memory(surface
);
3177 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3183 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
3187 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
3189 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3191 WARN("Not an overlay surface.\n");
3192 return WINEDDERR_NOTAOVERLAYSURFACE
;
3195 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
3196 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
3197 surface
->overlay_destrect
.left
= x
;
3198 surface
->overlay_destrect
.top
= y
;
3199 surface
->overlay_destrect
.right
= x
+ w
;
3200 surface
->overlay_destrect
.bottom
= y
+ h
;
3202 surface_draw_overlay(surface
);
3207 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
3209 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
3211 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3213 TRACE("Not an overlay surface.\n");
3214 return WINEDDERR_NOTAOVERLAYSURFACE
;
3217 if (!surface
->overlay_dest
)
3219 TRACE("Overlay not visible.\n");
3222 return WINEDDERR_OVERLAYNOTVISIBLE
;
3225 *x
= surface
->overlay_destrect
.left
;
3226 *y
= surface
->overlay_destrect
.top
;
3228 TRACE("Returning position %d, %d.\n", *x
, *y
);
3233 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
3234 DWORD flags
, struct wined3d_surface
*ref
)
3236 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
3238 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3240 TRACE("Not an overlay surface.\n");
3241 return WINEDDERR_NOTAOVERLAYSURFACE
;
3247 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
3248 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
3250 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3251 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
3253 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3255 WARN("Not an overlay surface.\n");
3256 return WINEDDERR_NOTAOVERLAYSURFACE
;
3258 else if (!dst_surface
)
3260 WARN("Dest surface is NULL.\n");
3261 return WINED3DERR_INVALIDCALL
;
3266 surface
->overlay_srcrect
= *src_rect
;
3270 surface
->overlay_srcrect
.left
= 0;
3271 surface
->overlay_srcrect
.top
= 0;
3272 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
3273 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
3278 surface
->overlay_destrect
= *dst_rect
;
3282 surface
->overlay_destrect
.left
= 0;
3283 surface
->overlay_destrect
.top
= 0;
3284 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
3285 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
3288 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
3290 surface
->overlay_dest
= NULL
;
3291 list_remove(&surface
->overlay_entry
);
3294 if (flags
& WINEDDOVER_SHOW
)
3296 if (surface
->overlay_dest
!= dst_surface
)
3298 surface
->overlay_dest
= dst_surface
;
3299 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
3302 else if (flags
& WINEDDOVER_HIDE
)
3304 /* tests show that the rectangles are erased on hide */
3305 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
3306 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
3307 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
3308 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
3309 surface
->overlay_dest
= NULL
;
3312 surface_draw_overlay(surface
);
3317 HRESULT CDECL
wined3d_surface_set_format(struct wined3d_surface
*surface
, enum wined3d_format_id format_id
)
3319 const struct wined3d_format
*format
= wined3d_get_format(&surface
->resource
.device
->adapter
->gl_info
, format_id
);
3321 TRACE("surface %p, format %s.\n", surface
, debug_d3dformat(format_id
));
3323 if (surface
->resource
.format
->id
!= WINED3DFMT_UNKNOWN
)
3325 FIXME("The format of the surface must be WINED3DFORMAT_UNKNOWN.\n");
3326 return WINED3DERR_INVALIDCALL
;
3329 surface
->resource
.size
= wined3d_format_calculate_size(format
, surface
->resource
.device
->surface_alignment
,
3330 surface
->pow2Width
, surface
->pow2Height
);
3331 surface
->flags
|= (WINED3DFMT_D16_LOCKABLE
== format_id
) ? SFLAG_LOCKABLE
: 0;
3332 surface
->resource
.format
= format
;
3334 TRACE("size %u, byte_count %u\n", surface
->resource
.size
, format
->byte_count
);
3335 TRACE("glFormat %#x, glInternal %#x, glType %#x.\n",
3336 format
->glFormat
, format
->glInternal
, format
->glType
);
3341 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
3342 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3344 unsigned short *dst_s
;
3348 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3350 for (y
= 0; y
< h
; ++y
)
3352 src_f
= (const float *)(src
+ y
* pitch_in
);
3353 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
3354 for (x
= 0; x
< w
; ++x
)
3356 dst_s
[x
] = float_32_to_16(src_f
+ x
);
3361 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3362 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3364 static const unsigned char convert_5to8
[] =
3366 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3367 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3368 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3369 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3371 static const unsigned char convert_6to8
[] =
3373 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3374 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3375 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3376 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3377 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3378 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3379 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3380 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3384 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3386 for (y
= 0; y
< h
; ++y
)
3388 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
3389 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3390 for (x
= 0; x
< w
; ++x
)
3392 WORD pixel
= src_line
[x
];
3393 dst_line
[x
] = 0xff000000
3394 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
3395 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
3396 | convert_5to8
[(pixel
& 0x001f)];
3401 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3402 * in both cases we're just setting the X / Alpha channel to 0xff. */
3403 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3404 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3408 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3410 for (y
= 0; y
< h
; ++y
)
3412 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
3413 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3415 for (x
= 0; x
< w
; ++x
)
3417 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
3422 static inline BYTE
cliptobyte(int x
)
3424 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
3427 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3428 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3430 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3433 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3435 for (y
= 0; y
< h
; ++y
)
3437 const BYTE
*src_line
= src
+ y
* pitch_in
;
3438 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3439 for (x
= 0; x
< w
; ++x
)
3441 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3442 * C = Y - 16; D = U - 128; E = V - 128;
3443 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3444 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3445 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3446 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3447 * U and V are shared between the pixels. */
3448 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3450 d
= (int) src_line
[1] - 128;
3451 e
= (int) src_line
[3] - 128;
3453 g2
= - 100 * d
- 208 * e
+ 128;
3456 c2
= 298 * ((int) src_line
[0] - 16);
3457 dst_line
[x
] = 0xff000000
3458 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
3459 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
3460 | cliptobyte((c2
+ b2
) >> 8); /* blue */
3461 /* Scale RGB values to 0..255 range,
3462 * then clip them if still not in range (may be negative),
3463 * then shift them within DWORD if necessary. */
3469 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
3470 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3473 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3475 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
3477 for (y
= 0; y
< h
; ++y
)
3479 const BYTE
*src_line
= src
+ y
* pitch_in
;
3480 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
3481 for (x
= 0; x
< w
; ++x
)
3483 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3484 * C = Y - 16; D = U - 128; E = V - 128;
3485 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3486 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3487 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3488 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3489 * U and V are shared between the pixels. */
3490 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3492 d
= (int) src_line
[1] - 128;
3493 e
= (int) src_line
[3] - 128;
3495 g2
= - 100 * d
- 208 * e
+ 128;
3498 c2
= 298 * ((int) src_line
[0] - 16);
3499 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
3500 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
3501 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
3502 /* Scale RGB values to 0..255 range,
3503 * then clip them if still not in range (may be negative),
3504 * then shift them within DWORD if necessary. */
3510 struct d3dfmt_convertor_desc
3512 enum wined3d_format_id from
, to
;
3513 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
3516 static const struct d3dfmt_convertor_desc convertors
[] =
3518 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
3519 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
3520 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3521 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3522 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
3523 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
3526 static inline const struct d3dfmt_convertor_desc
*find_convertor(enum wined3d_format_id from
,
3527 enum wined3d_format_id to
)
3531 for (i
= 0; i
< (sizeof(convertors
) / sizeof(*convertors
)); ++i
)
3533 if (convertors
[i
].from
== from
&& convertors
[i
].to
== to
)
3534 return &convertors
[i
];
3540 /*****************************************************************************
3541 * surface_convert_format
3543 * Creates a duplicate of a surface in a different format. Is used by Blt to
3544 * blit between surfaces with different formats.
3547 * source: Source surface
3548 * fmt: Requested destination format
3550 *****************************************************************************/
3551 static struct wined3d_surface
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
3553 struct wined3d_mapped_rect src_map
, dst_map
;
3554 const struct d3dfmt_convertor_desc
*conv
;
3555 struct wined3d_surface
*ret
= NULL
;
3558 conv
= find_convertor(source
->resource
.format
->id
, to_fmt
);
3561 FIXME("Cannot find a conversion function from format %s to %s.\n",
3562 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
3566 wined3d_surface_create(source
->resource
.device
, source
->resource
.width
,
3567 source
->resource
.height
, to_fmt
, 0 /* level */, 0 /* usage */, WINED3DPOOL_SCRATCH
,
3568 WINED3D_MULTISAMPLE_NONE
/* TODO: Multisampled conversion */, 0 /* MultiSampleQuality */,
3569 source
->surface_type
, WINED3D_SURFACE_MAPPABLE
| WINED3D_SURFACE_DISCARD
,
3570 NULL
/* parent */, &wined3d_null_parent_ops
, &ret
);
3573 ERR("Failed to create a destination surface for conversion.\n");
3577 memset(&src_map
, 0, sizeof(src_map
));
3578 memset(&dst_map
, 0, sizeof(dst_map
));
3580 hr
= wined3d_surface_map(source
, &src_map
, NULL
, WINED3DLOCK_READONLY
);
3583 ERR("Failed to lock the source surface.\n");
3584 wined3d_surface_decref(ret
);
3587 hr
= wined3d_surface_map(ret
, &dst_map
, NULL
, WINED3DLOCK_READONLY
);
3590 ERR("Failed to lock the destination surface.\n");
3591 wined3d_surface_unmap(source
);
3592 wined3d_surface_decref(ret
);
3596 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
3597 source
->resource
.width
, source
->resource
.height
);
3599 wined3d_surface_unmap(ret
);
3600 wined3d_surface_unmap(source
);
3605 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
3606 unsigned int bpp
, UINT pitch
, DWORD color
)
3613 #define COLORFILL_ROW(type) \
3615 type *d = (type *)buf; \
3616 for (x = 0; x < width; ++x) \
3617 d[x] = (type)color; \
3623 COLORFILL_ROW(BYTE
);
3627 COLORFILL_ROW(WORD
);
3633 for (x
= 0; x
< width
; ++x
, d
+= 3)
3635 d
[0] = (color
) & 0xFF;
3636 d
[1] = (color
>> 8) & 0xFF;
3637 d
[2] = (color
>> 16) & 0xFF;
3642 COLORFILL_ROW(DWORD
);
3646 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
3647 return WINED3DERR_NOTAVAILABLE
;
3650 #undef COLORFILL_ROW
3652 /* Now copy first row. */
3654 for (y
= 1; y
< height
; ++y
)
3657 memcpy(buf
, first
, width
* bpp
);
3663 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
3665 TRACE("surface %p.\n", surface
);
3667 if (!(surface
->flags
& SFLAG_LOCKED
))
3669 WARN("Trying to unmap unmapped surface.\n");
3670 return WINEDDERR_NOTLOCKED
;
3672 surface
->flags
&= ~SFLAG_LOCKED
;
3674 surface
->surface_ops
->surface_unmap(surface
);
3679 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
3680 struct wined3d_mapped_rect
*mapped_rect
, const RECT
*rect
, DWORD flags
)
3682 const struct wined3d_format
*format
= surface
->resource
.format
;
3684 TRACE("surface %p, mapped_rect %p, rect %s, flags %#x.\n",
3685 surface
, mapped_rect
, wine_dbgstr_rect(rect
), flags
);
3687 if (surface
->flags
& SFLAG_LOCKED
)
3689 WARN("Surface is already mapped.\n");
3690 return WINED3DERR_INVALIDCALL
;
3692 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
3693 && rect
&& (rect
->left
|| rect
->top
3694 || rect
->right
!= surface
->resource
.width
3695 || rect
->bottom
!= surface
->resource
.height
))
3697 UINT width_mask
= format
->block_width
- 1;
3698 UINT height_mask
= format
->block_height
- 1;
3700 if ((rect
->left
& width_mask
) || (rect
->right
& width_mask
)
3701 || (rect
->top
& height_mask
) || (rect
->bottom
& height_mask
))
3703 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
3704 wine_dbgstr_rect(rect
), format
->block_width
, format
->block_height
);
3706 if (surface
->resource
.pool
== WINED3DPOOL_DEFAULT
)
3707 return WINED3DERR_INVALIDCALL
;
3711 surface
->flags
|= SFLAG_LOCKED
;
3713 if (!(surface
->flags
& SFLAG_LOCKABLE
))
3714 WARN("Trying to lock unlockable surface.\n");
3716 /* Performance optimization: Count how often a surface is mapped, if it is
3717 * mapped regularly do not throw away the system memory copy. This avoids
3718 * the need to download the surface from OpenGL all the time. The surface
3719 * is still downloaded if the OpenGL texture is changed. */
3720 if (!(surface
->flags
& SFLAG_DYNLOCK
))
3722 if (++surface
->lockCount
> MAXLOCKCOUNT
)
3724 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3725 surface
->flags
|= SFLAG_DYNLOCK
;
3729 surface
->surface_ops
->surface_map(surface
, rect
, flags
);
3731 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
3732 mapped_rect
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
3734 mapped_rect
->row_pitch
= wined3d_surface_get_pitch(surface
);
3738 mapped_rect
->data
= surface
->resource
.allocatedMemory
;
3739 surface
->lockedRect
.left
= 0;
3740 surface
->lockedRect
.top
= 0;
3741 surface
->lockedRect
.right
= surface
->resource
.width
;
3742 surface
->lockedRect
.bottom
= surface
->resource
.height
;
3746 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
3748 /* Compressed textures are block based, so calculate the offset of
3749 * the block that contains the top-left pixel of the locked rectangle. */
3750 mapped_rect
->data
= surface
->resource
.allocatedMemory
3751 + ((rect
->top
/ format
->block_height
) * mapped_rect
->row_pitch
)
3752 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
3756 mapped_rect
->data
= surface
->resource
.allocatedMemory
3757 + (mapped_rect
->row_pitch
* rect
->top
)
3758 + (rect
->left
* format
->byte_count
);
3760 surface
->lockedRect
.left
= rect
->left
;
3761 surface
->lockedRect
.top
= rect
->top
;
3762 surface
->lockedRect
.right
= rect
->right
;
3763 surface
->lockedRect
.bottom
= rect
->bottom
;
3766 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
3767 TRACE("Returning memory %p, pitch %u.\n", mapped_rect
->data
, mapped_rect
->row_pitch
);
3772 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
3774 struct wined3d_mapped_rect map
;
3777 TRACE("surface %p, dc %p.\n", surface
, dc
);
3779 if (surface
->flags
& SFLAG_USERPTR
)
3781 ERR("Not supported on surfaces with application-provided memory.\n");
3782 return WINEDDERR_NODC
;
3785 /* Give more detailed info for ddraw. */
3786 if (surface
->flags
& SFLAG_DCINUSE
)
3787 return WINEDDERR_DCALREADYCREATED
;
3789 /* Can't GetDC if the surface is locked. */
3790 if (surface
->flags
& SFLAG_LOCKED
)
3791 return WINED3DERR_INVALIDCALL
;
3793 /* Create a DIB section if there isn't a dc yet. */
3796 if (surface
->flags
& SFLAG_CLIENT
)
3798 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
3799 surface_release_client_storage(surface
);
3801 hr
= surface_create_dib_section(surface
);
3803 return WINED3DERR_INVALIDCALL
;
3805 /* Use the DIB section from now on if we are not using a PBO. */
3806 if (!(surface
->flags
& SFLAG_PBO
))
3807 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
3810 /* Map the surface. */
3811 hr
= wined3d_surface_map(surface
, &map
, NULL
, 0);
3814 ERR("Map failed, hr %#x.\n", hr
);
3818 /* Sync the DIB with the PBO. This can't be done earlier because Map()
3819 * activates the allocatedMemory. */
3820 if (surface
->flags
& SFLAG_PBO
)
3821 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
3823 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3824 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3826 /* GetDC on palettized formats is unsupported in D3D9, and the method
3827 * is missing in D3D8, so this should only be used for DX <=7
3828 * surfaces (with non-device palettes). */
3829 const PALETTEENTRY
*pal
= NULL
;
3831 if (surface
->palette
)
3833 pal
= surface
->palette
->palents
;
3837 struct wined3d_swapchain
*swapchain
= surface
->resource
.device
->swapchains
[0];
3838 struct wined3d_surface
*dds_primary
= swapchain
->front_buffer
;
3840 if (dds_primary
&& dds_primary
->palette
)
3841 pal
= dds_primary
->palette
->palents
;
3849 for (i
= 0; i
< 256; ++i
)
3851 col
[i
].rgbRed
= pal
[i
].peRed
;
3852 col
[i
].rgbGreen
= pal
[i
].peGreen
;
3853 col
[i
].rgbBlue
= pal
[i
].peBlue
;
3854 col
[i
].rgbReserved
= 0;
3856 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
3860 surface
->flags
|= SFLAG_DCINUSE
;
3863 TRACE("Returning dc %p.\n", *dc
);
3868 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
3870 TRACE("surface %p, dc %p.\n", surface
, dc
);
3872 if (!(surface
->flags
& SFLAG_DCINUSE
))
3873 return WINEDDERR_NODC
;
3875 if (surface
->hDC
!= dc
)
3877 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3879 return WINEDDERR_NODC
;
3882 /* Copy the contents of the DIB over to the PBO. */
3883 if ((surface
->flags
& SFLAG_PBO
) && surface
->resource
.allocatedMemory
)
3884 memcpy(surface
->resource
.allocatedMemory
, surface
->dib
.bitmap_data
, surface
->resource
.size
);
3886 /* We locked first, so unlock now. */
3887 wined3d_surface_unmap(surface
);
3889 surface
->flags
&= ~SFLAG_DCINUSE
;
3894 HRESULT CDECL
wined3d_surface_flip(struct wined3d_surface
*surface
, struct wined3d_surface
*override
, DWORD flags
)
3896 TRACE("surface %p, override %p, flags %#x.\n", surface
, override
, flags
);
3902 FIXME("Ignoring flags %#x.\n", flags
);
3904 WARN("Ignoring flags %#x.\n", flags
);
3907 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
3909 ERR("Not supported on swapchain surfaces.\n");
3910 return WINEDDERR_NOTFLIPPABLE
;
3913 /* Flipping is only supported on render targets and overlays. */
3914 if (!(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_OVERLAY
)))
3916 WARN("Tried to flip a non-render target, non-overlay surface.\n");
3917 return WINEDDERR_NOTFLIPPABLE
;
3920 flip_surface(surface
, override
);
3922 /* Update overlays if they're visible. */
3923 if ((surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
) && surface
->overlay_dest
)
3924 return surface_draw_overlay(surface
);
3929 /* Do not call while under the GL lock. */
3930 void surface_internal_preload(struct wined3d_surface
*surface
, enum WINED3DSRGB srgb
)
3932 struct wined3d_device
*device
= surface
->resource
.device
;
3934 TRACE("iface %p, srgb %#x.\n", surface
, srgb
);
3936 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
3938 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
3940 TRACE("Passing to container (%p).\n", texture
);
3941 texture
->texture_ops
->texture_preload(texture
, srgb
);
3945 struct wined3d_context
*context
;
3947 TRACE("(%p) : About to load surface\n", surface
);
3949 /* TODO: Use already acquired context when possible. */
3950 context
= context_acquire(device
, NULL
);
3952 surface_load(surface
, srgb
== SRGB_SRGB
? TRUE
: FALSE
);
3954 if (surface
->resource
.pool
== WINED3DPOOL_DEFAULT
)
3956 /* Tell opengl to try and keep this texture in video ram (well mostly) */
3960 glPrioritizeTextures(1, &surface
->texture_name
, &tmp
);
3964 context_release(context
);
3968 BOOL
surface_init_sysmem(struct wined3d_surface
*surface
)
3970 if (!surface
->resource
.allocatedMemory
)
3972 if (!surface
->resource
.heapMemory
)
3974 if (!(surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
3975 surface
->resource
.size
+ RESOURCE_ALIGNMENT
)))
3977 ERR("Failed to allocate memory.\n");
3981 else if (!(surface
->flags
& SFLAG_CLIENT
))
3983 ERR("Surface %p has heapMemory %p and flags %#x.\n",
3984 surface
, surface
->resource
.heapMemory
, surface
->flags
);
3987 surface
->resource
.allocatedMemory
=
3988 (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
3992 memset(surface
->resource
.allocatedMemory
, 0, surface
->resource
.size
);
3995 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
4000 /* Read the framebuffer back into the surface */
4001 static void read_from_framebuffer(struct wined3d_surface
*surface
, const RECT
*rect
, void *dest
, UINT pitch
)
4003 struct wined3d_device
*device
= surface
->resource
.device
;
4004 const struct wined3d_gl_info
*gl_info
;
4005 struct wined3d_context
*context
;
4009 BYTE
*row
, *top
, *bottom
;
4013 BOOL srcIsUpsideDown
;
4018 context
= context_acquire(device
, surface
);
4019 context_apply_blit_state(context
, device
);
4020 gl_info
= context
->gl_info
;
4024 /* Select the correct read buffer, and give some debug output.
4025 * There is no need to keep track of the current read buffer or reset it, every part of the code
4026 * that reads sets the read buffer as desired.
4028 if (surface_is_offscreen(surface
))
4030 /* Mapping the primary render target which is not on a swapchain.
4031 * Read from the back buffer. */
4032 TRACE("Mapping offscreen render target.\n");
4033 glReadBuffer(device
->offscreenBuffer
);
4034 srcIsUpsideDown
= TRUE
;
4038 /* Onscreen surfaces are always part of a swapchain */
4039 GLenum buffer
= surface_get_gl_buffer(surface
);
4040 TRACE("Mapping %#x buffer.\n", buffer
);
4041 glReadBuffer(buffer
);
4042 checkGLcall("glReadBuffer");
4043 srcIsUpsideDown
= FALSE
;
4046 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4049 local_rect
.left
= 0;
4051 local_rect
.right
= surface
->resource
.width
;
4052 local_rect
.bottom
= surface
->resource
.height
;
4058 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4060 switch (surface
->resource
.format
->id
)
4062 case WINED3DFMT_P8_UINT
:
4064 if (primary_render_target_is_p8(device
))
4066 /* In case of P8 render targets the index is stored in the alpha component */
4068 type
= GL_UNSIGNED_BYTE
;
4070 bpp
= surface
->resource
.format
->byte_count
;
4074 /* GL can't return palettized data, so read ARGB pixels into a
4075 * separate block of memory and convert them into palettized format
4076 * in software. Slow, but if the app means to use palettized render
4077 * targets and locks it...
4079 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4080 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4081 * for the color channels when palettizing the colors.
4084 type
= GL_UNSIGNED_BYTE
;
4086 mem
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
* 3);
4089 ERR("Out of memory\n");
4093 bpp
= surface
->resource
.format
->byte_count
* 3;
4100 fmt
= surface
->resource
.format
->glFormat
;
4101 type
= surface
->resource
.format
->glType
;
4102 bpp
= surface
->resource
.format
->byte_count
;
4105 if (surface
->flags
& SFLAG_PBO
)
4107 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
4108 checkGLcall("glBindBufferARB");
4111 ERR("mem not null for pbo -- unexpected\n");
4116 /* Save old pixel store pack state */
4117 glGetIntegerv(GL_PACK_ROW_LENGTH
, &rowLen
);
4118 checkGLcall("glGetIntegerv");
4119 glGetIntegerv(GL_PACK_SKIP_PIXELS
, &skipPix
);
4120 checkGLcall("glGetIntegerv");
4121 glGetIntegerv(GL_PACK_SKIP_ROWS
, &skipRow
);
4122 checkGLcall("glGetIntegerv");
4124 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4125 glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
4126 checkGLcall("glPixelStorei");
4127 glPixelStorei(GL_PACK_SKIP_PIXELS
, local_rect
.left
);
4128 checkGLcall("glPixelStorei");
4129 glPixelStorei(GL_PACK_SKIP_ROWS
, local_rect
.top
);
4130 checkGLcall("glPixelStorei");
4132 glReadPixels(local_rect
.left
, !srcIsUpsideDown
? (surface
->resource
.height
- local_rect
.bottom
) : local_rect
.top
,
4133 local_rect
.right
- local_rect
.left
,
4134 local_rect
.bottom
- local_rect
.top
,
4136 checkGLcall("glReadPixels");
4138 /* Reset previous pixel store pack state */
4139 glPixelStorei(GL_PACK_ROW_LENGTH
, rowLen
);
4140 checkGLcall("glPixelStorei");
4141 glPixelStorei(GL_PACK_SKIP_PIXELS
, skipPix
);
4142 checkGLcall("glPixelStorei");
4143 glPixelStorei(GL_PACK_SKIP_ROWS
, skipRow
);
4144 checkGLcall("glPixelStorei");
4146 if (surface
->flags
& SFLAG_PBO
)
4148 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
4149 checkGLcall("glBindBufferARB");
4151 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4152 * to get a pointer to it and perform the flipping in software. This is a lot
4153 * faster than calling glReadPixels for each line. In case we want more speed
4154 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4155 if (!srcIsUpsideDown
)
4157 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
4158 checkGLcall("glBindBufferARB");
4160 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
4161 checkGLcall("glMapBufferARB");
4165 /* TODO: Merge this with the palettization loop below for P8 targets */
4166 if(!srcIsUpsideDown
) {
4168 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4169 Flip the lines in software */
4170 len
= (local_rect
.right
- local_rect
.left
) * bpp
;
4171 off
= local_rect
.left
* bpp
;
4173 row
= HeapAlloc(GetProcessHeap(), 0, len
);
4175 ERR("Out of memory\n");
4176 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
4177 HeapFree(GetProcessHeap(), 0, mem
);
4182 top
= mem
+ pitch
* local_rect
.top
;
4183 bottom
= mem
+ pitch
* (local_rect
.bottom
- 1);
4184 for(i
= 0; i
< (local_rect
.bottom
- local_rect
.top
) / 2; i
++) {
4185 memcpy(row
, top
+ off
, len
);
4186 memcpy(top
+ off
, bottom
+ off
, len
);
4187 memcpy(bottom
+ off
, row
, len
);
4191 HeapFree(GetProcessHeap(), 0, row
);
4193 /* Unmap the temp PBO buffer */
4194 if (surface
->flags
& SFLAG_PBO
)
4196 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
4197 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4202 context_release(context
);
4204 /* For P8 textures we need to perform an inverse palette lookup. This is
4205 * done by searching for a palette index which matches the RGB value.
4206 * Note this isn't guaranteed to work when there are multiple entries for
4207 * the same color but we have no choice. In case of P8 render targets,
4208 * the index is stored in the alpha component so no conversion is needed. */
4209 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
&& !primary_render_target_is_p8(device
))
4211 const PALETTEENTRY
*pal
= NULL
;
4212 DWORD width
= pitch
/ 3;
4215 if (surface
->palette
)
4217 pal
= surface
->palette
->palents
;
4221 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4222 HeapFree(GetProcessHeap(), 0, mem
);
4226 for(y
= local_rect
.top
; y
< local_rect
.bottom
; y
++) {
4227 for(x
= local_rect
.left
; x
< local_rect
.right
; x
++) {
4228 /* start lines pixels */
4229 const BYTE
*blue
= mem
+ y
* pitch
+ x
* (sizeof(BYTE
) * 3);
4230 const BYTE
*green
= blue
+ 1;
4231 const BYTE
*red
= green
+ 1;
4233 for(c
= 0; c
< 256; c
++) {
4234 if(*red
== pal
[c
].peRed
&&
4235 *green
== pal
[c
].peGreen
&&
4236 *blue
== pal
[c
].peBlue
)
4238 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
4244 HeapFree(GetProcessHeap(), 0, mem
);
4248 /* Read the framebuffer contents into a texture. Note that this function
4249 * doesn't do any kind of flipping. Using this on an onscreen surface will
4250 * result in a flipped D3D texture. */
4251 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
)
4253 struct wined3d_device
*device
= surface
->resource
.device
;
4254 struct wined3d_context
*context
;
4256 context
= context_acquire(device
, surface
);
4257 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
4259 surface_prepare_texture(surface
, context
, srgb
);
4260 surface_bind_and_dirtify(surface
, context
, srgb
);
4262 TRACE("Reading back offscreen render target %p.\n", surface
);
4266 if (surface_is_offscreen(surface
))
4267 glReadBuffer(device
->offscreenBuffer
);
4269 glReadBuffer(surface_get_gl_buffer(surface
));
4270 checkGLcall("glReadBuffer");
4272 glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
4273 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
4274 checkGLcall("glCopyTexSubImage2D");
4278 context_release(context
);
4281 /* Context activation is done by the caller. */
4282 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
4283 struct wined3d_context
*context
, BOOL srgb
)
4285 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
4286 CONVERT_TYPES convert
;
4287 struct wined3d_format format
;
4289 if (surface
->flags
& alloc_flag
) return;
4291 d3dfmt_get_conv(surface
, TRUE
, TRUE
, &format
, &convert
);
4292 if (convert
!= NO_CONVERSION
|| format
.convert
) surface
->flags
|= SFLAG_CONVERTED
;
4293 else surface
->flags
&= ~SFLAG_CONVERTED
;
4295 surface_bind_and_dirtify(surface
, context
, srgb
);
4296 surface_allocate_surface(surface
, context
->gl_info
, &format
, srgb
);
4297 surface
->flags
|= alloc_flag
;
4300 /* Context activation is done by the caller. */
4301 void surface_prepare_texture(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
4303 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
4305 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
4306 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
4309 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
4311 for (i
= 0; i
< sub_count
; ++i
)
4313 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
4314 surface_prepare_texture_internal(s
, context
, srgb
);
4320 surface_prepare_texture_internal(surface
, context
, srgb
);
4323 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
4327 if (surface
->rb_multisample
)
4330 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
4331 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
4332 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
4333 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
4334 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
4338 if (surface
->rb_resolved
)
4341 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
4342 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
4343 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
4344 surface
->pow2Width
, surface
->pow2Height
);
4345 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
4349 static void flush_to_framebuffer_drawpixels(struct wined3d_surface
*surface
,
4350 const RECT
*rect
, GLenum fmt
, GLenum type
, UINT bpp
, const BYTE
*mem
)
4352 struct wined3d_device
*device
= surface
->resource
.device
;
4353 UINT pitch
= wined3d_surface_get_pitch(surface
);
4354 const struct wined3d_gl_info
*gl_info
;
4355 struct wined3d_context
*context
;
4359 surface_get_rect(surface
, rect
, &local_rect
);
4361 mem
+= local_rect
.top
* pitch
+ local_rect
.left
* bpp
;
4362 w
= local_rect
.right
- local_rect
.left
;
4363 h
= local_rect
.bottom
- local_rect
.top
;
4365 /* Activate the correct context for the render target */
4366 context
= context_acquire(device
, surface
);
4367 context_apply_blit_state(context
, device
);
4368 gl_info
= context
->gl_info
;
4372 if (!surface_is_offscreen(surface
))
4374 GLenum buffer
= surface_get_gl_buffer(surface
);
4375 TRACE("Unlocking %#x buffer.\n", buffer
);
4376 context_set_draw_buffer(context
, buffer
);
4378 surface_translate_drawable_coords(surface
, context
->win_handle
, &local_rect
);
4379 glPixelZoom(1.0f
, -1.0f
);
4383 /* Primary offscreen render target */
4384 TRACE("Offscreen render target.\n");
4385 context_set_draw_buffer(context
, device
->offscreenBuffer
);
4387 glPixelZoom(1.0f
, 1.0f
);
4390 glRasterPos3i(local_rect
.left
, local_rect
.top
, 1);
4391 checkGLcall("glRasterPos3i");
4393 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4394 glPixelStorei(GL_UNPACK_ROW_LENGTH
, surface
->resource
.width
);
4396 if (surface
->flags
& SFLAG_PBO
)
4398 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
4399 checkGLcall("glBindBufferARB");
4402 glDrawPixels(w
, h
, fmt
, type
, mem
);
4403 checkGLcall("glDrawPixels");
4405 if (surface
->flags
& SFLAG_PBO
)
4407 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4408 checkGLcall("glBindBufferARB");
4411 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
4412 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4416 if (wined3d_settings
.strict_draw_ordering
4417 || (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
4418 && surface
->container
.u
.swapchain
->front_buffer
== surface
))
4421 context_release(context
);
4424 HRESULT
d3dfmt_get_conv(const struct wined3d_surface
*surface
, BOOL need_alpha_ck
,
4425 BOOL use_texturing
, struct wined3d_format
*format
, CONVERT_TYPES
*convert
)
4427 BOOL colorkey_active
= need_alpha_ck
&& (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
4428 const struct wined3d_device
*device
= surface
->resource
.device
;
4429 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4430 BOOL blit_supported
= FALSE
;
4432 /* Copy the default values from the surface. Below we might perform fixups */
4433 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
4434 *format
= *surface
->resource
.format
;
4435 *convert
= NO_CONVERSION
;
4437 /* Ok, now look if we have to do any conversion */
4438 switch (surface
->resource
.format
->id
)
4440 case WINED3DFMT_P8_UINT
:
4441 /* Below the call to blit_supported is disabled for Wine 1.2
4442 * because the function isn't operating correctly yet. At the
4443 * moment 8-bit blits are handled in software and if certain GL
4444 * extensions are around, surface conversion is performed at
4445 * upload time. The blit_supported call recognizes it as a
4446 * destination fixup. This type of upload 'fixup' and 8-bit to
4447 * 8-bit blits need to be handled by the blit_shader.
4448 * TODO: get rid of this #if 0. */
4450 blit_supported
= device
->blitter
->blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4451 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4452 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
);
4454 blit_supported
= gl_info
->supported
[EXT_PALETTED_TEXTURE
] || gl_info
->supported
[ARB_FRAGMENT_PROGRAM
];
4456 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
4457 * texturing. Further also use conversion in case of color keying.
4458 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
4459 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
4460 * conflicts with this.
4462 if (!((blit_supported
&& device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
4463 || colorkey_active
|| !use_texturing
)
4465 format
->glFormat
= GL_RGBA
;
4466 format
->glInternal
= GL_RGBA
;
4467 format
->glType
= GL_UNSIGNED_BYTE
;
4468 format
->conv_byte_count
= 4;
4469 if (colorkey_active
)
4470 *convert
= CONVERT_PALETTED_CK
;
4472 *convert
= CONVERT_PALETTED
;
4476 case WINED3DFMT_B2G3R3_UNORM
:
4477 /* **********************
4478 GL_UNSIGNED_BYTE_3_3_2
4479 ********************** */
4480 if (colorkey_active
) {
4481 /* This texture format will never be used.. So do not care about color keying
4482 up until the point in time it will be needed :-) */
4483 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
4487 case WINED3DFMT_B5G6R5_UNORM
:
4488 if (colorkey_active
)
4490 *convert
= CONVERT_CK_565
;
4491 format
->glFormat
= GL_RGBA
;
4492 format
->glInternal
= GL_RGB5_A1
;
4493 format
->glType
= GL_UNSIGNED_SHORT_5_5_5_1
;
4494 format
->conv_byte_count
= 2;
4498 case WINED3DFMT_B5G5R5X1_UNORM
:
4499 if (colorkey_active
)
4501 *convert
= CONVERT_CK_5551
;
4502 format
->glFormat
= GL_BGRA
;
4503 format
->glInternal
= GL_RGB5_A1
;
4504 format
->glType
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
4505 format
->conv_byte_count
= 2;
4509 case WINED3DFMT_B8G8R8_UNORM
:
4510 if (colorkey_active
)
4512 *convert
= CONVERT_CK_RGB24
;
4513 format
->glFormat
= GL_RGBA
;
4514 format
->glInternal
= GL_RGBA8
;
4515 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
4516 format
->conv_byte_count
= 4;
4520 case WINED3DFMT_B8G8R8X8_UNORM
:
4521 if (colorkey_active
)
4523 *convert
= CONVERT_RGB32_888
;
4524 format
->glFormat
= GL_RGBA
;
4525 format
->glInternal
= GL_RGBA8
;
4526 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
4527 format
->conv_byte_count
= 4;
4535 if (*convert
!= NO_CONVERSION
)
4537 format
->rtInternal
= format
->glInternal
;
4538 format
->glGammaInternal
= format
->glInternal
;
4544 static BOOL
color_in_range(const struct wined3d_color_key
*color_key
, DWORD color
)
4546 /* FIXME: Is this really how color keys are supposed to work? I think it
4547 * makes more sense to compare the individual channels. */
4548 return color
>= color_key
->color_space_low_value
4549 && color
<= color_key
->color_space_high_value
;
4552 void d3dfmt_p8_init_palette(const struct wined3d_surface
*surface
, BYTE table
[256][4], BOOL colorkey
)
4554 const struct wined3d_device
*device
= surface
->resource
.device
;
4555 const struct wined3d_palette
*pal
= surface
->palette
;
4556 BOOL index_in_alpha
= FALSE
;
4559 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4560 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4561 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4562 * duplicate entries. Store the color key in the unused alpha component to speed the
4563 * download up and to make conversion unneeded. */
4564 index_in_alpha
= primary_render_target_is_p8(device
);
4568 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4571 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4572 * there's no palette at this time. */
4573 for (i
= 0; i
< 256; i
++) table
[i
][3] = i
;
4578 TRACE("Using surface palette %p\n", pal
);
4579 /* Get the surface's palette */
4580 for (i
= 0; i
< 256; ++i
)
4582 table
[i
][0] = pal
->palents
[i
].peRed
;
4583 table
[i
][1] = pal
->palents
[i
].peGreen
;
4584 table
[i
][2] = pal
->palents
[i
].peBlue
;
4586 /* When index_in_alpha is set the palette index is stored in the
4587 * alpha component. In case of a readback we can then read
4588 * GL_ALPHA. Color keying is handled in BltOverride using a
4589 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4590 * color key itself is passed to glAlphaFunc in other cases the
4591 * alpha component of pixels that should be masked away is set to 0. */
4594 else if (colorkey
&& color_in_range(&surface
->src_blt_color_key
, i
))
4596 else if (pal
->flags
& WINEDDPCAPS_ALPHA
)
4597 table
[i
][3] = pal
->palents
[i
].peFlags
;
4604 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
,
4605 UINT height
, UINT outpitch
, CONVERT_TYPES convert
, struct wined3d_surface
*surface
)
4609 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src
, dst
, pitch
, height
, outpitch
, convert
, surface
);
4614 memcpy(dst
, src
, pitch
* height
);
4617 case CONVERT_PALETTED
:
4618 case CONVERT_PALETTED_CK
:
4623 d3dfmt_p8_init_palette(surface
, table
, (convert
== CONVERT_PALETTED_CK
));
4625 for (y
= 0; y
< height
; y
++)
4627 source
= src
+ pitch
* y
;
4628 dest
= dst
+ outpitch
* y
;
4629 /* This is an 1 bpp format, using the width here is fine */
4630 for (x
= 0; x
< width
; x
++) {
4631 BYTE color
= *source
++;
4632 *dest
++ = table
[color
][0];
4633 *dest
++ = table
[color
][1];
4634 *dest
++ = table
[color
][2];
4635 *dest
++ = table
[color
][3];
4641 case CONVERT_CK_565
:
4643 /* Converting the 565 format in 5551 packed to emulate color-keying.
4645 Note : in all these conversion, it would be best to average the averaging
4646 pixels to get the color of the pixel that will be color-keyed to
4647 prevent 'color bleeding'. This will be done later on if ever it is
4650 Note2: Nvidia documents say that their driver does not support alpha + color keying
4651 on the same surface and disables color keying in such a case
4657 TRACE("Color keyed 565\n");
4659 for (y
= 0; y
< height
; y
++) {
4660 Source
= (const WORD
*)(src
+ y
* pitch
);
4661 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4662 for (x
= 0; x
< width
; x
++ ) {
4663 WORD color
= *Source
++;
4664 *Dest
= ((color
& 0xFFC0) | ((color
& 0x1F) << 1));
4665 if (!color_in_range(&surface
->src_blt_color_key
, color
))
4673 case CONVERT_CK_5551
:
4675 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4679 TRACE("Color keyed 5551\n");
4680 for (y
= 0; y
< height
; y
++) {
4681 Source
= (const WORD
*)(src
+ y
* pitch
);
4682 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4683 for (x
= 0; x
< width
; x
++ ) {
4684 WORD color
= *Source
++;
4686 if (!color_in_range(&surface
->src_blt_color_key
, color
))
4689 *Dest
&= ~(1 << 15);
4696 case CONVERT_CK_RGB24
:
4698 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4700 for (y
= 0; y
< height
; y
++)
4702 source
= src
+ pitch
* y
;
4703 dest
= dst
+ outpitch
* y
;
4704 for (x
= 0; x
< width
; x
++) {
4705 DWORD color
= ((DWORD
)source
[0] << 16) + ((DWORD
)source
[1] << 8) + (DWORD
)source
[2] ;
4706 DWORD dstcolor
= color
<< 8;
4707 if (!color_in_range(&surface
->src_blt_color_key
, color
))
4709 *(DWORD
*)dest
= dstcolor
;
4717 case CONVERT_RGB32_888
:
4719 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4721 for (y
= 0; y
< height
; y
++)
4723 source
= src
+ pitch
* y
;
4724 dest
= dst
+ outpitch
* y
;
4725 for (x
= 0; x
< width
; x
++) {
4726 DWORD color
= 0xffffff & *(const DWORD
*)source
;
4727 DWORD dstcolor
= color
<< 8;
4728 if (!color_in_range(&surface
->src_blt_color_key
, color
))
4730 *(DWORD
*)dest
= dstcolor
;
4739 ERR("Unsupported conversion type %#x.\n", convert
);
4744 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
4746 /* Flip the surface contents */
4751 front
->hDC
= back
->hDC
;
4755 /* Flip the DIBsection */
4757 HBITMAP tmp
= front
->dib
.DIBsection
;
4758 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
4759 back
->dib
.DIBsection
= tmp
;
4762 /* Flip the surface data */
4766 tmp
= front
->dib
.bitmap_data
;
4767 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
4768 back
->dib
.bitmap_data
= tmp
;
4770 tmp
= front
->resource
.allocatedMemory
;
4771 front
->resource
.allocatedMemory
= back
->resource
.allocatedMemory
;
4772 back
->resource
.allocatedMemory
= tmp
;
4774 tmp
= front
->resource
.heapMemory
;
4775 front
->resource
.heapMemory
= back
->resource
.heapMemory
;
4776 back
->resource
.heapMemory
= tmp
;
4781 GLuint tmp_pbo
= front
->pbo
;
4782 front
->pbo
= back
->pbo
;
4783 back
->pbo
= tmp_pbo
;
4786 /* Flip the opengl texture */
4790 tmp
= back
->texture_name
;
4791 back
->texture_name
= front
->texture_name
;
4792 front
->texture_name
= tmp
;
4794 tmp
= back
->texture_name_srgb
;
4795 back
->texture_name_srgb
= front
->texture_name_srgb
;
4796 front
->texture_name_srgb
= tmp
;
4798 tmp
= back
->rb_multisample
;
4799 back
->rb_multisample
= front
->rb_multisample
;
4800 front
->rb_multisample
= tmp
;
4802 tmp
= back
->rb_resolved
;
4803 back
->rb_resolved
= front
->rb_resolved
;
4804 front
->rb_resolved
= tmp
;
4806 resource_unload(&back
->resource
);
4807 resource_unload(&front
->resource
);
4811 DWORD tmp_flags
= back
->flags
;
4812 back
->flags
= front
->flags
;
4813 front
->flags
= tmp_flags
;
4817 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4818 * pixel copy calls. */
4819 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4820 const RECT
*src_rect
, const RECT
*dst_rect_in
, WINED3DTEXTUREFILTERTYPE Filter
)
4822 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4825 struct wined3d_context
*context
;
4826 BOOL upsidedown
= FALSE
;
4827 RECT dst_rect
= *dst_rect_in
;
4829 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4830 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4832 if(dst_rect
.top
> dst_rect
.bottom
) {
4833 UINT tmp
= dst_rect
.bottom
;
4834 dst_rect
.bottom
= dst_rect
.top
;
4839 context
= context_acquire(device
, src_surface
);
4840 context_apply_blit_state(context
, device
);
4841 surface_internal_preload(dst_surface
, SRGB_RGB
);
4844 /* Bind the target texture */
4845 context_bind_texture(context
, dst_surface
->texture_target
, dst_surface
->texture_name
);
4846 if (surface_is_offscreen(src_surface
))
4848 TRACE("Reading from an offscreen target\n");
4849 upsidedown
= !upsidedown
;
4850 glReadBuffer(device
->offscreenBuffer
);
4854 glReadBuffer(surface_get_gl_buffer(src_surface
));
4856 checkGLcall("glReadBuffer");
4858 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
4859 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
4861 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4863 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4865 if(Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
) {
4866 ERR("Texture filtering not supported in direct blit\n");
4869 else if ((Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
)
4870 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4872 ERR("Texture filtering not supported in direct blit\n");
4876 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4877 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4879 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
4881 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4882 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
4883 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
4884 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
4888 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
4889 /* I have to process this row by row to swap the image,
4890 * otherwise it would be upside down, so stretching in y direction
4891 * doesn't cost extra time
4893 * However, stretching in x direction can be avoided if not necessary
4895 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
4896 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4898 /* Well, that stuff works, but it's very slow.
4899 * find a better way instead
4903 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
4905 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4906 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
4907 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
4912 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4913 dst_rect
.left
/* x offset */, row
/* y offset */,
4914 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
4918 checkGLcall("glCopyTexSubImage2D");
4921 context_release(context
);
4923 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
4924 * path is never entered
4926 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
4929 /* Uses the hardware to stretch and flip the image */
4930 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4931 const RECT
*src_rect
, const RECT
*dst_rect_in
, WINED3DTEXTUREFILTERTYPE Filter
)
4933 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4934 struct wined3d_swapchain
*src_swapchain
= NULL
;
4935 GLuint src
, backup
= 0;
4936 float left
, right
, top
, bottom
; /* Texture coordinates */
4937 UINT fbwidth
= src_surface
->resource
.width
;
4938 UINT fbheight
= src_surface
->resource
.height
;
4939 struct wined3d_context
*context
;
4940 GLenum drawBuffer
= GL_BACK
;
4941 GLenum texture_target
;
4942 BOOL noBackBufferBackup
;
4944 BOOL upsidedown
= FALSE
;
4945 RECT dst_rect
= *dst_rect_in
;
4947 TRACE("Using hwstretch blit\n");
4948 /* Activate the Proper context for reading from the source surface, set it up for blitting */
4949 context
= context_acquire(device
, src_surface
);
4950 context_apply_blit_state(context
, device
);
4951 surface_internal_preload(dst_surface
, SRGB_RGB
);
4953 src_offscreen
= surface_is_offscreen(src_surface
);
4954 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
4955 if (!noBackBufferBackup
&& !src_surface
->texture_name
)
4957 /* Get it a description */
4958 surface_internal_preload(src_surface
, SRGB_RGB
);
4962 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
4963 * This way we don't have to wait for the 2nd readback to finish to leave this function.
4965 if (context
->aux_buffers
>= 2)
4967 /* Got more than one aux buffer? Use the 2nd aux buffer */
4968 drawBuffer
= GL_AUX1
;
4970 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
4972 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
4973 drawBuffer
= GL_AUX0
;
4976 if(noBackBufferBackup
) {
4977 glGenTextures(1, &backup
);
4978 checkGLcall("glGenTextures");
4979 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
4980 texture_target
= GL_TEXTURE_2D
;
4982 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
4983 * we are reading from the back buffer, the backup can be used as source texture
4985 texture_target
= src_surface
->texture_target
;
4986 context_bind_texture(context
, texture_target
, src_surface
->texture_name
);
4987 glEnable(texture_target
);
4988 checkGLcall("glEnable(texture_target)");
4990 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
4991 src_surface
->flags
&= ~SFLAG_INTEXTURE
;
4994 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4995 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4997 if(dst_rect
.top
> dst_rect
.bottom
) {
4998 UINT tmp
= dst_rect
.bottom
;
4999 dst_rect
.bottom
= dst_rect
.top
;
5006 TRACE("Reading from an offscreen target\n");
5007 upsidedown
= !upsidedown
;
5008 glReadBuffer(device
->offscreenBuffer
);
5012 glReadBuffer(surface_get_gl_buffer(src_surface
));
5015 /* TODO: Only back up the part that will be overwritten */
5016 glCopyTexSubImage2D(texture_target
, 0,
5017 0, 0 /* read offsets */,
5022 checkGLcall("glCopyTexSubImage2D");
5024 /* No issue with overriding these - the sampler is dirty due to blit usage */
5025 glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
5026 wined3d_gl_mag_filter(magLookup
, Filter
));
5027 checkGLcall("glTexParameteri");
5028 glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
5029 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
5030 checkGLcall("glTexParameteri");
5032 if (src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5033 src_swapchain
= src_surface
->container
.u
.swapchain
;
5034 if (!src_swapchain
|| src_surface
== src_swapchain
->back_buffers
[0])
5036 src
= backup
? backup
: src_surface
->texture_name
;
5040 glReadBuffer(GL_FRONT
);
5041 checkGLcall("glReadBuffer(GL_FRONT)");
5043 glGenTextures(1, &src
);
5044 checkGLcall("glGenTextures(1, &src)");
5045 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
5047 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5048 * out for power of 2 sizes
5050 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
5051 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
5052 checkGLcall("glTexImage2D");
5053 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0,
5054 0, 0 /* read offsets */,
5059 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5060 checkGLcall("glTexParameteri");
5061 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5062 checkGLcall("glTexParameteri");
5064 glReadBuffer(GL_BACK
);
5065 checkGLcall("glReadBuffer(GL_BACK)");
5067 if(texture_target
!= GL_TEXTURE_2D
) {
5068 glDisable(texture_target
);
5069 glEnable(GL_TEXTURE_2D
);
5070 texture_target
= GL_TEXTURE_2D
;
5073 checkGLcall("glEnd and previous");
5075 left
= src_rect
->left
;
5076 right
= src_rect
->right
;
5080 top
= src_surface
->resource
.height
- src_rect
->top
;
5081 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
5085 top
= src_surface
->resource
.height
- src_rect
->bottom
;
5086 bottom
= src_surface
->resource
.height
- src_rect
->top
;
5089 if (src_surface
->flags
& SFLAG_NORMCOORD
)
5091 left
/= src_surface
->pow2Width
;
5092 right
/= src_surface
->pow2Width
;
5093 top
/= src_surface
->pow2Height
;
5094 bottom
/= src_surface
->pow2Height
;
5097 /* draw the source texture stretched and upside down. The correct surface is bound already */
5098 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
5099 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
5101 context_set_draw_buffer(context
, drawBuffer
);
5102 glReadBuffer(drawBuffer
);
5106 glTexCoord2f(left
, bottom
);
5110 glTexCoord2f(left
, top
);
5111 glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
5114 glTexCoord2f(right
, top
);
5115 glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
5118 glTexCoord2f(right
, bottom
);
5119 glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
5121 checkGLcall("glEnd and previous");
5123 if (texture_target
!= dst_surface
->texture_target
)
5125 glDisable(texture_target
);
5126 glEnable(dst_surface
->texture_target
);
5127 texture_target
= dst_surface
->texture_target
;
5130 /* Now read the stretched and upside down image into the destination texture */
5131 context_bind_texture(context
, texture_target
, dst_surface
->texture_name
);
5132 glCopyTexSubImage2D(texture_target
,
5134 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
5135 0, 0, /* We blitted the image to the origin */
5136 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
5137 checkGLcall("glCopyTexSubImage2D");
5139 if(drawBuffer
== GL_BACK
) {
5140 /* Write the back buffer backup back */
5142 if(texture_target
!= GL_TEXTURE_2D
) {
5143 glDisable(texture_target
);
5144 glEnable(GL_TEXTURE_2D
);
5145 texture_target
= GL_TEXTURE_2D
;
5147 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
5151 if (texture_target
!= src_surface
->texture_target
)
5153 glDisable(texture_target
);
5154 glEnable(src_surface
->texture_target
);
5155 texture_target
= src_surface
->texture_target
;
5157 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->texture_name
);
5162 glTexCoord2f(0.0f
, 0.0f
);
5163 glVertex2i(0, fbheight
);
5166 glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
5170 glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
5171 (float)fbheight
/ (float)src_surface
->pow2Height
);
5172 glVertex2i(fbwidth
, 0);
5175 glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
5176 glVertex2i(fbwidth
, fbheight
);
5179 glDisable(texture_target
);
5180 checkGLcall("glDisable(texture_target)");
5183 if (src
!= src_surface
->texture_name
&& src
!= backup
)
5185 glDeleteTextures(1, &src
);
5186 checkGLcall("glDeleteTextures(1, &src)");
5189 glDeleteTextures(1, &backup
);
5190 checkGLcall("glDeleteTextures(1, &backup)");
5195 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5197 context_release(context
);
5199 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5200 * path is never entered
5202 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
5205 /* Front buffer coordinates are always full screen coordinates, but our GL
5206 * drawable is limited to the window's client area. The sysmem and texture
5207 * copies do have the full screen size. Note that GL has a bottom-left
5208 * origin, while D3D has a top-left origin. */
5209 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
5211 UINT drawable_height
;
5213 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
5214 && surface
== surface
->container
.u
.swapchain
->front_buffer
)
5216 POINT offset
= {0, 0};
5219 ScreenToClient(window
, &offset
);
5220 OffsetRect(rect
, offset
.x
, offset
.y
);
5222 GetClientRect(window
, &windowsize
);
5223 drawable_height
= windowsize
.bottom
- windowsize
.top
;
5227 drawable_height
= surface
->resource
.height
;
5230 rect
->top
= drawable_height
- rect
->top
;
5231 rect
->bottom
= drawable_height
- rect
->bottom
;
5234 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
5235 WINED3DTEXTUREFILTERTYPE filter
, BOOL color_key
,
5236 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
5237 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
5239 struct wined3d_context
*context
;
5240 RECT src_rect
, dst_rect
;
5242 src_rect
= *src_rect_in
;
5243 dst_rect
= *dst_rect_in
;
5245 /* Make sure the surface is up-to-date. This should probably use
5246 * surface_load_location() and worry about the destination surface too,
5247 * unless we're overwriting it completely. */
5248 surface_internal_preload(src_surface
, SRGB_RGB
);
5250 /* Activate the destination context, set it up for blitting */
5251 context
= context_acquire(device
, dst_surface
);
5252 context_apply_blit_state(context
, device
);
5254 if (!surface_is_offscreen(dst_surface
))
5255 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
5257 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
5263 glEnable(GL_ALPHA_TEST
);
5264 checkGLcall("glEnable(GL_ALPHA_TEST)");
5266 /* When the primary render target uses P8, the alpha component
5267 * contains the palette index. Which means that the colorkey is one of
5268 * the palette entries. In other cases pixels that should be masked
5269 * away have alpha set to 0. */
5270 if (primary_render_target_is_p8(device
))
5271 glAlphaFunc(GL_NOTEQUAL
, (float)src_surface
->src_blt_color_key
.color_space_low_value
/ 256.0f
);
5273 glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
5274 checkGLcall("glAlphaFunc");
5278 glDisable(GL_ALPHA_TEST
);
5279 checkGLcall("glDisable(GL_ALPHA_TEST)");
5282 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
5286 glDisable(GL_ALPHA_TEST
);
5287 checkGLcall("glDisable(GL_ALPHA_TEST)");
5292 /* Leave the opengl state valid for blitting */
5293 device
->blitter
->unset_shader(context
->gl_info
);
5295 if (wined3d_settings
.strict_draw_ordering
5296 || (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
5297 && (dst_surface
->container
.u
.swapchain
->front_buffer
== dst_surface
)))
5298 wglFlush(); /* Flush to ensure ordering across contexts. */
5300 context_release(context
);
5303 /* Do not call while under the GL lock. */
5304 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
5306 struct wined3d_device
*device
= s
->resource
.device
;
5307 const struct blit_shader
*blitter
;
5309 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
5310 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
5313 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5314 return WINED3DERR_INVALIDCALL
;
5317 return blitter
->color_fill(device
, s
, rect
, color
);
5320 /* Do not call while under the GL lock. */
5321 static HRESULT
IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5322 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
5323 WINED3DTEXTUREFILTERTYPE Filter
)
5325 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5326 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5327 struct wined3d_swapchain
*srcSwapchain
= NULL
, *dstSwapchain
= NULL
;
5329 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5330 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5331 flags
, DDBltFx
, debug_d3dtexturefiltertype(Filter
));
5333 /* Get the swapchain. One of the surfaces has to be a primary surface */
5334 if (dst_surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
5336 WARN("Destination is in sysmem, rejecting gl blt\n");
5337 return WINED3DERR_INVALIDCALL
;
5340 if (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5341 dstSwapchain
= dst_surface
->container
.u
.swapchain
;
5345 if (src_surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
5347 WARN("Src is in sysmem, rejecting gl blt\n");
5348 return WINED3DERR_INVALIDCALL
;
5351 if (src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5352 srcSwapchain
= src_surface
->container
.u
.swapchain
;
5355 /* Early sort out of cases where no render target is used */
5356 if (!dstSwapchain
&& !srcSwapchain
5357 && src_surface
!= device
->fb
.render_targets
[0]
5358 && dst_surface
!= device
->fb
.render_targets
[0])
5360 TRACE("No surface is render target, not using hardware blit.\n");
5361 return WINED3DERR_INVALIDCALL
;
5364 /* No destination color keying supported */
5365 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
5367 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5368 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5369 return WINED3DERR_INVALIDCALL
;
5372 if (dstSwapchain
&& dstSwapchain
== srcSwapchain
)
5374 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5375 return WINED3DERR_INVALIDCALL
;
5378 if (dstSwapchain
&& srcSwapchain
)
5380 FIXME("Implement hardware blit between two different swapchains\n");
5381 return WINED3DERR_INVALIDCALL
;
5386 /* Handled with regular texture -> swapchain blit */
5387 if (src_surface
== device
->fb
.render_targets
[0])
5388 TRACE("Blit from active render target to a swapchain\n");
5390 else if (srcSwapchain
&& dst_surface
== device
->fb
.render_targets
[0])
5392 FIXME("Implement blit from a swapchain to the active render target\n");
5393 return WINED3DERR_INVALIDCALL
;
5396 if ((srcSwapchain
|| src_surface
== device
->fb
.render_targets
[0]) && !dstSwapchain
)
5398 /* Blit from render target to texture */
5401 /* P8 read back is not implemented */
5402 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
5403 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
5405 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5406 return WINED3DERR_INVALIDCALL
;
5409 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
5411 TRACE("Color keying not supported by frame buffer to texture blit\n");
5412 return WINED3DERR_INVALIDCALL
;
5413 /* Destination color key is checked above */
5416 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
5421 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5422 * flip the image nor scale it.
5424 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5425 * -> If the app wants a image width an unscaled width, copy it line per line
5426 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5427 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5428 * back buffer. This is slower than reading line per line, thus not used for flipping
5429 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5430 * pixel by pixel. */
5431 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
5432 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
5434 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
5435 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, Filter
);
5437 TRACE("Using hardware stretching to flip / stretch the texture\n");
5438 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, Filter
);
5441 if (!(dst_surface
->flags
& SFLAG_DONOTFREE
))
5443 HeapFree(GetProcessHeap(), 0, dst_surface
->resource
.heapMemory
);
5444 dst_surface
->resource
.allocatedMemory
= NULL
;
5445 dst_surface
->resource
.heapMemory
= NULL
;
5449 dst_surface
->flags
&= ~SFLAG_INSYSMEM
;
5454 else if (src_surface
)
5456 /* Blit from offscreen surface to render target */
5457 struct wined3d_color_key old_blt_key
= src_surface
->src_blt_color_key
;
5458 DWORD oldCKeyFlags
= src_surface
->CKeyFlags
;
5460 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
5462 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5463 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5464 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5466 FIXME("Unsupported blit operation falling back to software\n");
5467 return WINED3DERR_INVALIDCALL
;
5470 /* Color keying: Check if we have to do a color keyed blt,
5471 * and if not check if a color key is activated.
5473 * Just modify the color keying parameters in the surface and restore them afterwards
5474 * The surface keeps track of the color key last used to load the opengl surface.
5475 * PreLoad will catch the change to the flags and color key and reload if necessary.
5477 if (flags
& WINEDDBLT_KEYSRC
)
5479 /* Use color key from surface */
5481 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5483 /* Use color key from DDBltFx */
5484 src_surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
5485 src_surface
->src_blt_color_key
= DDBltFx
->ddckSrcColorkey
;
5489 /* Do not use color key */
5490 src_surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
5493 surface_blt_to_drawable(device
, Filter
, flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
),
5494 src_surface
, src_rect
, dst_surface
, dst_rect
);
5496 /* Restore the color key parameters */
5497 src_surface
->CKeyFlags
= oldCKeyFlags
;
5498 src_surface
->src_blt_color_key
= old_blt_key
;
5500 surface_modify_location(dst_surface
, dst_surface
->draw_binding
, TRUE
);
5505 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5506 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5507 return WINED3DERR_INVALIDCALL
;
5510 /* GL locking is done by the caller */
5511 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
5512 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
5514 struct wined3d_device
*device
= surface
->resource
.device
;
5515 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
5516 GLint compare_mode
= GL_NONE
;
5517 struct blt_info info
;
5518 GLint old_binding
= 0;
5521 glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
5523 glDisable(GL_CULL_FACE
);
5524 glDisable(GL_BLEND
);
5525 glDisable(GL_ALPHA_TEST
);
5526 glDisable(GL_SCISSOR_TEST
);
5527 glDisable(GL_STENCIL_TEST
);
5528 glEnable(GL_DEPTH_TEST
);
5529 glDepthFunc(GL_ALWAYS
);
5530 glDepthMask(GL_TRUE
);
5531 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
5532 glViewport(x
, y
, w
, h
);
5534 SetRect(&rect
, 0, h
, w
, 0);
5535 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
5536 context_active_texture(context
, context
->gl_info
, 0);
5537 glGetIntegerv(info
.binding
, &old_binding
);
5538 glBindTexture(info
.bind_target
, texture
);
5539 if (gl_info
->supported
[ARB_SHADOW
])
5541 glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
5542 if (compare_mode
!= GL_NONE
) glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
5545 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
5546 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
5548 glBegin(GL_TRIANGLE_STRIP
);
5549 glTexCoord3fv(info
.coords
[0]);
5550 glVertex2f(-1.0f
, -1.0f
);
5551 glTexCoord3fv(info
.coords
[1]);
5552 glVertex2f(1.0f
, -1.0f
);
5553 glTexCoord3fv(info
.coords
[2]);
5554 glVertex2f(-1.0f
, 1.0f
);
5555 glTexCoord3fv(info
.coords
[3]);
5556 glVertex2f(1.0f
, 1.0f
);
5559 if (compare_mode
!= GL_NONE
) glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
5560 glBindTexture(info
.bind_target
, old_binding
);
5564 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
5567 void surface_modify_ds_location(struct wined3d_surface
*surface
,
5568 DWORD location
, UINT w
, UINT h
)
5570 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
5572 if (location
& ~(SFLAG_LOCATIONS
| SFLAG_LOST
))
5573 FIXME("Invalid location (%#x) specified.\n", location
);
5575 if (((surface
->flags
& SFLAG_INTEXTURE
) && !(location
& SFLAG_INTEXTURE
))
5576 || (!(surface
->flags
& SFLAG_INTEXTURE
) && (location
& SFLAG_INTEXTURE
)))
5578 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5580 TRACE("Passing to container.\n");
5581 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5585 surface
->ds_current_size
.cx
= w
;
5586 surface
->ds_current_size
.cy
= h
;
5587 surface
->flags
&= ~(SFLAG_LOCATIONS
| SFLAG_LOST
);
5588 surface
->flags
|= location
;
5591 /* Context activation is done by the caller. */
5592 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
5594 struct wined3d_device
*device
= surface
->resource
.device
;
5597 TRACE("surface %p, new location %#x.\n", surface
, location
);
5599 /* TODO: Make this work for modes other than FBO */
5600 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
5602 if (!(surface
->flags
& location
))
5604 w
= surface
->ds_current_size
.cx
;
5605 h
= surface
->ds_current_size
.cy
;
5606 surface
->ds_current_size
.cx
= 0;
5607 surface
->ds_current_size
.cy
= 0;
5611 w
= surface
->resource
.width
;
5612 h
= surface
->resource
.height
;
5615 if (surface
->ds_current_size
.cx
== surface
->resource
.width
5616 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
5618 TRACE("Location (%#x) is already up to date.\n", location
);
5622 if (surface
->current_renderbuffer
)
5624 FIXME("Not supported with fixed up depth stencil.\n");
5628 if (surface
->flags
& SFLAG_LOST
)
5630 TRACE("Surface was discarded, no need copy data.\n");
5633 case SFLAG_INTEXTURE
:
5634 surface_prepare_texture(surface
, context
, FALSE
);
5636 case SFLAG_INRB_MULTISAMPLE
:
5637 surface_prepare_rb(surface
, context
->gl_info
, TRUE
);
5639 case SFLAG_INDRAWABLE
:
5643 FIXME("Unhandled location %#x", location
);
5645 surface
->flags
&= ~SFLAG_LOST
;
5646 surface
->flags
|= location
;
5647 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5648 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5652 if (!(surface
->flags
& SFLAG_LOCATIONS
))
5654 FIXME("No up to date depth stencil location.\n");
5655 surface
->flags
|= location
;
5656 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5657 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5661 if (location
== SFLAG_INTEXTURE
)
5663 GLint old_binding
= 0;
5666 /* The render target is allowed to be smaller than the depth/stencil
5667 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5668 * than the offscreen surface. Don't overwrite the offscreen surface
5669 * with undefined data. */
5670 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
5671 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
5673 TRACE("Copying onscreen depth buffer to depth texture.\n");
5677 if (!device
->depth_blt_texture
)
5679 glGenTextures(1, &device
->depth_blt_texture
);
5682 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5683 * directly on the FBO texture. That's because we need to flip. */
5684 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5685 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5686 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
5688 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
5689 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
5693 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
5694 bind_target
= GL_TEXTURE_2D
;
5696 glBindTexture(bind_target
, device
->depth_blt_texture
);
5697 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5698 * internal format, because the internal format might include stencil
5699 * data. In principle we should copy stencil data as well, but unless
5700 * the driver supports stencil export it's hard to do, and doesn't
5701 * seem to be needed in practice. If the hardware doesn't support
5702 * writing stencil data, the glCopyTexImage2D() call might trigger
5703 * software fallbacks. */
5704 glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
5705 glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5706 glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5707 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
5708 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
5709 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
5710 glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
5711 glBindTexture(bind_target
, old_binding
);
5713 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5714 NULL
, surface
, SFLAG_INTEXTURE
);
5715 context_set_draw_buffer(context
, GL_NONE
);
5716 glReadBuffer(GL_NONE
);
5718 /* Do the actual blit */
5719 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
5720 checkGLcall("depth_blt");
5722 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5726 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5728 else if (location
== SFLAG_INDRAWABLE
)
5730 TRACE("Copying depth texture to onscreen depth buffer.\n");
5734 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5735 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5736 surface_depth_blt(surface
, context
, surface
->texture_name
,
5737 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
5738 checkGLcall("depth_blt");
5740 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5744 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5748 ERR("Invalid location (%#x) specified.\n", location
);
5751 surface
->flags
|= location
;
5752 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5753 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5756 void surface_modify_location(struct wined3d_surface
*surface
, DWORD location
, BOOL persistent
)
5758 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
5759 struct wined3d_surface
*overlay
;
5761 TRACE("surface %p, location %s, persistent %#x.\n",
5762 surface
, debug_surflocation(location
), persistent
);
5764 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
)
5765 && !(surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
5766 && (location
& SFLAG_INDRAWABLE
))
5767 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5769 if (location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)
5770 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
5771 location
|= (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
5775 if (((surface
->flags
& SFLAG_INTEXTURE
) && !(location
& SFLAG_INTEXTURE
))
5776 || ((surface
->flags
& SFLAG_INSRGBTEX
) && !(location
& SFLAG_INSRGBTEX
)))
5778 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5780 TRACE("Passing to container.\n");
5781 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5784 surface
->flags
&= ~SFLAG_LOCATIONS
;
5785 surface
->flags
|= location
;
5787 /* Redraw emulated overlays, if any */
5788 if (location
& SFLAG_INDRAWABLE
&& !list_empty(&surface
->overlays
))
5790 LIST_FOR_EACH_ENTRY(overlay
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
5792 surface_draw_overlay(overlay
);
5798 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)) && (location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)))
5800 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5802 TRACE("Passing to container\n");
5803 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5806 surface
->flags
&= ~location
;
5809 if (!(surface
->flags
& SFLAG_LOCATIONS
))
5811 ERR("Surface %p does not have any up to date location.\n", surface
);
5815 static DWORD
resource_access_from_location(DWORD location
)
5819 case SFLAG_INSYSMEM
:
5820 return WINED3D_RESOURCE_ACCESS_CPU
;
5822 case SFLAG_INDRAWABLE
:
5823 case SFLAG_INSRGBTEX
:
5824 case SFLAG_INTEXTURE
:
5825 case SFLAG_INRB_MULTISAMPLE
:
5826 case SFLAG_INRB_RESOLVED
:
5827 return WINED3D_RESOURCE_ACCESS_GPU
;
5830 FIXME("Unhandled location %#x.\n", location
);
5835 static void surface_load_sysmem(struct wined3d_surface
*surface
,
5836 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5838 surface_prepare_system_memory(surface
);
5840 if (surface
->flags
& (SFLAG_INRB_MULTISAMPLE
| SFLAG_INRB_RESOLVED
))
5841 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
5843 /* Download the surface to system memory. */
5844 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
))
5846 struct wined3d_device
*device
= surface
->resource
.device
;
5847 struct wined3d_context
*context
;
5849 /* TODO: Use already acquired context when possible. */
5850 context
= context_acquire(device
, NULL
);
5852 surface_bind_and_dirtify(surface
, context
, !(surface
->flags
& SFLAG_INTEXTURE
));
5853 surface_download_data(surface
, gl_info
);
5855 context_release(context
);
5860 if (surface
->flags
& SFLAG_INDRAWABLE
)
5862 read_from_framebuffer(surface
, rect
, surface
->resource
.allocatedMemory
,
5863 wined3d_surface_get_pitch(surface
));
5867 FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
5868 surface
, surface
->flags
& SFLAG_LOCATIONS
);
5871 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
5872 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5874 struct wined3d_device
*device
= surface
->resource
.device
;
5875 struct wined3d_format format
;
5876 CONVERT_TYPES convert
;
5880 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
))
5882 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5883 return WINED3DERR_INVALIDCALL
;
5886 if (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
)
5887 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
5889 if (surface
->flags
& SFLAG_INTEXTURE
)
5893 surface_get_rect(surface
, rect
, &r
);
5894 surface_blt_to_drawable(device
, WINED3DTEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
5899 if ((surface
->flags
& SFLAG_LOCATIONS
) == SFLAG_INSRGBTEX
)
5901 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5902 * path through sysmem. */
5903 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5906 d3dfmt_get_conv(surface
, FALSE
, FALSE
, &format
, &convert
);
5908 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
5909 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
5911 if ((convert
!= NO_CONVERSION
) && (surface
->flags
& SFLAG_PBO
))
5913 struct wined3d_context
*context
;
5915 TRACE("Removing the pbo attached to surface %p.\n", surface
);
5917 /* TODO: Use already acquired context when possible. */
5918 context
= context_acquire(device
, NULL
);
5920 surface_remove_pbo(surface
, gl_info
);
5922 context_release(context
);
5925 if ((convert
!= NO_CONVERSION
) && surface
->resource
.allocatedMemory
)
5927 UINT height
= surface
->resource
.height
;
5928 UINT width
= surface
->resource
.width
;
5929 UINT src_pitch
, dst_pitch
;
5931 byte_count
= format
.conv_byte_count
;
5932 src_pitch
= wined3d_surface_get_pitch(surface
);
5934 /* Stick to the alignment for the converted surface too, makes it
5935 * easier to load the surface. */
5936 dst_pitch
= width
* byte_count
;
5937 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
5939 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
5941 ERR("Out of memory (%u).\n", dst_pitch
* height
);
5942 return E_OUTOFMEMORY
;
5945 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
,
5946 src_pitch
, width
, height
, dst_pitch
, convert
, surface
);
5948 surface
->flags
|= SFLAG_CONVERTED
;
5952 surface
->flags
&= ~SFLAG_CONVERTED
;
5953 mem
= surface
->resource
.allocatedMemory
;
5954 byte_count
= format
.byte_count
;
5957 flush_to_framebuffer_drawpixels(surface
, rect
, format
.glFormat
, format
.glType
, byte_count
, mem
);
5959 /* Don't delete PBO memory. */
5960 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
5961 HeapFree(GetProcessHeap(), 0, mem
);
5966 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
5967 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
, BOOL srgb
)
5969 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5970 struct wined3d_device
*device
= surface
->resource
.device
;
5971 struct wined3d_context
*context
;
5972 UINT width
, src_pitch
, dst_pitch
;
5973 struct wined3d_bo_address data
;
5974 struct wined3d_format format
;
5975 POINT dst_point
= {0, 0};
5976 CONVERT_TYPES convert
;
5979 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
5980 && surface_is_offscreen(surface
)
5981 && (surface
->flags
& SFLAG_INDRAWABLE
))
5983 surface_load_fb_texture(surface
, srgb
);
5988 if (surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INTEXTURE
)
5989 && (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
5990 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5991 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
5992 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
5995 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, SFLAG_INTEXTURE
,
5996 &src_rect
, surface
, SFLAG_INSRGBTEX
, &src_rect
);
5998 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, SFLAG_INSRGBTEX
,
5999 &src_rect
, surface
, SFLAG_INTEXTURE
, &src_rect
);
6004 if (surface
->flags
& (SFLAG_INRB_MULTISAMPLE
| SFLAG_INRB_RESOLVED
)
6005 && (!srgb
|| (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
6006 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
6007 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
6008 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
6010 DWORD src_location
= surface
->flags
& SFLAG_INRB_RESOLVED
? SFLAG_INRB_RESOLVED
: SFLAG_INRB_MULTISAMPLE
;
6011 DWORD dst_location
= srgb
? SFLAG_INSRGBTEX
: SFLAG_INTEXTURE
;
6012 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
6014 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, src_location
,
6015 &rect
, surface
, dst_location
, &rect
);
6020 /* Upload from system memory */
6022 d3dfmt_get_conv(surface
, TRUE
/* We need color keying */,
6023 TRUE
/* We will use textures */, &format
, &convert
);
6027 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSYSMEM
)) == SFLAG_INTEXTURE
)
6029 /* Performance warning... */
6030 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
6031 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
6036 if ((surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INSYSMEM
)) == SFLAG_INSRGBTEX
)
6038 /* Performance warning... */
6039 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
6040 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
6044 if (!(surface
->flags
& SFLAG_INSYSMEM
))
6046 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6047 /* Lets hope we get it from somewhere... */
6048 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
6051 /* TODO: Use already acquired context when possible. */
6052 context
= context_acquire(device
, NULL
);
6054 surface_prepare_texture(surface
, context
, srgb
);
6055 surface_bind_and_dirtify(surface
, context
, srgb
);
6057 if (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
6059 surface
->flags
|= SFLAG_GLCKEY
;
6060 surface
->gl_color_key
= surface
->src_blt_color_key
;
6062 else surface
->flags
&= ~SFLAG_GLCKEY
;
6064 width
= surface
->resource
.width
;
6065 src_pitch
= wined3d_surface_get_pitch(surface
);
6067 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6068 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6070 if ((convert
!= NO_CONVERSION
|| format
.convert
) && (surface
->flags
& SFLAG_PBO
))
6072 TRACE("Removing the pbo attached to surface %p.\n", surface
);
6073 surface_remove_pbo(surface
, gl_info
);
6078 /* This code is entered for texture formats which need a fixup. */
6079 UINT height
= surface
->resource
.height
;
6081 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6082 dst_pitch
= width
* format
.conv_byte_count
;
6083 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
6085 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
6087 ERR("Out of memory (%u).\n", dst_pitch
* height
);
6088 context_release(context
);
6089 return E_OUTOFMEMORY
;
6091 format
.convert(surface
->resource
.allocatedMemory
, mem
, src_pitch
, width
, height
);
6092 format
.byte_count
= format
.conv_byte_count
;
6093 src_pitch
= dst_pitch
;
6095 else if (convert
!= NO_CONVERSION
&& surface
->resource
.allocatedMemory
)
6097 /* This code is only entered for color keying fixups */
6098 UINT height
= surface
->resource
.height
;
6100 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6101 dst_pitch
= width
* format
.conv_byte_count
;
6102 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
6104 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
6106 ERR("Out of memory (%u).\n", dst_pitch
* height
);
6107 context_release(context
);
6108 return E_OUTOFMEMORY
;
6110 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
, src_pitch
,
6111 width
, height
, dst_pitch
, convert
, surface
);
6112 format
.byte_count
= format
.conv_byte_count
;
6113 src_pitch
= dst_pitch
;
6117 mem
= surface
->resource
.allocatedMemory
;
6120 data
.buffer_object
= surface
->flags
& SFLAG_PBO
? surface
->pbo
: 0;
6122 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, src_pitch
, &dst_point
, srgb
, &data
);
6124 context_release(context
);
6126 /* Don't delete PBO memory. */
6127 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
6128 HeapFree(GetProcessHeap(), 0, mem
);
6133 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
6135 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
6137 if (!(surface
->flags
& SFLAG_INRB_MULTISAMPLE
))
6138 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface
);
6140 surface_blt_fbo(surface
->resource
.device
, WINED3DTEXF_POINT
,
6141 surface
, SFLAG_INRB_MULTISAMPLE
, &rect
, surface
, SFLAG_INRB_RESOLVED
, &rect
);
6144 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
, const RECT
*rect
)
6146 struct wined3d_device
*device
= surface
->resource
.device
;
6147 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6150 TRACE("surface %p, location %s, rect %s.\n", surface
, debug_surflocation(location
), wine_dbgstr_rect(rect
));
6152 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
6154 if (location
== SFLAG_INTEXTURE
)
6156 struct wined3d_context
*context
= context_acquire(device
, NULL
);
6157 surface_load_ds_location(surface
, context
, location
);
6158 context_release(context
);
6163 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location
));
6164 return WINED3DERR_INVALIDCALL
;
6168 if (location
== SFLAG_INSRGBTEX
&& gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
6169 location
= SFLAG_INTEXTURE
;
6171 if (surface
->flags
& location
)
6173 TRACE("Location already up to date.\n");
6175 if (location
== SFLAG_INSYSMEM
&& !(surface
->flags
& SFLAG_PBO
)
6176 && surface_need_pbo(surface
, gl_info
))
6177 surface_load_pbo(surface
, gl_info
);
6182 if (WARN_ON(d3d_surface
))
6184 DWORD required_access
= resource_access_from_location(location
);
6185 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
6186 WARN("Operation requires %#x access, but surface only has %#x.\n",
6187 required_access
, surface
->resource
.access_flags
);
6190 if (!(surface
->flags
& SFLAG_LOCATIONS
))
6192 ERR("Surface %p does not have any up to date location.\n", surface
);
6193 surface
->flags
|= SFLAG_LOST
;
6194 return WINED3DERR_DEVICELOST
;
6199 case SFLAG_INSYSMEM
:
6200 surface_load_sysmem(surface
, gl_info
, rect
);
6203 case SFLAG_INDRAWABLE
:
6204 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
, rect
)))
6208 case SFLAG_INRB_RESOLVED
:
6209 surface_multisample_resolve(surface
);
6212 case SFLAG_INTEXTURE
:
6213 case SFLAG_INSRGBTEX
:
6214 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, rect
, location
== SFLAG_INSRGBTEX
)))
6219 ERR("Don't know how to handle location %#x.\n", location
);
6225 surface
->flags
|= location
;
6227 if (location
!= SFLAG_INSYSMEM
&& (surface
->flags
& SFLAG_INSYSMEM
))
6228 surface_evict_sysmem(surface
);
6231 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)
6232 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
6234 surface
->flags
|= (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
6240 BOOL
surface_is_offscreen(const struct wined3d_surface
*surface
)
6242 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
6244 /* Not on a swapchain - must be offscreen */
6245 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
) return TRUE
;
6247 /* The front buffer is always onscreen */
6248 if (surface
== swapchain
->front_buffer
) return FALSE
;
6250 /* If the swapchain is rendered to an FBO, the backbuffer is
6251 * offscreen, otherwise onscreen */
6252 return swapchain
->render_to_fbo
;
6255 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
6256 /* Context activation is done by the caller. */
6257 static void ffp_blit_free(struct wined3d_device
*device
) { }
6259 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6260 /* Context activation is done by the caller. */
6261 static void ffp_blit_p8_upload_palette(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
6264 BOOL colorkey_active
= (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
) ? TRUE
: FALSE
;
6266 d3dfmt_p8_init_palette(surface
, table
, colorkey_active
);
6268 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6270 GL_EXTCALL(glColorTableEXT(surface
->texture_target
, GL_RGBA
, 256, GL_RGBA
, GL_UNSIGNED_BYTE
, table
));
6274 /* Context activation is done by the caller. */
6275 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
6277 enum complex_fixup fixup
= get_complex_fixup(surface
->resource
.format
->color_fixup
);
6279 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6280 * else the surface is converted in software at upload time in LoadLocation.
6282 if (!(surface
->flags
& SFLAG_CONVERTED
) && fixup
== COMPLEX_FIXUP_P8
6283 && context
->gl_info
->supported
[EXT_PALETTED_TEXTURE
])
6284 ffp_blit_p8_upload_palette(surface
, context
->gl_info
);
6287 glEnable(surface
->texture_target
);
6288 checkGLcall("glEnable(surface->texture_target)");
6293 /* Context activation is done by the caller. */
6294 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
6297 glDisable(GL_TEXTURE_2D
);
6298 checkGLcall("glDisable(GL_TEXTURE_2D)");
6299 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
6301 glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
6302 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6304 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
6306 glDisable(GL_TEXTURE_RECTANGLE_ARB
);
6307 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6312 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
6313 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
6314 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
6316 enum complex_fixup src_fixup
;
6320 case WINED3D_BLIT_OP_COLOR_BLIT
:
6321 if (src_pool
== WINED3DPOOL_SYSTEMMEM
|| dst_pool
== WINED3DPOOL_SYSTEMMEM
)
6324 src_fixup
= get_complex_fixup(src_format
->color_fixup
);
6325 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
6327 TRACE("Checking support for fixup:\n");
6328 dump_color_fixup_desc(src_format
->color_fixup
);
6331 if (!is_identity_fixup(dst_format
->color_fixup
))
6333 TRACE("Destination fixups are not supported\n");
6337 if (src_fixup
== COMPLEX_FIXUP_P8
&& gl_info
->supported
[EXT_PALETTED_TEXTURE
])
6339 TRACE("P8 fixup supported\n");
6343 /* We only support identity conversions. */
6344 if (is_identity_fixup(src_format
->color_fixup
))
6350 TRACE("[FAILED]\n");
6353 case WINED3D_BLIT_OP_COLOR_FILL
:
6354 if (dst_pool
== WINED3DPOOL_SYSTEMMEM
)
6357 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6359 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
6362 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
6364 TRACE("Color fill not supported\n");
6368 /* FIXME: We should reject color fills on formats with fixups,
6369 * but this would break P8 color fills for example. */
6373 case WINED3D_BLIT_OP_DEPTH_FILL
:
6377 TRACE("Unsupported blit_op=%d\n", blit_op
);
6382 /* Do not call while under the GL lock. */
6383 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
6384 const RECT
*dst_rect
, const struct wined3d_color
*color
)
6386 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
6387 struct wined3d_fb_state fb
= {&dst_surface
, NULL
};
6389 return device_clear_render_targets(device
, 1, &fb
,
6390 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
6393 /* Do not call while under the GL lock. */
6394 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
6395 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
6397 const RECT draw_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
6398 struct wined3d_fb_state fb
= {NULL
, surface
};
6400 return device_clear_render_targets(device
, 0, &fb
,
6401 1, rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
6404 const struct blit_shader ffp_blit
= {
6410 ffp_blit_color_fill
,
6411 ffp_blit_depth_fill
,
6414 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
6419 /* Context activation is done by the caller. */
6420 static void cpu_blit_free(struct wined3d_device
*device
)
6424 /* Context activation is done by the caller. */
6425 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
6430 /* Context activation is done by the caller. */
6431 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
6435 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
6436 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
6437 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
6439 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
6447 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
6448 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
6449 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
6451 UINT row_block_count
;
6452 const BYTE
*src_row
;
6459 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
6463 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
6465 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
6466 src_row
+= src_pitch
;
6467 dst_row
+= dst_pitch
;
6473 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
6475 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
6479 case WINED3DFMT_DXT1
:
6480 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
6485 BYTE control_row
[4];
6488 const struct block
*s
= (const struct block
*)src_row
;
6489 struct block
*d
= (struct block
*)dst_row
;
6491 for (x
= 0; x
< row_block_count
; ++x
)
6493 d
[x
].color
[0] = s
[x
].color
[0];
6494 d
[x
].color
[1] = s
[x
].color
[1];
6495 d
[x
].control_row
[0] = s
[x
].control_row
[3];
6496 d
[x
].control_row
[1] = s
[x
].control_row
[2];
6497 d
[x
].control_row
[2] = s
[x
].control_row
[1];
6498 d
[x
].control_row
[3] = s
[x
].control_row
[0];
6500 src_row
-= src_pitch
;
6501 dst_row
+= dst_pitch
;
6505 case WINED3DFMT_DXT3
:
6506 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
6512 BYTE control_row
[4];
6515 const struct block
*s
= (const struct block
*)src_row
;
6516 struct block
*d
= (struct block
*)dst_row
;
6518 for (x
= 0; x
< row_block_count
; ++x
)
6520 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
6521 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
6522 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
6523 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
6524 d
[x
].color
[0] = s
[x
].color
[0];
6525 d
[x
].color
[1] = s
[x
].color
[1];
6526 d
[x
].control_row
[0] = s
[x
].control_row
[3];
6527 d
[x
].control_row
[1] = s
[x
].control_row
[2];
6528 d
[x
].control_row
[2] = s
[x
].control_row
[1];
6529 d
[x
].control_row
[3] = s
[x
].control_row
[0];
6531 src_row
-= src_pitch
;
6532 dst_row
+= dst_pitch
;
6537 FIXME("Compressed flip not implemented for format %s.\n",
6538 debug_d3dformat(format
->id
));
6543 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
6544 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
6549 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
6550 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
6551 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
)
6553 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
6554 const struct wined3d_format
*src_format
, *dst_format
;
6555 struct wined3d_surface
*orig_src
= src_surface
;
6556 struct wined3d_mapped_rect dst_map
, src_map
;
6557 HRESULT hr
= WINED3D_OK
;
6563 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6564 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
6565 flags
, fx
, debug_d3dtexturefiltertype(filter
));
6575 full_rect
.right
= dst_surface
->resource
.width
;
6576 full_rect
.bottom
= dst_surface
->resource
.height
;
6577 IntersectRect(&xdst
, &full_rect
, dst_rect
);
6581 BOOL clip_horiz
, clip_vert
;
6584 clip_horiz
= xdst
.left
< 0 || xdst
.right
> (int)dst_surface
->resource
.width
;
6585 clip_vert
= xdst
.top
< 0 || xdst
.bottom
> (int)dst_surface
->resource
.height
;
6587 if (clip_vert
|| clip_horiz
)
6589 /* Now check if this is a special case or not... */
6590 if ((flags
& WINEDDBLT_DDFX
)
6591 || (clip_horiz
&& xdst
.right
- xdst
.left
!= xsrc
.right
- xsrc
.left
)
6592 || (clip_vert
&& xdst
.bottom
- xdst
.top
!= xsrc
.bottom
- xsrc
.top
))
6594 WARN("Out of screen rectangle in special case. Not handled right now.\n");
6602 xsrc
.left
-= xdst
.left
;
6605 if (xdst
.right
> dst_surface
->resource
.width
)
6607 xsrc
.right
-= (xdst
.right
- (int)dst_surface
->resource
.width
);
6608 xdst
.right
= (int)dst_surface
->resource
.width
;
6616 xsrc
.top
-= xdst
.top
;
6619 if (xdst
.bottom
> dst_surface
->resource
.height
)
6621 xsrc
.bottom
-= (xdst
.bottom
- (int)dst_surface
->resource
.height
);
6622 xdst
.bottom
= (int)dst_surface
->resource
.height
;
6626 /* And check if after clipping something is still to be done... */
6627 if ((xdst
.right
<= 0) || (xdst
.bottom
<= 0)
6628 || (xdst
.left
>= (int)dst_surface
->resource
.width
)
6629 || (xdst
.top
>= (int)dst_surface
->resource
.height
)
6630 || (xsrc
.right
<= 0) || (xsrc
.bottom
<= 0)
6631 || (xsrc
.left
>= (int)src_surface
->resource
.width
)
6632 || (xsrc
.top
>= (int)src_surface
->resource
.height
))
6634 TRACE("Nothing to be done after clipping.\n");
6640 if (src_surface
== dst_surface
)
6642 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
6644 src_format
= dst_surface
->resource
.format
;
6645 dst_format
= src_format
;
6649 dst_format
= dst_surface
->resource
.format
;
6652 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
6654 src_surface
= surface_convert_format(src_surface
, dst_format
->id
);
6657 /* The conv function writes a FIXME */
6658 WARN("Cannot convert source surface format to dest format.\n");
6662 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3DLOCK_READONLY
);
6663 src_format
= src_surface
->resource
.format
;
6667 src_format
= dst_format
;
6670 wined3d_surface_map(dst_surface
, &dst_map
, &xdst
, 0);
6672 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
6675 bpp
= dst_surface
->resource
.format
->byte_count
;
6676 srcheight
= xsrc
.bottom
- xsrc
.top
;
6677 srcwidth
= xsrc
.right
- xsrc
.left
;
6678 dstheight
= xdst
.bottom
- xdst
.top
;
6679 dstwidth
= xdst
.right
- xdst
.left
;
6680 width
= (xdst
.right
- xdst
.left
) * bpp
;
6682 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
6684 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
6686 if (src_surface
== dst_surface
)
6688 FIXME("Only plain blits supported on compressed surfaces.\n");
6693 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
6695 WARN("Stretching not supported on compressed surfaces.\n");
6696 hr
= WINED3DERR_INVALIDCALL
;
6700 if (srcwidth
& (src_format
->block_width
- 1) || srcheight
& (src_format
->block_height
- 1))
6702 WARN("Rectangle not block-aligned.\n");
6703 hr
= WINED3DERR_INVALIDCALL
;
6707 hr
= surface_cpu_blt_compressed(src_map
.data
, dst_map
.data
,
6708 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
6709 src_format
, flags
, fx
);
6713 if (dst_rect
&& src_surface
!= dst_surface
)
6714 dbuf
= dst_map
.data
;
6716 dbuf
= (BYTE
*)dst_map
.data
+ (xdst
.top
* dst_map
.row_pitch
) + (xdst
.left
* bpp
);
6718 /* First, all the 'source-less' blits */
6719 if (flags
& WINEDDBLT_COLORFILL
)
6721 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->u5
.dwFillColor
);
6722 flags
&= ~WINEDDBLT_COLORFILL
;
6725 if (flags
& WINEDDBLT_DEPTHFILL
)
6727 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6729 if (flags
& WINEDDBLT_ROP
)
6731 /* Catch some degenerate cases here. */
6735 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, 0);
6737 case 0xAA0029: /* No-op */
6740 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, ~0U);
6742 case SRCCOPY
: /* Well, we do that below? */
6745 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
6748 flags
&= ~WINEDDBLT_ROP
;
6750 if (flags
& WINEDDBLT_DDROPS
)
6752 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
6754 /* Now the 'with source' blits. */
6758 int sx
, xinc
, sy
, yinc
;
6760 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
6763 if (filter
!= WINED3DTEXF_NONE
&& filter
!= WINED3DTEXF_POINT
6764 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
6766 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6767 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
6770 sbase
= (BYTE
*)src_map
.data
+ (xsrc
.top
* src_map
.row_pitch
) + xsrc
.left
* bpp
;
6771 xinc
= (srcwidth
<< 16) / dstwidth
;
6772 yinc
= (srcheight
<< 16) / dstheight
;
6776 /* No effects, we can cheat here. */
6777 if (dstwidth
== srcwidth
)
6779 if (dstheight
== srcheight
)
6781 /* No stretching in either direction. This needs to be as
6782 * fast as possible. */
6785 /* Check for overlapping surfaces. */
6786 if (src_surface
!= dst_surface
|| xdst
.top
< xsrc
.top
6787 || xdst
.right
<= xsrc
.left
|| xsrc
.right
<= xdst
.left
)
6789 /* No overlap, or dst above src, so copy from top downwards. */
6790 for (y
= 0; y
< dstheight
; ++y
)
6792 memcpy(dbuf
, sbuf
, width
);
6793 sbuf
+= src_map
.row_pitch
;
6794 dbuf
+= dst_map
.row_pitch
;
6797 else if (xdst
.top
> xsrc
.top
)
6799 /* Copy from bottom upwards. */
6800 sbuf
+= src_map
.row_pitch
* dstheight
;
6801 dbuf
+= dst_map
.row_pitch
* dstheight
;
6802 for (y
= 0; y
< dstheight
; ++y
)
6804 sbuf
-= src_map
.row_pitch
;
6805 dbuf
-= dst_map
.row_pitch
;
6806 memcpy(dbuf
, sbuf
, width
);
6811 /* Src and dst overlapping on the same line, use memmove. */
6812 for (y
= 0; y
< dstheight
; ++y
)
6814 memmove(dbuf
, sbuf
, width
);
6815 sbuf
+= src_map
.row_pitch
;
6816 dbuf
+= dst_map
.row_pitch
;
6822 /* Stretching in y direction only. */
6823 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6825 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
6826 memcpy(dbuf
, sbuf
, width
);
6827 dbuf
+= dst_map
.row_pitch
;
6833 /* Stretching in X direction. */
6835 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6837 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
6839 if ((sy
>> 16) == (last_sy
>> 16))
6841 /* This source row is the same as last source row -
6842 * Copy the already stretched row. */
6843 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
6847 #define STRETCH_ROW(type) \
6849 const type *s = (const type *)sbuf; \
6850 type *d = (type *)dbuf; \
6851 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6852 d[x] = s[sx >> 16]; \
6870 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
6874 s
= sbuf
+ 3 * (sx
>> 16);
6875 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
6876 d
[0] = (pixel
) & 0xff;
6877 d
[1] = (pixel
>> 8) & 0xff;
6878 d
[2] = (pixel
>> 16) & 0xff;
6884 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
6885 hr
= WINED3DERR_NOTAVAILABLE
;
6890 dbuf
+= dst_map
.row_pitch
;
6897 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
6898 DWORD keylow
= 0xFFFFFFFF, keyhigh
= 0, keymask
= 0xFFFFFFFF;
6899 DWORD destkeylow
= 0x0, destkeyhigh
= 0xFFFFFFFF, destkeymask
= 0xFFFFFFFF;
6900 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
6902 /* The color keying flags are checked for correctness in ddraw */
6903 if (flags
& WINEDDBLT_KEYSRC
)
6905 keylow
= src_surface
->src_blt_color_key
.color_space_low_value
;
6906 keyhigh
= src_surface
->src_blt_color_key
.color_space_high_value
;
6908 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
6910 keylow
= fx
->ddckSrcColorkey
.color_space_low_value
;
6911 keyhigh
= fx
->ddckSrcColorkey
.color_space_high_value
;
6914 if (flags
& WINEDDBLT_KEYDEST
)
6916 /* Destination color keys are taken from the source surface! */
6917 destkeylow
= src_surface
->dst_blt_color_key
.color_space_low_value
;
6918 destkeyhigh
= src_surface
->dst_blt_color_key
.color_space_high_value
;
6920 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
6922 destkeylow
= fx
->ddckDestColorkey
.color_space_low_value
;
6923 destkeyhigh
= fx
->ddckDestColorkey
.color_space_high_value
;
6932 keymask
= src_format
->red_mask
6933 | src_format
->green_mask
6934 | src_format
->blue_mask
;
6936 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
6939 if (flags
& WINEDDBLT_DDFX
)
6941 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
6944 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
6945 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
6946 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
6948 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
6950 /* I don't think we need to do anything about this flag */
6951 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6953 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
6956 dTopRight
= dTopLeft
;
6959 dBottomRight
= dBottomLeft
;
6961 dstxinc
= dstxinc
* -1;
6963 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
6966 dTopLeft
= dBottomLeft
;
6969 dTopRight
= dBottomRight
;
6971 dstyinc
= dstyinc
* -1;
6973 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
6975 /* I don't think we need to do anything about this flag */
6976 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
6978 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
6981 dBottomRight
= dTopLeft
;
6984 dBottomLeft
= dTopRight
;
6986 dstxinc
= dstxinc
* -1;
6987 dstyinc
= dstyinc
* -1;
6989 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
6992 dTopLeft
= dBottomLeft
;
6993 dBottomLeft
= dBottomRight
;
6994 dBottomRight
= dTopRight
;
6999 dstxinc
= dstxinc
* -1;
7001 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
7004 dTopLeft
= dTopRight
;
7005 dTopRight
= dBottomRight
;
7006 dBottomRight
= dBottomLeft
;
7011 dstyinc
= dstyinc
* -1;
7013 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
7015 /* I don't think we need to do anything about this flag */
7016 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7019 flags
&= ~(WINEDDBLT_DDFX
);
7022 #define COPY_COLORKEY_FX(type) \
7025 type *d = (type *)dbuf, *dx, tmp; \
7026 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7028 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7030 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7032 tmp = s[sx >> 16]; \
7033 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7034 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7038 dx = (type *)(((BYTE *)dx) + dstxinc); \
7040 d = (type *)(((BYTE *)d) + dstyinc); \
7047 COPY_COLORKEY_FX(BYTE
);
7050 COPY_COLORKEY_FX(WORD
);
7053 COPY_COLORKEY_FX(DWORD
);
7058 BYTE
*d
= dbuf
, *dx
;
7059 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
7061 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
7063 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
7065 DWORD pixel
, dpixel
= 0;
7066 s
= sbuf
+ 3 * (sx
>>16);
7067 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
7068 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
7069 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
7070 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
7072 dx
[0] = (pixel
) & 0xff;
7073 dx
[1] = (pixel
>> 8) & 0xff;
7074 dx
[2] = (pixel
>> 16) & 0xff;
7083 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7084 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
7085 hr
= WINED3DERR_NOTAVAILABLE
;
7087 #undef COPY_COLORKEY_FX
7093 if (flags
&& FIXME_ON(d3d_surface
))
7095 FIXME("\tUnsupported flags: %#x.\n", flags
);
7099 wined3d_surface_unmap(dst_surface
);
7100 if (src_surface
&& src_surface
!= dst_surface
)
7101 wined3d_surface_unmap(src_surface
);
7102 /* Release the converted surface, if any. */
7103 if (src_surface
&& src_surface
!= orig_src
)
7104 wined3d_surface_decref(src_surface
);
7109 /* Do not call while under the GL lock. */
7110 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
7111 const RECT
*dst_rect
, const struct wined3d_color
*color
)
7113 static const RECT src_rect
;
7116 memset(&BltFx
, 0, sizeof(BltFx
));
7117 BltFx
.dwSize
= sizeof(BltFx
);
7118 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
7119 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
7120 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
7123 /* Do not call while under the GL lock. */
7124 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
7125 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
7127 FIXME("Depth filling not implemented by cpu_blit.\n");
7128 return WINED3DERR_INVALIDCALL
;
7131 const struct blit_shader cpu_blit
= {
7137 cpu_blit_color_fill
,
7138 cpu_blit_depth_fill
,
7141 static HRESULT
surface_init(struct wined3d_surface
*surface
, WINED3DSURFTYPE surface_type
, UINT alignment
,
7142 UINT width
, UINT height
, UINT level
, enum wined3d_multisample_type multisample_type
,
7143 UINT multisample_quality
, struct wined3d_device
*device
, DWORD usage
, enum wined3d_format_id format_id
,
7144 WINED3DPOOL pool
, DWORD flags
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
7146 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
7147 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
7148 BOOL lockable
= flags
& WINED3D_SURFACE_MAPPABLE
;
7149 unsigned int resource_size
;
7152 if (multisample_quality
> 0)
7154 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
7155 multisample_quality
= 0;
7158 /* Quick lockable sanity check.
7159 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7160 * this function is too deep to need to care about things like this.
7161 * Levels need to be checked too, since they all affect what can be done. */
7164 case WINED3DPOOL_SCRATCH
:
7167 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7168 "which are mutually exclusive, setting lockable to TRUE.\n");
7173 case WINED3DPOOL_SYSTEMMEM
:
7175 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7178 case WINED3DPOOL_MANAGED
:
7179 if (usage
& WINED3DUSAGE_DYNAMIC
)
7180 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7183 case WINED3DPOOL_DEFAULT
:
7184 if (lockable
&& !(usage
& (WINED3DUSAGE_DYNAMIC
| WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
7185 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7189 FIXME("Unknown pool %#x.\n", pool
);
7193 if (usage
& WINED3DUSAGE_RENDERTARGET
&& pool
!= WINED3DPOOL_DEFAULT
)
7194 FIXME("Trying to create a render target that isn't in the default pool.\n");
7196 /* FIXME: Check that the format is supported by the device. */
7198 resource_size
= wined3d_format_calculate_size(format
, alignment
, width
, height
);
7200 return WINED3DERR_INVALIDCALL
;
7202 surface
->surface_type
= surface_type
;
7204 switch (surface_type
)
7206 case SURFACE_OPENGL
:
7207 surface
->surface_ops
= &surface_ops
;
7211 surface
->surface_ops
= &gdi_surface_ops
;
7215 ERR("Requested unknown surface implementation %#x.\n", surface_type
);
7216 return WINED3DERR_INVALIDCALL
;
7219 hr
= resource_init(&surface
->resource
, device
, WINED3DRTYPE_SURFACE
, format
,
7220 multisample_type
, multisample_quality
, usage
, pool
, width
, height
, 1,
7221 resource_size
, parent
, parent_ops
, &surface_resource_ops
);
7224 WARN("Failed to initialize resource, returning %#x.\n", hr
);
7228 /* "Standalone" surface. */
7229 surface_set_container(surface
, WINED3D_CONTAINER_NONE
, NULL
);
7231 surface
->texture_level
= level
;
7232 list_init(&surface
->overlays
);
7235 surface
->flags
= SFLAG_NORMCOORD
; /* Default to normalized coords. */
7236 if (flags
& WINED3D_SURFACE_DISCARD
)
7237 surface
->flags
|= SFLAG_DISCARD
;
7238 if (flags
& WINED3D_SURFACE_PIN_SYSMEM
)
7239 surface
->flags
|= SFLAG_PIN_SYSMEM
;
7240 if (lockable
|| format_id
== WINED3DFMT_D16_LOCKABLE
)
7241 surface
->flags
|= SFLAG_LOCKABLE
;
7242 /* I'm not sure if this qualifies as a hack or as an optimization. It
7243 * seems reasonable to assume that lockable render targets will get
7244 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7245 * creation. However, the other reason we want to do this is that several
7246 * ddraw applications access surface memory while the surface isn't
7247 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7248 * future locks prevents these from crashing. */
7249 if (lockable
&& (usage
& WINED3DUSAGE_RENDERTARGET
))
7250 surface
->flags
|= SFLAG_DYNLOCK
;
7252 /* Mark the texture as dirty so that it gets loaded first time around. */
7253 surface_add_dirty_rect(surface
, NULL
);
7254 list_init(&surface
->renderbuffers
);
7256 TRACE("surface %p, memory %p, size %u\n",
7257 surface
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
7259 /* Call the private setup routine */
7260 hr
= surface
->surface_ops
->surface_private_setup(surface
);
7263 ERR("Private setup failed, returning %#x\n", hr
);
7264 surface_cleanup(surface
);
7268 /* Similar to lockable rendertargets above, creating the DIB section
7269 * during surface initialization prevents the sysmem pointer from changing
7270 * after a wined3d_surface_getdc() call. */
7271 if ((usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
7272 && SUCCEEDED(surface_create_dib_section(surface
)))
7274 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
7275 surface
->resource
.heapMemory
= NULL
;
7276 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
7282 HRESULT CDECL
wined3d_surface_create(struct wined3d_device
*device
, UINT width
, UINT height
,
7283 enum wined3d_format_id format_id
, UINT level
, DWORD usage
, WINED3DPOOL pool
,
7284 enum wined3d_multisample_type multisample_type
, DWORD multisample_quality
, WINED3DSURFTYPE surface_type
,
7285 DWORD flags
, void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_surface
**surface
)
7287 struct wined3d_surface
*object
;
7290 TRACE("device %p, width %u, height %u, format %s, level %u\n",
7291 device
, width
, height
, debug_d3dformat(format_id
), level
);
7292 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7293 surface
, debug_d3dusage(usage
), usage
, debug_d3dpool(pool
), multisample_type
, multisample_quality
);
7294 TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type
, flags
, parent
, parent_ops
);
7296 if (surface_type
== SURFACE_OPENGL
&& !device
->adapter
)
7298 ERR("OpenGL surfaces are not available without OpenGL.\n");
7299 return WINED3DERR_NOTAVAILABLE
;
7302 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
7305 ERR("Failed to allocate surface memory.\n");
7306 return WINED3DERR_OUTOFVIDEOMEMORY
;
7309 hr
= surface_init(object
, surface_type
, device
->surface_alignment
, width
, height
, level
,
7310 multisample_type
, multisample_quality
, device
, usage
, format_id
, pool
, flags
, parent
, parent_ops
);
7313 WARN("Failed to initialize surface, returning %#x.\n", hr
);
7314 HeapFree(GetProcessHeap(), 0, object
);
7318 TRACE("Created surface %p.\n", object
);