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-2008 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 TRACE("surface %p.\n", surface
);
47 if (surface
->texture_name
|| (surface
->flags
& SFLAG_PBO
)
48 || surface
->rb_multisample
|| surface
->rb_resolved
49 || !list_empty(&surface
->renderbuffers
))
51 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
52 const struct wined3d_gl_info
*gl_info
;
53 struct wined3d_context
*context
;
55 context
= context_acquire(surface
->resource
.device
, NULL
);
56 gl_info
= context
->gl_info
;
60 if (surface
->texture_name
)
62 TRACE("Deleting texture %u.\n", surface
->texture_name
);
63 glDeleteTextures(1, &surface
->texture_name
);
66 if (surface
->flags
& SFLAG_PBO
)
68 TRACE("Deleting PBO %u.\n", surface
->pbo
);
69 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
72 if (surface
->rb_multisample
)
74 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
75 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
78 if (surface
->rb_resolved
)
80 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
81 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
84 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
86 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
87 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
88 HeapFree(GetProcessHeap(), 0, entry
);
93 context_release(context
);
96 if (surface
->flags
& SFLAG_DIBSECTION
)
99 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
100 DeleteDC(surface
->hDC
);
101 /* Release the DIB section. */
102 DeleteObject(surface
->dib
.DIBsection
);
103 surface
->dib
.bitmap_data
= NULL
;
104 surface
->resource
.allocatedMemory
= NULL
;
107 if (surface
->flags
& SFLAG_USERPTR
)
108 wined3d_surface_set_mem(surface
, NULL
);
109 if (surface
->overlay_dest
)
110 list_remove(&surface
->overlay_entry
);
112 HeapFree(GetProcessHeap(), 0, surface
->palette9
);
114 resource_cleanup(&surface
->resource
);
117 void surface_update_draw_binding(struct wined3d_surface
*surface
)
119 if (!surface_is_offscreen(surface
) || wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
)
120 surface
->draw_binding
= SFLAG_INDRAWABLE
;
121 else if (surface
->resource
.multisample_type
)
122 surface
->draw_binding
= SFLAG_INRB_MULTISAMPLE
;
124 surface
->draw_binding
= SFLAG_INTEXTURE
;
127 void surface_set_container(struct wined3d_surface
*surface
, enum wined3d_container_type type
, void *container
)
129 TRACE("surface %p, container %p.\n", surface
, container
);
131 if (!container
&& type
!= WINED3D_CONTAINER_NONE
)
132 ERR("Setting NULL container of type %#x.\n", type
);
134 if (type
== WINED3D_CONTAINER_SWAPCHAIN
)
136 surface
->get_drawable_size
= get_drawable_size_swapchain
;
140 switch (wined3d_settings
.offscreen_rendering_mode
)
143 surface
->get_drawable_size
= get_drawable_size_fbo
;
147 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
151 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
156 surface
->container
.type
= type
;
157 surface
->container
.u
.base
= container
;
158 surface_update_draw_binding(surface
);
165 enum tex_types tex_type
;
166 GLfloat coords
[4][3];
177 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
179 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
180 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
181 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
182 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
185 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
187 GLfloat (*coords
)[3] = info
->coords
;
193 FIXME("Unsupported texture target %#x\n", target
);
194 /* Fall back to GL_TEXTURE_2D */
196 info
->binding
= GL_TEXTURE_BINDING_2D
;
197 info
->bind_target
= GL_TEXTURE_2D
;
198 info
->tex_type
= tex_2d
;
199 coords
[0][0] = (float)rect
->left
/ w
;
200 coords
[0][1] = (float)rect
->top
/ h
;
203 coords
[1][0] = (float)rect
->right
/ w
;
204 coords
[1][1] = (float)rect
->top
/ h
;
207 coords
[2][0] = (float)rect
->left
/ w
;
208 coords
[2][1] = (float)rect
->bottom
/ h
;
211 coords
[3][0] = (float)rect
->right
/ w
;
212 coords
[3][1] = (float)rect
->bottom
/ h
;
216 case GL_TEXTURE_RECTANGLE_ARB
:
217 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
218 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
219 info
->tex_type
= tex_rect
;
220 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
221 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
222 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
223 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
226 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
227 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
228 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
229 info
->tex_type
= tex_cube
;
230 cube_coords_float(rect
, w
, h
, &f
);
232 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
233 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
234 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
235 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
238 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
239 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
240 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
241 info
->tex_type
= tex_cube
;
242 cube_coords_float(rect
, w
, h
, &f
);
244 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
245 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
246 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
247 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
250 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
251 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
252 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
253 info
->tex_type
= tex_cube
;
254 cube_coords_float(rect
, w
, h
, &f
);
256 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
257 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
258 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
259 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
262 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
263 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
264 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
265 info
->tex_type
= tex_cube
;
266 cube_coords_float(rect
, w
, h
, &f
);
268 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
269 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
270 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
271 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
274 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
275 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
276 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
277 info
->tex_type
= tex_cube
;
278 cube_coords_float(rect
, w
, h
, &f
);
280 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
281 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
282 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
283 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
286 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
287 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
288 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
289 info
->tex_type
= tex_cube
;
290 cube_coords_float(rect
, w
, h
, &f
);
292 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
293 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
294 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
295 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
300 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
303 *rect_out
= *rect_in
;
308 rect_out
->right
= surface
->resource
.width
;
309 rect_out
->bottom
= surface
->resource
.height
;
313 /* GL locking and context activation is done by the caller */
314 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
315 const RECT
*src_rect
, const RECT
*dst_rect
, WINED3DTEXTUREFILTERTYPE Filter
)
317 struct blt_info info
;
319 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
321 glEnable(info
.bind_target
);
322 checkGLcall("glEnable(bind_target)");
324 context_bind_texture(context
, info
.bind_target
, src_surface
->texture_name
);
326 /* Filtering for StretchRect */
327 glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
328 wined3d_gl_mag_filter(magLookup
, Filter
));
329 checkGLcall("glTexParameteri");
330 glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
331 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
332 checkGLcall("glTexParameteri");
333 glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
334 glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
335 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
336 glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
337 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
338 checkGLcall("glTexEnvi");
341 glBegin(GL_TRIANGLE_STRIP
);
342 glTexCoord3fv(info
.coords
[0]);
343 glVertex2i(dst_rect
->left
, dst_rect
->top
);
345 glTexCoord3fv(info
.coords
[1]);
346 glVertex2i(dst_rect
->right
, dst_rect
->top
);
348 glTexCoord3fv(info
.coords
[2]);
349 glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
351 glTexCoord3fv(info
.coords
[3]);
352 glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
355 /* Unbind the texture */
356 context_bind_texture(context
, info
.bind_target
, 0);
358 /* We changed the filtering settings on the texture. Inform the
359 * container about this to get the filters reset properly next draw. */
360 if (src_surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
362 struct wined3d_texture
*texture
= src_surface
->container
.u
.texture
;
363 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
364 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
365 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3DTEXF_NONE
;
366 texture
->texture_rgb
.states
[WINED3DTEXSTA_SRGBTEXTURE
] = FALSE
;
370 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
372 const struct wined3d_format
*format
= surface
->resource
.format
;
380 TRACE("surface %p.\n", surface
);
382 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
384 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
385 return WINED3DERR_INVALIDCALL
;
388 switch (format
->byte_count
)
392 /* Allocate extra space to store the RGB bit masks. */
393 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
397 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
401 /* Allocate extra space for a palette. */
402 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
403 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
408 return E_OUTOFMEMORY
;
410 /* Some applications access the surface in via DWORDs, and do not take
411 * the necessary care at the end of the surface. So we need at least
412 * 4 extra bytes at the end of the surface. Check against the page size,
413 * if the last page used for the surface has at least 4 spare bytes we're
414 * safe, otherwise add an extra line to the DIB section. */
415 GetSystemInfo(&sysInfo
);
416 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
419 TRACE("Adding an extra line to the DIB section.\n");
422 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
423 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
424 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
425 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
426 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
427 * wined3d_surface_get_pitch(surface
);
428 b_info
->bmiHeader
.biPlanes
= 1;
429 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
431 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
432 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
433 b_info
->bmiHeader
.biClrUsed
= 0;
434 b_info
->bmiHeader
.biClrImportant
= 0;
436 /* Get the bit masks */
437 masks
= (DWORD
*)b_info
->bmiColors
;
438 switch (surface
->resource
.format
->id
)
440 case WINED3DFMT_B8G8R8_UNORM
:
441 usage
= DIB_RGB_COLORS
;
442 b_info
->bmiHeader
.biCompression
= BI_RGB
;
445 case WINED3DFMT_B5G5R5X1_UNORM
:
446 case WINED3DFMT_B5G5R5A1_UNORM
:
447 case WINED3DFMT_B4G4R4A4_UNORM
:
448 case WINED3DFMT_B4G4R4X4_UNORM
:
449 case WINED3DFMT_B2G3R3_UNORM
:
450 case WINED3DFMT_B2G3R3A8_UNORM
:
451 case WINED3DFMT_R10G10B10A2_UNORM
:
452 case WINED3DFMT_R8G8B8A8_UNORM
:
453 case WINED3DFMT_R8G8B8X8_UNORM
:
454 case WINED3DFMT_B10G10R10A2_UNORM
:
455 case WINED3DFMT_B5G6R5_UNORM
:
456 case WINED3DFMT_R16G16B16A16_UNORM
:
458 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
459 masks
[0] = format
->red_mask
;
460 masks
[1] = format
->green_mask
;
461 masks
[2] = format
->blue_mask
;
465 /* Don't know palette */
466 b_info
->bmiHeader
.biCompression
= BI_RGB
;
471 if (!(dc
= GetDC(0)))
473 HeapFree(GetProcessHeap(), 0, b_info
);
474 return HRESULT_FROM_WIN32(GetLastError());
477 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
478 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
479 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
480 surface
->dib
.DIBsection
= CreateDIBSection(dc
, b_info
, usage
, &surface
->dib
.bitmap_data
, 0, 0);
483 if (!surface
->dib
.DIBsection
)
485 ERR("Failed to create DIB section.\n");
486 HeapFree(GetProcessHeap(), 0, b_info
);
487 return HRESULT_FROM_WIN32(GetLastError());
490 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
491 /* Copy the existing surface to the dib section. */
492 if (surface
->resource
.allocatedMemory
)
494 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
,
495 surface
->resource
.height
* wined3d_surface_get_pitch(surface
));
499 /* This is to make maps read the GL texture although memory is allocated. */
500 surface
->flags
&= ~SFLAG_INSYSMEM
;
502 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
504 HeapFree(GetProcessHeap(), 0, b_info
);
506 /* Now allocate a DC. */
507 surface
->hDC
= CreateCompatibleDC(0);
508 surface
->dib
.holdbitmap
= SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
509 TRACE("Using wined3d palette %p.\n", surface
->palette
);
510 SelectPalette(surface
->hDC
, surface
->palette
? surface
->palette
->hpal
: 0, FALSE
);
512 surface
->flags
|= SFLAG_DIBSECTION
;
514 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
515 surface
->resource
.heapMemory
= NULL
;
520 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
522 struct wined3d_device
*device
= surface
->resource
.device
;
523 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
525 TRACE("surface %p.\n", surface
);
527 /* Performance optimization: Count how often a surface is locked, if it is
528 * locked regularly do not throw away the system memory copy. This avoids
529 * the need to download the surface from OpenGL all the time. The surface
530 * is still downloaded if the OpenGL texture is changed. */
531 if (!(surface
->flags
& SFLAG_DYNLOCK
))
533 if (++surface
->lockCount
> MAXLOCKCOUNT
)
535 TRACE("Surface is locked regularly, not freeing the system memory copy any more.\n");
536 surface
->flags
|= SFLAG_DYNLOCK
;
540 /* Create a PBO for dynamically locked surfaces but don't do it for
541 * converted or NPOT surfaces. Also don't create a PBO for systemmem
543 if (gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
] && (surface
->flags
& SFLAG_DYNLOCK
)
544 && !(surface
->flags
& (SFLAG_PBO
| SFLAG_CONVERTED
| SFLAG_NONPOW2
))
545 && (surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
))
547 struct wined3d_context
*context
;
550 context
= context_acquire(device
, NULL
);
553 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
554 error
= glGetError();
555 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
556 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
558 TRACE("Binding PBO %u.\n", surface
->pbo
);
560 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
561 checkGLcall("glBindBufferARB");
563 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->resource
.size
+ 4,
564 surface
->resource
.allocatedMemory
, GL_STREAM_DRAW_ARB
));
565 checkGLcall("glBufferDataARB");
567 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
568 checkGLcall("glBindBufferARB");
570 /* We don't need the system memory anymore and we can't even use it for PBOs. */
571 if (!(surface
->flags
& SFLAG_CLIENT
))
573 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
574 surface
->resource
.heapMemory
= NULL
;
576 surface
->resource
.allocatedMemory
= NULL
;
577 surface
->flags
|= SFLAG_PBO
;
579 context_release(context
);
581 else if (!(surface
->resource
.allocatedMemory
|| surface
->flags
& SFLAG_PBO
))
583 /* Whatever surface we have, make sure that there is memory allocated
584 * for the downloaded copy, or a PBO to map. */
585 if (!surface
->resource
.heapMemory
)
586 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
588 surface
->resource
.allocatedMemory
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
589 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
591 if (surface
->flags
& SFLAG_INSYSMEM
)
592 ERR("Surface without memory or PBO has SFLAG_INSYSMEM set.\n");
596 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
598 if (surface
->flags
& SFLAG_DONOTFREE
)
601 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
602 surface
->resource
.allocatedMemory
= NULL
;
603 surface
->resource
.heapMemory
= NULL
;
604 surface_modify_location(surface
, SFLAG_INSYSMEM
, FALSE
);
607 /* Context activation is done by the caller. */
608 static void surface_bind_and_dirtify(struct wined3d_surface
*surface
,
609 struct wined3d_context
*context
, BOOL srgb
)
611 struct wined3d_device
*device
= surface
->resource
.device
;
612 DWORD active_sampler
;
614 /* We don't need a specific texture unit, but after binding the texture
615 * the current unit is dirty. Read the unit back instead of switching to
616 * 0, this avoids messing around with the state manager's GL states. The
617 * current texture unit should always be a valid one.
619 * To be more specific, this is tricky because we can implicitly be
620 * called from sampler() in state.c. This means we can't touch anything
621 * other than whatever happens to be the currently active texture, or we
622 * would risk marking already applied sampler states dirty again. */
623 active_sampler
= device
->rev_tex_unit_map
[context
->active_texture
];
625 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
626 device_invalidate_state(device
, STATE_SAMPLER(active_sampler
));
627 surface_bind(surface
, context
, srgb
);
630 static void surface_force_reload(struct wined3d_surface
*surface
)
632 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
635 static void surface_release_client_storage(struct wined3d_surface
*surface
)
637 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
640 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
641 if (surface
->texture_name
)
643 surface_bind_and_dirtify(surface
, context
, FALSE
);
644 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
645 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
647 if (surface
->texture_name_srgb
)
649 surface_bind_and_dirtify(surface
, context
, TRUE
);
650 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
651 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
653 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
656 context_release(context
);
658 surface_modify_location(surface
, SFLAG_INSRGBTEX
, FALSE
);
659 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
660 surface_force_reload(surface
);
663 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
665 /* TODO: Check against the maximum texture sizes supported by the video card. */
666 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
667 unsigned int pow2Width
, pow2Height
;
669 TRACE("surface %p.\n", surface
);
671 surface
->texture_name
= 0;
672 surface
->texture_target
= GL_TEXTURE_2D
;
674 /* Non-power2 support */
675 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
677 pow2Width
= surface
->resource
.width
;
678 pow2Height
= surface
->resource
.height
;
682 /* Find the nearest pow2 match */
683 pow2Width
= pow2Height
= 1;
684 while (pow2Width
< surface
->resource
.width
)
686 while (pow2Height
< surface
->resource
.height
)
689 surface
->pow2Width
= pow2Width
;
690 surface
->pow2Height
= pow2Height
;
692 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
694 /* TODO: Add support for non power two compressed textures. */
695 if (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
697 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
698 surface
, surface
->resource
.width
, surface
->resource
.height
);
699 return WINED3DERR_NOTAVAILABLE
;
703 if (pow2Width
!= surface
->resource
.width
704 || pow2Height
!= surface
->resource
.height
)
706 surface
->flags
|= SFLAG_NONPOW2
;
709 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
710 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
712 /* One of three options:
713 * 1: Do the same as we do with NPOT and scale the texture, (any
714 * texture ops would require the texture to be scaled which is
716 * 2: Set the texture to the maximum size (bad idea).
717 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
718 * 4: Create the surface, but allow it to be used only for DirectDraw
719 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
720 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
721 * the render target. */
722 if (surface
->resource
.pool
== WINED3DPOOL_DEFAULT
|| surface
->resource
.pool
== WINED3DPOOL_MANAGED
)
724 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
725 return WINED3DERR_NOTAVAILABLE
;
728 /* We should never use this surface in combination with OpenGL! */
729 TRACE("Creating an oversized surface: %ux%u.\n",
730 surface
->pow2Width
, surface
->pow2Height
);
734 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
735 * and EXT_PALETTED_TEXTURE is used in combination with texture
736 * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
737 * EXT_PALETTED_TEXTURE doesn't work in combination with
738 * ARB_TEXTURE_RECTANGLE. */
739 if (surface
->flags
& SFLAG_NONPOW2
&& gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
740 && !(surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
741 && gl_info
->supported
[EXT_PALETTED_TEXTURE
]
742 && wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
))
744 surface
->texture_target
= GL_TEXTURE_RECTANGLE_ARB
;
745 surface
->pow2Width
= surface
->resource
.width
;
746 surface
->pow2Height
= surface
->resource
.height
;
747 surface
->flags
&= ~(SFLAG_NONPOW2
| SFLAG_NORMCOORD
);
751 switch (wined3d_settings
.offscreen_rendering_mode
)
754 surface
->get_drawable_size
= get_drawable_size_fbo
;
758 surface
->get_drawable_size
= get_drawable_size_backbuffer
;
762 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings
.offscreen_rendering_mode
);
763 return WINED3DERR_INVALIDCALL
;
766 surface
->flags
|= SFLAG_INSYSMEM
;
771 static void surface_realize_palette(struct wined3d_surface
*surface
)
773 struct wined3d_palette
*palette
= surface
->palette
;
775 TRACE("surface %p.\n", surface
);
777 if (!palette
) return;
779 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
780 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
782 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
784 /* Make sure the texture is up to date. This call doesn't do
785 * anything if the texture is already up to date. */
786 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
788 /* We want to force a palette refresh, so mark the drawable as not being up to date */
789 if (!surface_is_offscreen(surface
))
790 surface_modify_location(surface
, SFLAG_INDRAWABLE
, FALSE
);
794 if (!(surface
->flags
& SFLAG_INSYSMEM
))
796 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
797 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
799 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
803 if (surface
->flags
& SFLAG_DIBSECTION
)
808 TRACE("Updating the DC's palette.\n");
810 for (i
= 0; i
< 256; ++i
)
812 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
813 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
814 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
815 col
[i
].rgbReserved
= 0;
817 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
820 /* Propagate the changes to the drawable when we have a palette. */
821 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
822 surface_load_location(surface
, surface
->draw_binding
, NULL
);
825 static HRESULT
surface_draw_overlay(struct wined3d_surface
*surface
)
829 /* If there's no destination surface there is nothing to do. */
830 if (!surface
->overlay_dest
)
833 /* Blt calls ModifyLocation on the dest surface, which in turn calls
834 * DrawOverlay to update the overlay. Prevent an endless recursion. */
835 if (surface
->overlay_dest
->flags
& SFLAG_INOVERLAYDRAW
)
838 surface
->overlay_dest
->flags
|= SFLAG_INOVERLAYDRAW
;
839 hr
= wined3d_surface_blt(surface
->overlay_dest
, &surface
->overlay_destrect
, surface
,
840 &surface
->overlay_srcrect
, WINEDDBLT_WAIT
, NULL
, WINED3DTEXF_LINEAR
);
841 surface
->overlay_dest
->flags
&= ~SFLAG_INOVERLAYDRAW
;
846 static void surface_preload(struct wined3d_surface
*surface
)
848 TRACE("surface %p.\n", surface
);
850 surface_internal_preload(surface
, SRGB_ANY
);
853 static void surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
855 struct wined3d_device
*device
= surface
->resource
.device
;
856 const RECT
*pass_rect
= rect
;
858 TRACE("surface %p, rect %s, flags %#x.\n",
859 surface
, wine_dbgstr_rect(rect
), flags
);
861 if (flags
& WINED3DLOCK_DISCARD
)
863 TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n");
864 surface_prepare_system_memory(surface
);
865 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
869 /* surface_load_location() does not check if the rectangle specifies
870 * the full surface. Most callers don't need that, so do it here. */
871 if (rect
&& !rect
->top
&& !rect
->left
872 && rect
->right
== surface
->resource
.width
873 && rect
->bottom
== surface
->resource
.height
)
876 if (!(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
877 && ((surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
878 || surface
== device
->fb
.render_targets
[0])))
879 surface_load_location(surface
, SFLAG_INSYSMEM
, pass_rect
);
882 if (surface
->flags
& SFLAG_PBO
)
884 const struct wined3d_gl_info
*gl_info
;
885 struct wined3d_context
*context
;
887 context
= context_acquire(device
, NULL
);
888 gl_info
= context
->gl_info
;
891 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
892 checkGLcall("glBindBufferARB");
894 /* This shouldn't happen but could occur if some other function
895 * didn't handle the PBO properly. */
896 if (surface
->resource
.allocatedMemory
)
897 ERR("The surface already has PBO memory allocated.\n");
899 surface
->resource
.allocatedMemory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
900 checkGLcall("glMapBufferARB");
902 /* Make sure the PBO isn't set anymore in order not to break non-PBO
904 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
905 checkGLcall("glBindBufferARB");
908 context_release(context
);
911 if (!(flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)))
914 surface_add_dirty_rect(surface
, NULL
);
921 b
.Right
= rect
->right
;
922 b
.Bottom
= rect
->bottom
;
925 surface_add_dirty_rect(surface
, &b
);
930 static void surface_unmap(struct wined3d_surface
*surface
)
932 struct wined3d_device
*device
= surface
->resource
.device
;
935 TRACE("surface %p.\n", surface
);
937 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
939 if (surface
->flags
& SFLAG_PBO
)
941 const struct wined3d_gl_info
*gl_info
;
942 struct wined3d_context
*context
;
944 TRACE("Freeing PBO memory.\n");
946 context
= context_acquire(device
, NULL
);
947 gl_info
= context
->gl_info
;
950 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
951 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
952 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
953 checkGLcall("glUnmapBufferARB");
955 context_release(context
);
957 surface
->resource
.allocatedMemory
= NULL
;
960 TRACE("dirtyfied %u.\n", surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
) ? 0 : 1);
962 if (surface
->flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
))
964 TRACE("Not dirtified, nothing to do.\n");
968 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
969 || (device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
971 if (wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
)
973 static BOOL warned
= FALSE
;
976 ERR("The application tries to write to the render target, but render target locking is disabled.\n");
982 if (!surface
->dirtyRect
.left
&& !surface
->dirtyRect
.top
983 && surface
->dirtyRect
.right
== surface
->resource
.width
984 && surface
->dirtyRect
.bottom
== surface
->resource
.height
)
990 /* TODO: Proper partial rectangle tracking. */
992 surface
->flags
|= SFLAG_INSYSMEM
;
995 surface_load_location(surface
, surface
->draw_binding
, fullsurface
? NULL
: &surface
->dirtyRect
);
997 /* Partial rectangle tracking is not commonly implemented, it is only
998 * done for render targets. INSYSMEM was set before to tell
999 * surface_load_location() where to read the rectangle from.
1000 * Indrawable is set because all modifications from the partial
1001 * sysmem copy are written back to the drawable, thus the surface is
1002 * merged again in the drawable. The sysmem copy is not fully up to
1003 * date because only a subrectangle was read in Map(). */
1006 surface_modify_location(surface
, surface
->draw_binding
, TRUE
);
1007 surface_evict_sysmem(surface
);
1010 surface
->dirtyRect
.left
= surface
->resource
.width
;
1011 surface
->dirtyRect
.top
= surface
->resource
.height
;
1012 surface
->dirtyRect
.right
= 0;
1013 surface
->dirtyRect
.bottom
= 0;
1015 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
1017 FIXME("Depth / stencil buffer locking is not implemented.\n");
1021 /* Overlays have to be redrawn manually after changes with the GL implementation */
1022 if (surface
->overlay_dest
)
1023 surface
->surface_ops
->surface_draw_overlay(surface
);
1026 static HRESULT
surface_getdc(struct wined3d_surface
*surface
)
1028 WINED3DLOCKED_RECT lock
;
1031 TRACE("surface %p.\n", surface
);
1033 /* Create a DIB section if there isn't a dc yet. */
1036 if (surface
->flags
& SFLAG_CLIENT
)
1038 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
1039 surface_release_client_storage(surface
);
1041 hr
= surface_create_dib_section(surface
);
1043 return WINED3DERR_INVALIDCALL
;
1045 /* Use the DIB section from now on if we are not using a PBO. */
1046 if (!(surface
->flags
& SFLAG_PBO
))
1047 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1050 /* Map the surface. */
1051 hr
= wined3d_surface_map(surface
, &lock
, NULL
, 0);
1053 ERR("Map failed, hr %#x.\n", hr
);
1055 /* Sync the DIB with the PBO. This can't be done earlier because Map()
1056 * activates the allocatedMemory. */
1057 if (surface
->flags
& SFLAG_PBO
)
1058 memcpy(surface
->dib
.bitmap_data
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
1063 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
1065 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
1067 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
1072 static void wined3d_surface_depth_blt_fbo(struct wined3d_device
*device
, struct wined3d_surface
*src_surface
,
1073 const RECT
*src_rect
, struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
)
1075 const struct wined3d_gl_info
*gl_info
;
1076 struct wined3d_context
*context
;
1077 DWORD src_mask
, dst_mask
;
1080 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
1081 device
, src_surface
, wine_dbgstr_rect(src_rect
),
1082 dst_surface
, wine_dbgstr_rect(dst_rect
));
1084 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1085 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1087 if (src_mask
!= dst_mask
)
1089 ERR("Incompatible formats %s and %s.\n",
1090 debug_d3dformat(src_surface
->resource
.format
->id
),
1091 debug_d3dformat(dst_surface
->resource
.format
->id
));
1097 ERR("Not a depth / stencil format: %s.\n",
1098 debug_d3dformat(src_surface
->resource
.format
->id
));
1103 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
1104 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
1105 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
1106 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
1108 /* Make sure the locations are up-to-date. Loading the destination
1109 * surface isn't required if the entire surface is overwritten. */
1110 surface_load_location(src_surface
, SFLAG_INTEXTURE
, NULL
);
1111 if (!surface_is_full_rect(dst_surface
, dst_rect
))
1112 surface_load_location(dst_surface
, SFLAG_INTEXTURE
, NULL
);
1114 context
= context_acquire(device
, NULL
);
1115 if (!context
->valid
)
1117 context_release(context
);
1118 WARN("Invalid context, skipping blit.\n");
1122 gl_info
= context
->gl_info
;
1126 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, SFLAG_INTEXTURE
);
1127 glReadBuffer(GL_NONE
);
1128 checkGLcall("glReadBuffer()");
1129 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1131 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, SFLAG_INTEXTURE
);
1132 context_set_draw_buffer(context
, GL_NONE
);
1133 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1135 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
1137 glDepthMask(GL_TRUE
);
1138 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
1140 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
1142 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
1144 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
1145 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE
));
1148 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
1151 glDisable(GL_SCISSOR_TEST
);
1152 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
1154 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
1155 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
1156 checkGLcall("glBlitFramebuffer()");
1160 if (wined3d_settings
.strict_draw_ordering
)
1161 wglFlush(); /* Flush to ensure ordering across contexts. */
1163 context_release(context
);
1166 /* Blit between surface locations. Onscreen on different swapchains is not supported.
1167 * Depth / stencil is not supported. */
1168 static void surface_blt_fbo(struct wined3d_device
*device
, const WINED3DTEXTUREFILTERTYPE filter
,
1169 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
1170 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
1172 const struct wined3d_gl_info
*gl_info
;
1173 struct wined3d_context
*context
;
1174 RECT src_rect
, dst_rect
;
1178 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
1179 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
1180 src_surface
, debug_surflocation(src_location
), wine_dbgstr_rect(src_rect_in
));
1181 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
1182 dst_surface
, debug_surflocation(dst_location
), wine_dbgstr_rect(dst_rect_in
));
1184 src_rect
= *src_rect_in
;
1185 dst_rect
= *dst_rect_in
;
1189 case WINED3DTEXF_LINEAR
:
1190 gl_filter
= GL_LINEAR
;
1194 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
1195 case WINED3DTEXF_NONE
:
1196 case WINED3DTEXF_POINT
:
1197 gl_filter
= GL_NEAREST
;
1201 /* Resolve the source surface first if needed. */
1202 if (src_location
== SFLAG_INRB_MULTISAMPLE
1203 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
1204 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
1205 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
1206 src_location
= SFLAG_INRB_RESOLVED
;
1208 /* Make sure the locations are up-to-date. Loading the destination
1209 * surface isn't required if the entire surface is overwritten. (And is
1210 * in fact harmful if we're being called by surface_load_location() with
1211 * the purpose of loading the destination surface.) */
1212 surface_load_location(src_surface
, src_location
, NULL
);
1213 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
1214 surface_load_location(dst_surface
, dst_location
, NULL
);
1216 if (src_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, src_surface
);
1217 else if (dst_location
== SFLAG_INDRAWABLE
) context
= context_acquire(device
, dst_surface
);
1218 else context
= context_acquire(device
, NULL
);
1220 if (!context
->valid
)
1222 context_release(context
);
1223 WARN("Invalid context, skipping blit.\n");
1227 gl_info
= context
->gl_info
;
1229 if (src_location
== SFLAG_INDRAWABLE
)
1231 TRACE("Source surface %p is onscreen.\n", src_surface
);
1232 buffer
= surface_get_gl_buffer(src_surface
);
1233 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
1237 TRACE("Source surface %p is offscreen.\n", src_surface
);
1238 buffer
= GL_COLOR_ATTACHMENT0
;
1242 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
1243 glReadBuffer(buffer
);
1244 checkGLcall("glReadBuffer()");
1245 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
1248 if (dst_location
== SFLAG_INDRAWABLE
)
1250 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
1251 buffer
= surface_get_gl_buffer(dst_surface
);
1252 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
1256 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
1257 buffer
= GL_COLOR_ATTACHMENT0
;
1261 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
1262 context_set_draw_buffer(context
, buffer
);
1263 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
1264 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
1266 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
1267 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
1268 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1
));
1269 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2
));
1270 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3
));
1272 glDisable(GL_SCISSOR_TEST
);
1273 context_invalidate_state(context
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
1275 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
1276 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
1277 checkGLcall("glBlitFramebuffer()");
1281 if (wined3d_settings
.strict_draw_ordering
1282 || (dst_location
== SFLAG_INDRAWABLE
1283 && dst_surface
->container
.u
.swapchain
->front_buffer
== dst_surface
))
1286 context_release(context
);
1289 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
1290 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
1291 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
1293 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
1296 /* Source and/or destination need to be on the GL side */
1297 if (src_pool
== WINED3DPOOL_SYSTEMMEM
|| dst_pool
== WINED3DPOOL_SYSTEMMEM
)
1302 case WINED3D_BLIT_OP_COLOR_BLIT
:
1303 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
1305 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1309 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1310 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1312 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1320 if (!(src_format
->id
== dst_format
->id
1321 || (is_identity_fixup(src_format
->color_fixup
)
1322 && is_identity_fixup(dst_format
->color_fixup
))))
1328 /* This function checks if the primary render target uses the 8bit paletted format. */
1329 static BOOL
primary_render_target_is_p8(const struct wined3d_device
*device
)
1331 if (device
->fb
.render_targets
&& device
->fb
.render_targets
[0])
1333 const struct wined3d_surface
*render_target
= device
->fb
.render_targets
[0];
1334 if ((render_target
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1335 && (render_target
->resource
.format
->id
== WINED3DFMT_P8_UINT
))
1341 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1342 DWORD color
, WINED3DCOLORVALUE
*float_color
)
1344 const struct wined3d_format
*format
= surface
->resource
.format
;
1345 const struct wined3d_device
*device
= surface
->resource
.device
;
1349 case WINED3DFMT_P8_UINT
:
1350 if (surface
->palette
)
1352 float_color
->r
= surface
->palette
->palents
[color
].peRed
/ 255.0f
;
1353 float_color
->g
= surface
->palette
->palents
[color
].peGreen
/ 255.0f
;
1354 float_color
->b
= surface
->palette
->palents
[color
].peBlue
/ 255.0f
;
1358 float_color
->r
= 0.0f
;
1359 float_color
->g
= 0.0f
;
1360 float_color
->b
= 0.0f
;
1362 float_color
->a
= primary_render_target_is_p8(device
) ? color
/ 255.0f
: 1.0f
;
1365 case WINED3DFMT_B5G6R5_UNORM
:
1366 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1367 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1368 float_color
->b
= (color
& 0x1f) / 31.0f
;
1369 float_color
->a
= 1.0f
;
1372 case WINED3DFMT_B8G8R8_UNORM
:
1373 case WINED3DFMT_B8G8R8X8_UNORM
:
1374 float_color
->r
= D3DCOLOR_R(color
);
1375 float_color
->g
= D3DCOLOR_G(color
);
1376 float_color
->b
= D3DCOLOR_B(color
);
1377 float_color
->a
= 1.0f
;
1380 case WINED3DFMT_B8G8R8A8_UNORM
:
1381 float_color
->r
= D3DCOLOR_R(color
);
1382 float_color
->g
= D3DCOLOR_G(color
);
1383 float_color
->b
= D3DCOLOR_B(color
);
1384 float_color
->a
= D3DCOLOR_A(color
);
1388 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1395 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1397 const struct wined3d_format
*format
= surface
->resource
.format
;
1401 case WINED3DFMT_S1_UINT_D15_UNORM
:
1402 *float_depth
= depth
/ (float)0x00007fff;
1405 case WINED3DFMT_D16_UNORM
:
1406 *float_depth
= depth
/ (float)0x0000ffff;
1409 case WINED3DFMT_D24_UNORM_S8_UINT
:
1410 case WINED3DFMT_X8D24_UNORM
:
1411 *float_depth
= depth
/ (float)0x00ffffff;
1414 case WINED3DFMT_D32_UNORM
:
1415 *float_depth
= depth
/ (float)0xffffffff;
1419 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1426 /* Do not call while under the GL lock. */
1427 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1429 const struct wined3d_resource
*resource
= &surface
->resource
;
1430 struct wined3d_device
*device
= resource
->device
;
1431 const struct blit_shader
*blitter
;
1433 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1434 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1437 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1438 return WINED3DERR_INVALIDCALL
;
1441 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1444 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, const RECT
*src_rect
,
1445 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
)
1447 struct wined3d_device
*device
= src_surface
->resource
.device
;
1449 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1450 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1451 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1452 return WINED3DERR_INVALIDCALL
;
1454 wined3d_surface_depth_blt_fbo(device
, src_surface
, src_rect
, dst_surface
, dst_rect
);
1456 surface_modify_ds_location(dst_surface
, SFLAG_DS_OFFSCREEN
,
1457 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1458 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
1463 /* Do not call while under the GL lock. */
1464 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
1465 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
1466 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
)
1468 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
1469 struct wined3d_device
*device
= dst_surface
->resource
.device
;
1470 DWORD src_ds_flags
, dst_ds_flags
;
1471 RECT src_rect
, dst_rect
;
1473 static const DWORD simple_blit
= WINEDDBLT_ASYNC
1474 | WINEDDBLT_COLORFILL
1476 | WINEDDBLT_DEPTHFILL
1477 | WINEDDBLT_DONOTWAIT
;
1479 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
1480 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
1481 flags
, fx
, debug_d3dtexturefiltertype(filter
));
1482 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
1486 TRACE("dwSize %#x.\n", fx
->dwSize
);
1487 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
1488 TRACE("dwROP %#x.\n", fx
->dwROP
);
1489 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
1490 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
1491 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
1492 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
1493 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
1494 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
1495 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
1496 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
1497 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
1498 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
1499 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
1500 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
1501 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
1502 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
1503 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
1504 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
1505 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
1506 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
1507 TRACE("ddckDestColorkey {%#x, %#x}.\n",
1508 fx
->ddckDestColorkey
.dwColorSpaceLowValue
,
1509 fx
->ddckDestColorkey
.dwColorSpaceHighValue
);
1510 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
1511 fx
->ddckSrcColorkey
.dwColorSpaceLowValue
,
1512 fx
->ddckSrcColorkey
.dwColorSpaceHighValue
);
1515 if ((dst_surface
->flags
& SFLAG_LOCKED
) || (src_surface
&& (src_surface
->flags
& SFLAG_LOCKED
)))
1517 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
1518 return WINEDDERR_SURFACEBUSY
;
1521 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
1523 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
1524 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
1525 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
1526 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
1527 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
1529 /* The destination rect can be out of bounds on the condition
1530 * that a clipper is set for the surface. */
1531 if (dst_surface
->clipper
)
1532 FIXME("Blit clipping not implemented.\n");
1534 WARN("The application gave us a bad destination rectangle without a clipper set.\n");
1535 return WINEDDERR_INVALIDRECT
;
1540 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
1542 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
1543 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
1544 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
1545 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
1546 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
1548 WARN("Application gave us bad source rectangle for Blt.\n");
1549 return WINEDDERR_INVALIDRECT
;
1554 memset(&src_rect
, 0, sizeof(src_rect
));
1557 if (!fx
|| !(fx
->dwDDFX
))
1558 flags
&= ~WINEDDBLT_DDFX
;
1560 if (flags
& WINEDDBLT_WAIT
)
1561 flags
&= ~WINEDDBLT_WAIT
;
1563 if (flags
& WINEDDBLT_ASYNC
)
1565 static unsigned int once
;
1568 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
1569 flags
&= ~WINEDDBLT_ASYNC
;
1572 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
1573 if (flags
& WINEDDBLT_DONOTWAIT
)
1575 static unsigned int once
;
1578 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
1579 flags
&= ~WINEDDBLT_DONOTWAIT
;
1582 if (!device
->d3d_initialized
)
1584 WARN("D3D not initialized, using fallback.\n");
1588 /* We want to avoid invalidating the sysmem location for converted
1589 * surfaces, since otherwise we'd have to convert the data back when
1591 if (dst_surface
->flags
& SFLAG_CONVERTED
)
1593 WARN("Converted surface, using CPU blit.\n");
1594 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
1597 if (flags
& ~simple_blit
)
1599 WARN("Using fallback for complex blit (%#x).\n", flags
);
1603 if (src_surface
&& src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1604 src_swapchain
= src_surface
->container
.u
.swapchain
;
1606 src_swapchain
= NULL
;
1608 if (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
1609 dst_swapchain
= dst_surface
->container
.u
.swapchain
;
1611 dst_swapchain
= NULL
;
1613 /* This isn't strictly needed. FBO blits for example could deal with
1614 * cross-swapchain blits by first downloading the source to a texture
1615 * before switching to the destination context. We just have this here to
1616 * not have to deal with the issue, since cross-swapchain blits should be
1618 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
1620 FIXME("Using fallback for cross-swapchain blit.\n");
1624 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1626 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
1630 if (src_ds_flags
|| dst_ds_flags
)
1632 if (flags
& WINEDDBLT_DEPTHFILL
)
1636 TRACE("Depth fill.\n");
1638 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
1639 return WINED3DERR_INVALIDCALL
;
1641 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
1646 /* Accessing depth / stencil surfaces is supposed to fail while in
1647 * a scene, except for fills, which seem to work. */
1648 if (device
->inScene
)
1650 WARN("Rejecting depth / stencil access while in scene.\n");
1651 return WINED3DERR_INVALIDCALL
;
1654 if (src_ds_flags
!= dst_ds_flags
)
1656 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
1657 return WINED3DERR_INVALIDCALL
;
1660 if (src_rect
.top
|| src_rect
.left
1661 || src_rect
.bottom
!= src_surface
->resource
.height
1662 || src_rect
.right
!= src_surface
->resource
.width
)
1664 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
1665 wine_dbgstr_rect(&src_rect
));
1666 return WINED3DERR_INVALIDCALL
;
1669 if (dst_rect
.top
|| dst_rect
.left
1670 || dst_rect
.bottom
!= dst_surface
->resource
.height
1671 || dst_rect
.right
!= dst_surface
->resource
.width
)
1673 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
1674 wine_dbgstr_rect(&src_rect
));
1675 return WINED3DERR_INVALIDCALL
;
1678 if (src_surface
->resource
.height
!= dst_surface
->resource
.height
1679 || src_surface
->resource
.width
!= dst_surface
->resource
.width
)
1681 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
1682 return WINED3DERR_INVALIDCALL
;
1685 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
1691 if (flags
& WINEDDBLT_COLORFILL
)
1693 WINED3DCOLORVALUE color
;
1695 TRACE("Color fill.\n");
1697 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
1700 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
1705 TRACE("Color blit.\n");
1707 /* Use present for back -> front blits. The idea behind this is
1708 * that present is potentially faster than a blit, in particular
1709 * when FBO blits aren't available. Some ddraw applications like
1710 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
1711 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
1712 * applications can't blit directly to the frontbuffer. */
1713 if (dst_swapchain
&& dst_swapchain
->back_buffers
1714 && dst_surface
== dst_swapchain
->front_buffer
1715 && src_surface
== dst_swapchain
->back_buffers
[0])
1717 WINED3DSWAPEFFECT swap_effect
= dst_swapchain
->presentParms
.SwapEffect
;
1719 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
1721 /* Set the swap effect to COPY, we don't want the backbuffer
1722 * to become undefined. */
1723 dst_swapchain
->presentParms
.SwapEffect
= WINED3DSWAPEFFECT_COPY
;
1724 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
1725 dst_swapchain
->presentParms
.SwapEffect
= swap_effect
;
1730 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1731 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1732 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1734 TRACE("Using FBO blit.\n");
1736 surface_blt_fbo(device
, filter
,
1737 src_surface
, src_surface
->draw_binding
, &src_rect
,
1738 dst_surface
, dst_surface
->draw_binding
, &dst_rect
);
1739 surface_modify_location(dst_surface
, dst_surface
->draw_binding
, TRUE
);
1743 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
1744 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1745 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1747 TRACE("Using arbfp blit.\n");
1749 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
1757 /* Special cases for render targets. */
1758 if ((dst_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
1759 || (src_surface
&& (src_surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)))
1761 if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(dst_surface
, &dst_rect
,
1762 src_surface
, &src_rect
, flags
, fx
, filter
)))
1768 /* For the rest call the X11 surface implementation. For render targets
1769 * this should be implemented OpenGL accelerated in BltOverride, other
1770 * blits are rather rare. */
1771 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
1774 /* Do not call while under the GL lock. */
1775 HRESULT CDECL
wined3d_surface_bltfast(struct wined3d_surface
*dst_surface
, DWORD dst_x
, DWORD dst_y
,
1776 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD trans
)
1778 RECT src_rect
, dst_rect
;
1781 TRACE("dst_surface %p, dst_x %u, dst_y %u, src_surface %p, src_rect_in %s, trans %#x.\n",
1782 dst_surface
, dst_x
, dst_y
, src_surface
, wine_dbgstr_rect(src_rect_in
), trans
);
1784 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
1786 dst_rect
.left
= dst_x
;
1787 dst_rect
.top
= dst_y
;
1788 dst_rect
.right
= dst_x
+ src_rect
.right
- src_rect
.left
;
1789 dst_rect
.bottom
= dst_y
+ src_rect
.bottom
- src_rect
.top
;
1791 if (trans
& WINEDDBLTFAST_SRCCOLORKEY
)
1792 flags
|= WINEDDBLT_KEYSRC
;
1793 if (trans
& WINEDDBLTFAST_DESTCOLORKEY
)
1794 flags
|= WINEDDBLT_KEYDEST
;
1795 if (trans
& WINEDDBLTFAST_WAIT
)
1796 flags
|= WINEDDBLT_WAIT
;
1797 if (trans
& WINEDDBLTFAST_DONOTWAIT
)
1798 flags
|= WINEDDBLT_DONOTWAIT
;
1800 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, NULL
, WINED3DTEXF_POINT
);
1803 /* Context activation is done by the caller. */
1804 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1806 if (!surface
->resource
.heapMemory
)
1808 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
1809 surface
->resource
.allocatedMemory
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
1810 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
1814 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
1815 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
1816 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0,
1817 surface
->resource
.size
, surface
->resource
.allocatedMemory
));
1818 checkGLcall("glGetBufferSubDataARB");
1819 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1820 checkGLcall("glDeleteBuffersARB");
1824 surface
->flags
&= ~SFLAG_PBO
;
1827 /* Do not call while under the GL lock. */
1828 static void surface_unload(struct wined3d_resource
*resource
)
1830 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1831 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1832 struct wined3d_device
*device
= resource
->device
;
1833 const struct wined3d_gl_info
*gl_info
;
1834 struct wined3d_context
*context
;
1836 TRACE("surface %p.\n", surface
);
1838 if (resource
->pool
== WINED3DPOOL_DEFAULT
)
1840 /* Default pool resources are supposed to be destroyed before Reset is called.
1841 * Implicit resources stay however. So this means we have an implicit render target
1842 * or depth stencil. The content may be destroyed, but we still have to tear down
1843 * opengl resources, so we cannot leave early.
1845 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1846 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1847 * or the depth stencil into an FBO the texture or render buffer will be removed
1848 * and all flags get lost
1850 surface_init_sysmem(surface
);
1854 /* Load the surface into system memory */
1855 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
1856 surface_modify_location(surface
, surface
->draw_binding
, FALSE
);
1858 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
1859 surface_modify_location(surface
, SFLAG_INSRGBTEX
, FALSE
);
1860 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1862 context
= context_acquire(device
, NULL
);
1863 gl_info
= context
->gl_info
;
1865 /* Destroy PBOs, but load them into real sysmem before */
1866 if (surface
->flags
& SFLAG_PBO
)
1867 surface_remove_pbo(surface
, gl_info
);
1869 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1870 * all application-created targets the application has to release the surface
1871 * before calling _Reset
1873 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1876 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1878 list_remove(&entry
->entry
);
1879 HeapFree(GetProcessHeap(), 0, entry
);
1881 list_init(&surface
->renderbuffers
);
1882 surface
->current_renderbuffer
= NULL
;
1886 /* If we're in a texture, the texture name belongs to the texture.
1887 * Otherwise, destroy it. */
1888 if (surface
->container
.type
!= WINED3D_CONTAINER_TEXTURE
)
1890 glDeleteTextures(1, &surface
->texture_name
);
1891 surface
->texture_name
= 0;
1892 glDeleteTextures(1, &surface
->texture_name_srgb
);
1893 surface
->texture_name_srgb
= 0;
1895 if (surface
->rb_multisample
)
1897 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1898 surface
->rb_multisample
= 0;
1900 if (surface
->rb_resolved
)
1902 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1903 surface
->rb_resolved
= 0;
1908 context_release(context
);
1910 resource_unload(resource
);
1913 static const struct wined3d_resource_ops surface_resource_ops
=
1918 static const struct wined3d_surface_ops surface_ops
=
1920 surface_private_setup
,
1922 surface_realize_palette
,
1923 surface_draw_overlay
,
1930 /*****************************************************************************
1931 * Initializes the GDI surface, aka creates the DIB section we render to
1932 * The DIB section creation is done by calling GetDC, which will create the
1933 * section and releasing the dc to allow the app to use it. The dib section
1934 * will stay until the surface is released
1936 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1937 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1938 * avoid confusion in the shared surface code.
1941 * WINED3D_OK on success
1942 * The return values of called methods on failure
1944 *****************************************************************************/
1945 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1949 TRACE("surface %p.\n", surface
);
1951 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1953 ERR("Overlays not yet supported by GDI surfaces.\n");
1954 return WINED3DERR_INVALIDCALL
;
1957 /* Sysmem textures have memory already allocated - release it,
1958 * this avoids an unnecessary memcpy. */
1959 hr
= surface_create_dib_section(surface
);
1962 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
1963 surface
->resource
.heapMemory
= NULL
;
1964 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
1967 /* We don't mind the nonpow2 stuff in GDI. */
1968 surface
->pow2Width
= surface
->resource
.width
;
1969 surface
->pow2Height
= surface
->resource
.height
;
1974 static void surface_gdi_cleanup(struct wined3d_surface
*surface
)
1976 TRACE("surface %p.\n", surface
);
1978 if (surface
->flags
& SFLAG_DIBSECTION
)
1980 /* Release the DC. */
1981 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
1982 DeleteDC(surface
->hDC
);
1983 /* Release the DIB section. */
1984 DeleteObject(surface
->dib
.DIBsection
);
1985 surface
->dib
.bitmap_data
= NULL
;
1986 surface
->resource
.allocatedMemory
= NULL
;
1989 if (surface
->flags
& SFLAG_USERPTR
)
1990 wined3d_surface_set_mem(surface
, NULL
);
1991 if (surface
->overlay_dest
)
1992 list_remove(&surface
->overlay_entry
);
1994 HeapFree(GetProcessHeap(), 0, surface
->palette9
);
1996 resource_cleanup(&surface
->resource
);
1999 static void gdi_surface_realize_palette(struct wined3d_surface
*surface
)
2001 struct wined3d_palette
*palette
= surface
->palette
;
2003 TRACE("surface %p.\n", surface
);
2005 if (!palette
) return;
2007 if (surface
->flags
& SFLAG_DIBSECTION
)
2012 TRACE("Updating the DC's palette.\n");
2014 for (i
= 0; i
< 256; ++i
)
2016 col
[i
].rgbRed
= palette
->palents
[i
].peRed
;
2017 col
[i
].rgbGreen
= palette
->palents
[i
].peGreen
;
2018 col
[i
].rgbBlue
= palette
->palents
[i
].peBlue
;
2019 col
[i
].rgbReserved
= 0;
2021 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
2024 /* Update the image because of the palette change. Some games like e.g.
2025 * Red Alert call SetEntries a lot to implement fading. */
2026 /* Tell the swapchain to update the screen. */
2027 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
2029 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2030 if (surface
== swapchain
->front_buffer
)
2032 x11_copy_to_screen(swapchain
, NULL
);
2037 static HRESULT
gdi_surface_draw_overlay(struct wined3d_surface
*surface
)
2039 FIXME("GDI surfaces can't draw overlays yet.\n");
2043 static void gdi_surface_preload(struct wined3d_surface
*surface
)
2045 TRACE("surface %p.\n", surface
);
2047 ERR("Preloading GDI surfaces is not supported.\n");
2050 static void gdi_surface_map(struct wined3d_surface
*surface
, const RECT
*rect
, DWORD flags
)
2052 TRACE("surface %p, rect %s, flags %#x.\n",
2053 surface
, wine_dbgstr_rect(rect
), flags
);
2055 if (!surface
->resource
.allocatedMemory
)
2057 /* This happens on gdi surfaces if the application set a user pointer
2058 * and resets it. Recreate the DIB section. */
2059 surface_create_dib_section(surface
);
2060 surface
->resource
.allocatedMemory
= surface
->dib
.bitmap_data
;
2064 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
2066 TRACE("surface %p.\n", surface
);
2068 /* Tell the swapchain to update the screen. */
2069 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
2071 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2072 if (surface
== swapchain
->front_buffer
)
2074 x11_copy_to_screen(swapchain
, &surface
->lockedRect
);
2078 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
2081 static HRESULT
gdi_surface_getdc(struct wined3d_surface
*surface
)
2083 WINED3DLOCKED_RECT lock
;
2086 TRACE("surface %p.\n", surface
);
2088 /* Should have a DIB section already. */
2089 if (!(surface
->flags
& SFLAG_DIBSECTION
))
2091 WARN("DC not supported on this surface\n");
2092 return WINED3DERR_INVALIDCALL
;
2095 /* Map the surface. */
2096 hr
= wined3d_surface_map(surface
, &lock
, NULL
, 0);
2098 ERR("Map failed, hr %#x.\n", hr
);
2103 static const struct wined3d_surface_ops gdi_surface_ops
=
2105 gdi_surface_private_setup
,
2106 surface_gdi_cleanup
,
2107 gdi_surface_realize_palette
,
2108 gdi_surface_draw_overlay
,
2109 gdi_surface_preload
,
2115 void surface_set_texture_name(struct wined3d_surface
*surface
, GLuint new_name
, BOOL srgb
)
2120 TRACE("surface %p, new_name %u, srgb %#x.\n", surface
, new_name
, srgb
);
2124 name
= &surface
->texture_name_srgb
;
2125 flag
= SFLAG_INSRGBTEX
;
2129 name
= &surface
->texture_name
;
2130 flag
= SFLAG_INTEXTURE
;
2133 if (!*name
&& new_name
)
2135 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
2136 * surface has no texture name yet. See if we can get rid of this. */
2137 if (surface
->flags
& flag
)
2138 ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag
));
2139 surface_modify_location(surface
, flag
, FALSE
);
2143 surface_force_reload(surface
);
2146 void surface_set_texture_target(struct wined3d_surface
*surface
, GLenum target
)
2148 TRACE("surface %p, target %#x.\n", surface
, target
);
2150 if (surface
->texture_target
!= target
)
2152 if (target
== GL_TEXTURE_RECTANGLE_ARB
)
2154 surface
->flags
&= ~SFLAG_NORMCOORD
;
2156 else if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
2158 surface
->flags
|= SFLAG_NORMCOORD
;
2161 surface
->texture_target
= target
;
2162 surface_force_reload(surface
);
2165 /* Context activation is done by the caller. */
2166 void surface_bind(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
2168 TRACE("surface %p, context %p, srgb %#x.\n", surface
, context
, srgb
);
2170 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
2172 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
2174 TRACE("Passing to container (%p).\n", texture
);
2175 texture
->texture_ops
->texture_bind(texture
, context
, srgb
);
2179 if (surface
->texture_level
)
2181 ERR("Standalone surface %p is non-zero texture level %u.\n",
2182 surface
, surface
->texture_level
);
2186 ERR("Trying to bind standalone surface %p as sRGB.\n", surface
);
2190 if (!surface
->texture_name
)
2192 glGenTextures(1, &surface
->texture_name
);
2193 checkGLcall("glGenTextures");
2195 TRACE("Surface %p given name %u.\n", surface
, surface
->texture_name
);
2197 context_bind_texture(context
, surface
->texture_target
, surface
->texture_name
);
2198 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2199 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2200 glTexParameteri(surface
->texture_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
2201 glTexParameteri(surface
->texture_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2202 glTexParameteri(surface
->texture_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2203 checkGLcall("glTexParameteri");
2207 context_bind_texture(context
, surface
->texture_target
, surface
->texture_name
);
2214 /* This call just downloads data, the caller is responsible for binding the
2215 * correct texture. */
2216 /* Context activation is done by the caller. */
2217 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
2219 const struct wined3d_format
*format
= surface
->resource
.format
;
2221 /* Only support read back of converted P8 surfaces. */
2222 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
2224 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
2230 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
2232 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2233 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
,
2234 surface
->resource
.allocatedMemory
);
2236 if (surface
->flags
& SFLAG_PBO
)
2238 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
2239 checkGLcall("glBindBufferARB");
2240 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
2241 checkGLcall("glGetCompressedTexImageARB");
2242 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
2243 checkGLcall("glBindBufferARB");
2247 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
2248 surface
->texture_level
, surface
->resource
.allocatedMemory
));
2249 checkGLcall("glGetCompressedTexImageARB");
2257 GLenum gl_format
= format
->glFormat
;
2258 GLenum gl_type
= format
->glType
;
2262 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2263 if (format
->id
== WINED3DFMT_P8_UINT
&& primary_render_target_is_p8(surface
->resource
.device
))
2265 gl_format
= GL_ALPHA
;
2266 gl_type
= GL_UNSIGNED_BYTE
;
2269 if (surface
->flags
& SFLAG_NONPOW2
)
2271 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
2272 src_pitch
= format
->byte_count
* surface
->pow2Width
;
2273 dst_pitch
= wined3d_surface_get_pitch(surface
);
2274 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
2275 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
2279 mem
= surface
->resource
.allocatedMemory
;
2282 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2283 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
2285 if (surface
->flags
& SFLAG_PBO
)
2287 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
2288 checkGLcall("glBindBufferARB");
2290 glGetTexImage(surface
->texture_target
, surface
->texture_level
, gl_format
, gl_type
, NULL
);
2291 checkGLcall("glGetTexImage");
2293 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
2294 checkGLcall("glBindBufferARB");
2298 glGetTexImage(surface
->texture_target
, surface
->texture_level
, gl_format
, gl_type
, mem
);
2299 checkGLcall("glGetTexImage");
2303 if (surface
->flags
& SFLAG_NONPOW2
)
2305 const BYTE
*src_data
;
2309 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2310 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2311 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2313 * We're doing this...
2315 * instead of boxing the texture :
2316 * |<-texture width ->| -->pow2width| /\
2317 * |111111111111111111| | |
2318 * |222 Texture 222222| boxed empty | texture height
2319 * |3333 Data 33333333| | |
2320 * |444444444444444444| | \/
2321 * ----------------------------------- |
2322 * | boxed empty | boxed empty | pow2height
2324 * -----------------------------------
2327 * we're repacking the data to the expected texture width
2329 * |<-texture width ->| -->pow2width| /\
2330 * |111111111111111111222222222222222| |
2331 * |222333333333333333333444444444444| texture height
2335 * | empty | pow2height
2337 * -----------------------------------
2341 * |<-texture width ->| /\
2342 * |111111111111111111|
2343 * |222222222222222222|texture height
2344 * |333333333333333333|
2345 * |444444444444444444| \/
2346 * --------------------
2348 * this also means that any references to allocatedMemory should work with the data as if were a
2349 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2351 * internally the texture is still stored in a boxed format so any references to textureName will
2352 * get a boxed texture with width pow2width and not a texture of width resource.width.
2354 * Performance should not be an issue, because applications normally do not lock the surfaces when
2355 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2356 * and doesn't have to be re-read. */
2358 dst_data
= surface
->resource
.allocatedMemory
;
2359 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
2360 for (y
= 1; y
< surface
->resource
.height
; ++y
)
2362 /* skip the first row */
2363 src_data
+= src_pitch
;
2364 dst_data
+= dst_pitch
;
2365 memcpy(dst_data
, src_data
, dst_pitch
);
2368 HeapFree(GetProcessHeap(), 0, mem
);
2372 /* Surface has now been downloaded */
2373 surface
->flags
|= SFLAG_INSYSMEM
;
2376 /* This call just uploads data, the caller is responsible for binding the
2377 * correct texture. */
2378 /* Context activation is done by the caller. */
2379 void surface_upload_data(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2380 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_w
, const POINT
*dst_point
,
2381 BOOL srgb
, const struct wined3d_bo_address
*data
)
2383 UINT update_w
= src_rect
->right
- src_rect
->left
;
2384 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
2386 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_w %u, dst_point %p, srgb %#x, data {%#x:%p}.\n",
2387 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_w
,
2388 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
2390 if (format
->heightscale
!= 1.0f
&& format
->heightscale
!= 0.0f
)
2391 update_h
*= format
->heightscale
;
2395 if (data
->buffer_object
)
2397 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
2398 checkGLcall("glBindBufferARB");
2401 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
2403 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1);
2404 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
2405 UINT src_pitch
= wined3d_format_calculate_size(format
, 1, src_w
, 1);
2406 const BYTE
*addr
= data
->addr
;
2409 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
2410 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
2413 internal
= format
->glGammaInternal
;
2414 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2415 internal
= format
->rtInternal
;
2417 internal
= format
->glInternal
;
2419 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2420 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
2421 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
2423 if (row_length
== src_pitch
)
2425 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
2426 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
2432 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2433 * can't use the unpack row length like below. */
2434 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
2436 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
2437 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
2438 y
+= format
->block_height
;
2442 checkGLcall("glCompressedTexSubImage2DARB");
2446 const BYTE
*addr
= data
->addr
;
2448 addr
+= src_rect
->top
* src_w
* format
->byte_count
;
2449 addr
+= src_rect
->left
* format
->byte_count
;
2451 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2452 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
2453 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
2455 glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_w
);
2456 glTexSubImage2D(surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
2457 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
2458 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
2459 checkGLcall("glTexSubImage2D");
2462 if (data
->buffer_object
)
2464 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
2465 checkGLcall("glBindBufferARB");
2470 if (wined3d_settings
.strict_draw_ordering
)
2473 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
2475 struct wined3d_device
*device
= surface
->resource
.device
;
2478 for (i
= 0; i
< device
->context_count
; ++i
)
2480 context_surface_update(device
->contexts
[i
], surface
);
2485 /* This call just allocates the texture, the caller is responsible for binding
2486 * the correct texture. */
2487 /* Context activation is done by the caller. */
2488 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
2489 const struct wined3d_format
*format
, BOOL srgb
)
2491 BOOL enable_client_storage
= FALSE
;
2492 GLsizei width
= surface
->pow2Width
;
2493 GLsizei height
= surface
->pow2Height
;
2494 const BYTE
*mem
= NULL
;
2499 internal
= format
->glGammaInternal
;
2501 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
&& surface_is_offscreen(surface
))
2503 internal
= format
->rtInternal
;
2507 internal
= format
->glInternal
;
2510 if (format
->heightscale
!= 1.0f
&& format
->heightscale
!= 0.0f
) height
*= format
->heightscale
;
2512 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",
2513 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
2514 internal
, width
, height
, format
->glFormat
, format
->glType
);
2518 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
2520 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
2521 || !surface
->resource
.allocatedMemory
)
2523 /* In some cases we want to disable client storage.
2524 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2525 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2526 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2527 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2529 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2530 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2531 surface
->flags
&= ~SFLAG_CLIENT
;
2532 enable_client_storage
= TRUE
;
2536 surface
->flags
|= SFLAG_CLIENT
;
2538 /* Point OpenGL to our allocated texture memory. Do not use
2539 * resource.allocatedMemory here because it might point into a
2540 * PBO. Instead use heapMemory, but get the alignment right. */
2541 mem
= (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
2542 + (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
2546 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
2548 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
2549 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
2550 checkGLcall("glCompressedTexImage2DARB");
2554 glTexImage2D(surface
->texture_target
, surface
->texture_level
,
2555 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
2556 checkGLcall("glTexImage2D");
2559 if(enable_client_storage
) {
2560 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2561 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2566 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2567 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2568 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2569 /* GL locking is done by the caller */
2570 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
2572 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
2573 struct wined3d_renderbuffer_entry
*entry
;
2574 GLuint renderbuffer
= 0;
2575 unsigned int src_width
, src_height
;
2576 unsigned int width
, height
;
2578 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
2580 width
= rt
->pow2Width
;
2581 height
= rt
->pow2Height
;
2585 width
= surface
->pow2Width
;
2586 height
= surface
->pow2Height
;
2589 src_width
= surface
->pow2Width
;
2590 src_height
= surface
->pow2Height
;
2592 /* A depth stencil smaller than the render target is not valid */
2593 if (width
> src_width
|| height
> src_height
) return;
2595 /* Remove any renderbuffer set if the sizes match */
2596 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
2597 || (width
== src_width
&& height
== src_height
))
2599 surface
->current_renderbuffer
= NULL
;
2603 /* Look if we've already got a renderbuffer of the correct dimensions */
2604 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
2606 if (entry
->width
== width
&& entry
->height
== height
)
2608 renderbuffer
= entry
->id
;
2609 surface
->current_renderbuffer
= entry
;
2616 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
2617 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
2618 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
2619 surface
->resource
.format
->glInternal
, width
, height
);
2621 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
2622 entry
->width
= width
;
2623 entry
->height
= height
;
2624 entry
->id
= renderbuffer
;
2625 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
2627 surface
->current_renderbuffer
= entry
;
2630 checkGLcall("set_compatible_renderbuffer");
2633 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
2635 const struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
2637 TRACE("surface %p.\n", surface
);
2639 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
)
2641 ERR("Surface %p is not on a swapchain.\n", surface
);
2645 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
)
2647 if (swapchain
->render_to_fbo
)
2649 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2650 return GL_COLOR_ATTACHMENT0
;
2652 TRACE("Returning GL_BACK\n");
2655 else if (surface
== swapchain
->front_buffer
)
2657 TRACE("Returning GL_FRONT\n");
2661 FIXME("Higher back buffer, returning GL_BACK\n");
2665 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2666 void surface_add_dirty_rect(struct wined3d_surface
*surface
, const WINED3DBOX
*dirty_rect
)
2668 TRACE("surface %p, dirty_rect %p.\n", surface
, dirty_rect
);
2670 if (!(surface
->flags
& SFLAG_INSYSMEM
) && (surface
->flags
& SFLAG_INTEXTURE
))
2671 /* No partial locking for textures yet. */
2672 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2674 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
2677 surface
->dirtyRect
.left
= min(surface
->dirtyRect
.left
, dirty_rect
->Left
);
2678 surface
->dirtyRect
.top
= min(surface
->dirtyRect
.top
, dirty_rect
->Top
);
2679 surface
->dirtyRect
.right
= max(surface
->dirtyRect
.right
, dirty_rect
->Right
);
2680 surface
->dirtyRect
.bottom
= max(surface
->dirtyRect
.bottom
, dirty_rect
->Bottom
);
2684 surface
->dirtyRect
.left
= 0;
2685 surface
->dirtyRect
.top
= 0;
2686 surface
->dirtyRect
.right
= surface
->resource
.width
;
2687 surface
->dirtyRect
.bottom
= surface
->resource
.height
;
2690 /* if the container is a texture then mark it dirty. */
2691 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
2693 TRACE("Passing to container.\n");
2694 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
2698 HRESULT
surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
2700 DWORD flag
= srgb
? SFLAG_INSRGBTEX
: SFLAG_INTEXTURE
;
2703 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
2705 if (surface
->resource
.pool
== WINED3DPOOL_SCRATCH
)
2707 ERR("Not supported on scratch surfaces.\n");
2708 return WINED3DERR_INVALIDCALL
;
2711 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
2713 /* Reload if either the texture and sysmem have different ideas about the
2714 * color key, or the actual key values changed. */
2715 if (ck_changed
|| ((surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
2716 && (surface
->glCKey
.dwColorSpaceLowValue
!= surface
->SrcBltCKey
.dwColorSpaceLowValue
2717 || surface
->glCKey
.dwColorSpaceHighValue
!= surface
->SrcBltCKey
.dwColorSpaceHighValue
)))
2719 TRACE("Reloading because of color keying\n");
2720 /* To perform the color key conversion we need a sysmem copy of
2721 * the surface. Make sure we have it. */
2723 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
2724 /* Make sure the texture is reloaded because of the color key change,
2725 * this kills performance though :( */
2726 /* TODO: This is not necessarily needed with hw palettized texture support. */
2727 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
2728 /* Switching color keying on / off may change the internal format. */
2730 surface_force_reload(surface
);
2732 else if (!(surface
->flags
& flag
))
2734 TRACE("Reloading because surface is dirty.\n");
2738 TRACE("surface is already in texture\n");
2742 /* No partial locking for textures yet. */
2743 surface_load_location(surface
, flag
, NULL
);
2744 surface_evict_sysmem(surface
);
2749 /* See also float_16_to_32() in wined3d_private.h */
2750 static inline unsigned short float_32_to_16(const float *in
)
2753 float tmp
= fabsf(*in
);
2754 unsigned int mantissa
;
2757 /* Deal with special numbers */
2763 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2765 if (tmp
< powf(2, 10))
2771 } while (tmp
< powf(2, 10));
2773 else if (tmp
>= powf(2, 11))
2779 } while (tmp
>= powf(2, 11));
2782 mantissa
= (unsigned int)tmp
;
2783 if (tmp
- mantissa
>= 0.5f
)
2784 ++mantissa
; /* Round to nearest, away from zero. */
2786 exp
+= 10; /* Normalize the mantissa. */
2787 exp
+= 15; /* Exponent is encoded with excess 15. */
2789 if (exp
> 30) /* too big */
2791 ret
= 0x7c00; /* INF */
2795 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2798 mantissa
= mantissa
>> 1;
2801 ret
= mantissa
& 0x3ff;
2805 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2808 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2812 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2816 TRACE("Surface %p, container %p of type %#x.\n",
2817 surface
, surface
->container
.u
.base
, surface
->container
.type
);
2819 switch (surface
->container
.type
)
2821 case WINED3D_CONTAINER_TEXTURE
:
2822 return wined3d_texture_incref(surface
->container
.u
.texture
);
2824 case WINED3D_CONTAINER_SWAPCHAIN
:
2825 return wined3d_swapchain_incref(surface
->container
.u
.swapchain
);
2828 ERR("Unhandled container type %#x.\n", surface
->container
.type
);
2829 case WINED3D_CONTAINER_NONE
:
2833 refcount
= InterlockedIncrement(&surface
->resource
.ref
);
2834 TRACE("%p increasing refcount to %u.\n", surface
, refcount
);
2839 /* Do not call while under the GL lock. */
2840 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2844 TRACE("Surface %p, container %p of type %#x.\n",
2845 surface
, surface
->container
.u
.base
, surface
->container
.type
);
2847 switch (surface
->container
.type
)
2849 case WINED3D_CONTAINER_TEXTURE
:
2850 return wined3d_texture_decref(surface
->container
.u
.texture
);
2852 case WINED3D_CONTAINER_SWAPCHAIN
:
2853 return wined3d_swapchain_decref(surface
->container
.u
.swapchain
);
2856 ERR("Unhandled container type %#x.\n", surface
->container
.type
);
2857 case WINED3D_CONTAINER_NONE
:
2861 refcount
= InterlockedDecrement(&surface
->resource
.ref
);
2862 TRACE("%p decreasing refcount to %u.\n", surface
, refcount
);
2866 surface
->surface_ops
->surface_cleanup(surface
);
2867 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
2869 TRACE("Destroyed surface %p.\n", surface
);
2870 HeapFree(GetProcessHeap(), 0, surface
);
2876 DWORD CDECL
wined3d_surface_set_priority(struct wined3d_surface
*surface
, DWORD priority
)
2878 return resource_set_priority(&surface
->resource
, priority
);
2881 DWORD CDECL
wined3d_surface_get_priority(const struct wined3d_surface
*surface
)
2883 return resource_get_priority(&surface
->resource
);
2886 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2888 TRACE("surface %p.\n", surface
);
2890 surface
->surface_ops
->surface_preload(surface
);
2893 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2895 TRACE("surface %p.\n", surface
);
2897 return surface
->resource
.parent
;
2900 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2902 TRACE("surface %p.\n", surface
);
2904 return &surface
->resource
;
2907 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2909 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2913 case WINEDDGBS_CANBLT
:
2914 case WINEDDGBS_ISBLTDONE
:
2918 return WINED3DERR_INVALIDCALL
;
2922 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2924 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2926 /* XXX: DDERR_INVALIDSURFACETYPE */
2930 case WINEDDGFS_CANFLIP
:
2931 case WINEDDGFS_ISFLIPDONE
:
2935 return WINED3DERR_INVALIDCALL
;
2939 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2941 TRACE("surface %p.\n", surface
);
2943 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2944 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2947 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2949 TRACE("surface %p.\n", surface
);
2951 /* So far we don't lose anything :) */
2952 surface
->flags
&= ~SFLAG_LOST
;
2956 HRESULT CDECL
wined3d_surface_set_palette(struct wined3d_surface
*surface
, struct wined3d_palette
*palette
)
2958 TRACE("surface %p, palette %p.\n", surface
, palette
);
2960 if (surface
->palette
== palette
)
2962 TRACE("Nop palette change.\n");
2966 if (surface
->palette
&& (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
2967 surface
->palette
->flags
&= ~WINEDDPCAPS_PRIMARYSURFACE
;
2969 surface
->palette
= palette
;
2973 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
2974 palette
->flags
|= WINEDDPCAPS_PRIMARYSURFACE
;
2976 surface
->surface_ops
->surface_realize_palette(surface
);
2982 HRESULT CDECL
wined3d_surface_set_color_key(struct wined3d_surface
*surface
,
2983 DWORD flags
, const WINEDDCOLORKEY
*color_key
)
2985 TRACE("surface %p, flags %#x, color_key %p.\n", surface
, flags
, color_key
);
2987 if (flags
& WINEDDCKEY_COLORSPACE
)
2989 FIXME(" colorkey value not supported (%08x) !\n", flags
);
2990 return WINED3DERR_INVALIDCALL
;
2993 /* Dirtify the surface, but only if a key was changed. */
2996 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
2998 case WINEDDCKEY_DESTBLT
:
2999 surface
->DestBltCKey
= *color_key
;
3000 surface
->CKeyFlags
|= WINEDDSD_CKDESTBLT
;
3003 case WINEDDCKEY_DESTOVERLAY
:
3004 surface
->DestOverlayCKey
= *color_key
;
3005 surface
->CKeyFlags
|= WINEDDSD_CKDESTOVERLAY
;
3008 case WINEDDCKEY_SRCOVERLAY
:
3009 surface
->SrcOverlayCKey
= *color_key
;
3010 surface
->CKeyFlags
|= WINEDDSD_CKSRCOVERLAY
;
3013 case WINEDDCKEY_SRCBLT
:
3014 surface
->SrcBltCKey
= *color_key
;
3015 surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
3021 switch (flags
& ~WINEDDCKEY_COLORSPACE
)
3023 case WINEDDCKEY_DESTBLT
:
3024 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTBLT
;
3027 case WINEDDCKEY_DESTOVERLAY
:
3028 surface
->CKeyFlags
&= ~WINEDDSD_CKDESTOVERLAY
;
3031 case WINEDDCKEY_SRCOVERLAY
:
3032 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCOVERLAY
;
3035 case WINEDDCKEY_SRCBLT
:
3036 surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
3044 struct wined3d_palette
* CDECL
wined3d_surface_get_palette(const struct wined3d_surface
*surface
)
3046 TRACE("surface %p.\n", surface
);
3048 return surface
->palette
;
3051 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
3053 const struct wined3d_format
*format
= surface
->resource
.format
;
3056 TRACE("surface %p.\n", surface
);
3058 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
3060 /* Since compressed formats are block based, pitch means the amount of
3061 * bytes to the next row of block rather than the next row of pixels. */
3062 UINT row_block_count
= (surface
->resource
.width
+ format
->block_width
- 1) / format
->block_width
;
3063 pitch
= row_block_count
* format
->block_byte_count
;
3067 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
3068 pitch
= surface
->resource
.format
->byte_count
* surface
->resource
.width
; /* Bytes / row */
3069 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
3072 TRACE("Returning %u.\n", pitch
);
3077 HRESULT CDECL
wined3d_surface_set_mem(struct wined3d_surface
*surface
, void *mem
)
3079 TRACE("surface %p, mem %p.\n", surface
, mem
);
3081 if (surface
->flags
& (SFLAG_LOCKED
| SFLAG_DCINUSE
))
3083 WARN("Surface is locked or the DC is in use.\n");
3084 return WINED3DERR_INVALIDCALL
;
3087 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3088 if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
3090 ERR("Not supported on render targets.\n");
3091 return WINED3DERR_INVALIDCALL
;
3094 if (mem
&& mem
!= surface
->resource
.allocatedMemory
)
3096 void *release
= NULL
;
3098 /* Do I have to copy the old surface content? */
3099 if (surface
->flags
& SFLAG_DIBSECTION
)
3101 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
3102 DeleteDC(surface
->hDC
);
3103 /* Release the DIB section. */
3104 DeleteObject(surface
->dib
.DIBsection
);
3105 surface
->dib
.bitmap_data
= NULL
;
3106 surface
->resource
.allocatedMemory
= NULL
;
3107 surface
->hDC
= NULL
;
3108 surface
->flags
&= ~SFLAG_DIBSECTION
;
3110 else if (!(surface
->flags
& SFLAG_USERPTR
))
3112 release
= surface
->resource
.heapMemory
;
3113 surface
->resource
.heapMemory
= NULL
;
3115 surface
->resource
.allocatedMemory
= mem
;
3116 surface
->flags
|= SFLAG_USERPTR
;
3118 /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3119 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3121 /* For client textures OpenGL has to be notified. */
3122 if (surface
->flags
& SFLAG_CLIENT
)
3123 surface_release_client_storage(surface
);
3125 /* Now free the old memory if any. */
3126 HeapFree(GetProcessHeap(), 0, release
);
3128 else if (surface
->flags
& SFLAG_USERPTR
)
3130 /* HeapMemory should be NULL already. */
3131 if (surface
->resource
.heapMemory
)
3132 ERR("User pointer surface has heap memory allocated.\n");
3136 surface
->resource
.allocatedMemory
= NULL
;
3137 surface
->flags
&= ~(SFLAG_USERPTR
| SFLAG_INSYSMEM
);
3139 if (surface
->flags
& SFLAG_CLIENT
)
3140 surface_release_client_storage(surface
);
3142 surface_prepare_system_memory(surface
);
3145 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3151 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
3155 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
3157 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3159 WARN("Not an overlay surface.\n");
3160 return WINEDDERR_NOTAOVERLAYSURFACE
;
3163 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
3164 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
3165 surface
->overlay_destrect
.left
= x
;
3166 surface
->overlay_destrect
.top
= y
;
3167 surface
->overlay_destrect
.right
= x
+ w
;
3168 surface
->overlay_destrect
.bottom
= y
+ h
;
3170 surface
->surface_ops
->surface_draw_overlay(surface
);
3175 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
3177 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
3179 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3181 TRACE("Not an overlay surface.\n");
3182 return WINEDDERR_NOTAOVERLAYSURFACE
;
3185 if (!surface
->overlay_dest
)
3187 TRACE("Overlay not visible.\n");
3190 return WINEDDERR_OVERLAYNOTVISIBLE
;
3193 *x
= surface
->overlay_destrect
.left
;
3194 *y
= surface
->overlay_destrect
.top
;
3196 TRACE("Returning position %d, %d.\n", *x
, *y
);
3201 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
3202 DWORD flags
, struct wined3d_surface
*ref
)
3204 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
3206 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3208 TRACE("Not an overlay surface.\n");
3209 return WINEDDERR_NOTAOVERLAYSURFACE
;
3215 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
3216 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
3218 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3219 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
3221 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
3223 WARN("Not an overlay surface.\n");
3224 return WINEDDERR_NOTAOVERLAYSURFACE
;
3226 else if (!dst_surface
)
3228 WARN("Dest surface is NULL.\n");
3229 return WINED3DERR_INVALIDCALL
;
3234 surface
->overlay_srcrect
= *src_rect
;
3238 surface
->overlay_srcrect
.left
= 0;
3239 surface
->overlay_srcrect
.top
= 0;
3240 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
3241 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
3246 surface
->overlay_destrect
= *dst_rect
;
3250 surface
->overlay_destrect
.left
= 0;
3251 surface
->overlay_destrect
.top
= 0;
3252 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
3253 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
3256 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
3258 list_remove(&surface
->overlay_entry
);
3261 if (flags
& WINEDDOVER_SHOW
)
3263 if (surface
->overlay_dest
!= dst_surface
)
3265 surface
->overlay_dest
= dst_surface
;
3266 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
3269 else if (flags
& WINEDDOVER_HIDE
)
3271 /* tests show that the rectangles are erased on hide */
3272 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
3273 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
3274 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
3275 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
3276 surface
->overlay_dest
= NULL
;
3279 surface
->surface_ops
->surface_draw_overlay(surface
);
3284 HRESULT CDECL
wined3d_surface_set_clipper(struct wined3d_surface
*surface
, struct wined3d_clipper
*clipper
)
3286 TRACE("surface %p, clipper %p.\n", surface
, clipper
);
3288 surface
->clipper
= clipper
;
3293 struct wined3d_clipper
* CDECL
wined3d_surface_get_clipper(const struct wined3d_surface
*surface
)
3295 TRACE("surface %p.\n", surface
);
3297 return surface
->clipper
;
3300 HRESULT CDECL
wined3d_surface_set_format(struct wined3d_surface
*surface
, enum wined3d_format_id format_id
)
3302 const struct wined3d_format
*format
= wined3d_get_format(&surface
->resource
.device
->adapter
->gl_info
, format_id
);
3304 TRACE("surface %p, format %s.\n", surface
, debug_d3dformat(format_id
));
3306 if (surface
->resource
.format
->id
!= WINED3DFMT_UNKNOWN
)
3308 FIXME("The format of the surface must be WINED3DFORMAT_UNKNOWN.\n");
3309 return WINED3DERR_INVALIDCALL
;
3312 surface
->resource
.size
= wined3d_format_calculate_size(format
, surface
->resource
.device
->surface_alignment
,
3313 surface
->pow2Width
, surface
->pow2Height
);
3314 surface
->flags
|= (WINED3DFMT_D16_LOCKABLE
== format_id
) ? SFLAG_LOCKABLE
: 0;
3315 surface
->resource
.format
= format
;
3317 TRACE("size %u, byte_count %u\n", surface
->resource
.size
, format
->byte_count
);
3318 TRACE("glFormat %#x, glInternal %#x, glType %#x.\n",
3319 format
->glFormat
, format
->glInternal
, format
->glType
);
3324 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
3325 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3327 unsigned short *dst_s
;
3331 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3333 for (y
= 0; y
< h
; ++y
)
3335 src_f
= (const float *)(src
+ y
* pitch_in
);
3336 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
3337 for (x
= 0; x
< w
; ++x
)
3339 dst_s
[x
] = float_32_to_16(src_f
+ x
);
3344 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3345 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3347 static const unsigned char convert_5to8
[] =
3349 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3350 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3351 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3352 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3354 static const unsigned char convert_6to8
[] =
3356 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3357 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3358 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3359 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3360 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3361 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3362 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3363 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3367 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3369 for (y
= 0; y
< h
; ++y
)
3371 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
3372 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3373 for (x
= 0; x
< w
; ++x
)
3375 WORD pixel
= src_line
[x
];
3376 dst_line
[x
] = 0xff000000
3377 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
3378 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
3379 | convert_5to8
[(pixel
& 0x001f)];
3384 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3385 * in both cases we're just setting the X / Alpha channel to 0xff. */
3386 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3387 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3391 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3393 for (y
= 0; y
< h
; ++y
)
3395 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
3396 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3398 for (x
= 0; x
< w
; ++x
)
3400 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
3405 static inline BYTE
cliptobyte(int x
)
3407 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
3410 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
3411 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3413 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3416 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
3418 for (y
= 0; y
< h
; ++y
)
3420 const BYTE
*src_line
= src
+ y
* pitch_in
;
3421 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
3422 for (x
= 0; x
< w
; ++x
)
3424 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3425 * C = Y - 16; D = U - 128; E = V - 128;
3426 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3427 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3428 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3429 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3430 * U and V are shared between the pixels. */
3431 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3433 d
= (int) src_line
[1] - 128;
3434 e
= (int) src_line
[3] - 128;
3436 g2
= - 100 * d
- 208 * e
+ 128;
3439 c2
= 298 * ((int) src_line
[0] - 16);
3440 dst_line
[x
] = 0xff000000
3441 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
3442 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
3443 | cliptobyte((c2
+ b2
) >> 8); /* blue */
3444 /* Scale RGB values to 0..255 range,
3445 * then clip them if still not in range (may be negative),
3446 * then shift them within DWORD if necessary. */
3452 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
3453 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
3456 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
3458 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
3460 for (y
= 0; y
< h
; ++y
)
3462 const BYTE
*src_line
= src
+ y
* pitch_in
;
3463 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
3464 for (x
= 0; x
< w
; ++x
)
3466 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3467 * C = Y - 16; D = U - 128; E = V - 128;
3468 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3469 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3470 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3471 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3472 * U and V are shared between the pixels. */
3473 if (!(x
& 1)) /* For every even pixel, read new U and V. */
3475 d
= (int) src_line
[1] - 128;
3476 e
= (int) src_line
[3] - 128;
3478 g2
= - 100 * d
- 208 * e
+ 128;
3481 c2
= 298 * ((int) src_line
[0] - 16);
3482 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
3483 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
3484 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
3485 /* Scale RGB values to 0..255 range,
3486 * then clip them if still not in range (may be negative),
3487 * then shift them within DWORD if necessary. */
3493 struct d3dfmt_convertor_desc
3495 enum wined3d_format_id from
, to
;
3496 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
3499 static const struct d3dfmt_convertor_desc convertors
[] =
3501 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
3502 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
3503 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3504 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
3505 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
3506 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
3509 static inline const struct d3dfmt_convertor_desc
*find_convertor(enum wined3d_format_id from
,
3510 enum wined3d_format_id to
)
3514 for (i
= 0; i
< (sizeof(convertors
) / sizeof(*convertors
)); ++i
)
3516 if (convertors
[i
].from
== from
&& convertors
[i
].to
== to
)
3517 return &convertors
[i
];
3523 /*****************************************************************************
3524 * surface_convert_format
3526 * Creates a duplicate of a surface in a different format. Is used by Blt to
3527 * blit between surfaces with different formats.
3530 * source: Source surface
3531 * fmt: Requested destination format
3533 *****************************************************************************/
3534 static struct wined3d_surface
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
3536 const struct d3dfmt_convertor_desc
*conv
;
3537 WINED3DLOCKED_RECT lock_src
, lock_dst
;
3538 struct wined3d_surface
*ret
= NULL
;
3541 conv
= find_convertor(source
->resource
.format
->id
, to_fmt
);
3544 FIXME("Cannot find a conversion function from format %s to %s.\n",
3545 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
3549 wined3d_surface_create(source
->resource
.device
, source
->resource
.width
,
3550 source
->resource
.height
, to_fmt
, TRUE
/* lockable */, TRUE
/* discard */, 0 /* level */,
3551 0 /* usage */, WINED3DPOOL_SCRATCH
, WINED3DMULTISAMPLE_NONE
/* TODO: Multisampled conversion */,
3552 0 /* MultiSampleQuality */, source
->surface_type
, NULL
/* parent */, &wined3d_null_parent_ops
, &ret
);
3555 ERR("Failed to create a destination surface for conversion.\n");
3559 memset(&lock_src
, 0, sizeof(lock_src
));
3560 memset(&lock_dst
, 0, sizeof(lock_dst
));
3562 hr
= wined3d_surface_map(source
, &lock_src
, NULL
, WINED3DLOCK_READONLY
);
3565 ERR("Failed to lock the source surface.\n");
3566 wined3d_surface_decref(ret
);
3569 hr
= wined3d_surface_map(ret
, &lock_dst
, NULL
, WINED3DLOCK_READONLY
);
3572 ERR("Failed to lock the destination surface.\n");
3573 wined3d_surface_unmap(source
);
3574 wined3d_surface_decref(ret
);
3578 conv
->convert(lock_src
.pBits
, lock_dst
.pBits
, lock_src
.Pitch
, lock_dst
.Pitch
,
3579 source
->resource
.width
, source
->resource
.height
);
3581 wined3d_surface_unmap(ret
);
3582 wined3d_surface_unmap(source
);
3587 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
3588 unsigned int bpp
, UINT pitch
, DWORD color
)
3595 #define COLORFILL_ROW(type) \
3597 type *d = (type *)buf; \
3598 for (x = 0; x < width; ++x) \
3599 d[x] = (type)color; \
3605 COLORFILL_ROW(BYTE
);
3609 COLORFILL_ROW(WORD
);
3615 for (x
= 0; x
< width
; ++x
, d
+= 3)
3617 d
[0] = (color
) & 0xFF;
3618 d
[1] = (color
>> 8) & 0xFF;
3619 d
[2] = (color
>> 16) & 0xFF;
3624 COLORFILL_ROW(DWORD
);
3628 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
3629 return WINED3DERR_NOTAVAILABLE
;
3632 #undef COLORFILL_ROW
3634 /* Now copy first row. */
3636 for (y
= 1; y
< height
; ++y
)
3639 memcpy(buf
, first
, width
* bpp
);
3645 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
3647 TRACE("surface %p.\n", surface
);
3649 if (!(surface
->flags
& SFLAG_LOCKED
))
3651 WARN("Trying to unmap unmapped surface.\n");
3652 return WINEDDERR_NOTLOCKED
;
3654 surface
->flags
&= ~SFLAG_LOCKED
;
3656 surface
->surface_ops
->surface_unmap(surface
);
3661 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
3662 WINED3DLOCKED_RECT
*locked_rect
, const RECT
*rect
, DWORD flags
)
3664 TRACE("surface %p, locked_rect %p, rect %s, flags %#x.\n",
3665 surface
, locked_rect
, wine_dbgstr_rect(rect
), flags
);
3667 if (surface
->flags
& SFLAG_LOCKED
)
3669 WARN("Surface is already mapped.\n");
3670 return WINED3DERR_INVALIDCALL
;
3672 surface
->flags
|= SFLAG_LOCKED
;
3674 if (!(surface
->flags
& SFLAG_LOCKABLE
))
3675 WARN("Trying to lock unlockable surface.\n");
3677 surface
->surface_ops
->surface_map(surface
, rect
, flags
);
3679 locked_rect
->Pitch
= wined3d_surface_get_pitch(surface
);
3683 locked_rect
->pBits
= surface
->resource
.allocatedMemory
;
3684 surface
->lockedRect
.left
= 0;
3685 surface
->lockedRect
.top
= 0;
3686 surface
->lockedRect
.right
= surface
->resource
.width
;
3687 surface
->lockedRect
.bottom
= surface
->resource
.height
;
3691 const struct wined3d_format
*format
= surface
->resource
.format
;
3693 if ((format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_COMPRESSED
)
3695 /* Compressed textures are block based, so calculate the offset of
3696 * the block that contains the top-left pixel of the locked rectangle. */
3697 locked_rect
->pBits
= surface
->resource
.allocatedMemory
3698 + ((rect
->top
/ format
->block_height
) * locked_rect
->Pitch
)
3699 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
3703 locked_rect
->pBits
= surface
->resource
.allocatedMemory
3704 + (locked_rect
->Pitch
* rect
->top
)
3705 + (rect
->left
* format
->byte_count
);
3707 surface
->lockedRect
.left
= rect
->left
;
3708 surface
->lockedRect
.top
= rect
->top
;
3709 surface
->lockedRect
.right
= rect
->right
;
3710 surface
->lockedRect
.bottom
= rect
->bottom
;
3713 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
3714 TRACE("Returning memory %p, pitch %u.\n", locked_rect
->pBits
, locked_rect
->Pitch
);
3719 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
3723 TRACE("surface %p, dc %p.\n", surface
, dc
);
3725 if (surface
->flags
& SFLAG_USERPTR
)
3727 ERR("Not supported on surfaces with application-provided memory.\n");
3728 return WINEDDERR_NODC
;
3731 /* Give more detailed info for ddraw. */
3732 if (surface
->flags
& SFLAG_DCINUSE
)
3733 return WINEDDERR_DCALREADYCREATED
;
3735 /* Can't GetDC if the surface is locked. */
3736 if (surface
->flags
& SFLAG_LOCKED
)
3737 return WINED3DERR_INVALIDCALL
;
3739 hr
= surface
->surface_ops
->surface_getdc(surface
);
3743 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3744 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3746 /* GetDC on palettized formats is unsupported in D3D9, and the method
3747 * is missing in D3D8, so this should only be used for DX <=7
3748 * surfaces (with non-device palettes). */
3749 const PALETTEENTRY
*pal
= NULL
;
3751 if (surface
->palette
)
3753 pal
= surface
->palette
->palents
;
3757 struct wined3d_swapchain
*swapchain
= surface
->resource
.device
->swapchains
[0];
3758 struct wined3d_surface
*dds_primary
= swapchain
->front_buffer
;
3760 if (dds_primary
&& dds_primary
->palette
)
3761 pal
= dds_primary
->palette
->palents
;
3769 for (i
= 0; i
< 256; ++i
)
3771 col
[i
].rgbRed
= pal
[i
].peRed
;
3772 col
[i
].rgbGreen
= pal
[i
].peGreen
;
3773 col
[i
].rgbBlue
= pal
[i
].peBlue
;
3774 col
[i
].rgbReserved
= 0;
3776 SetDIBColorTable(surface
->hDC
, 0, 256, col
);
3780 surface
->flags
|= SFLAG_DCINUSE
;
3783 TRACE("Returning dc %p.\n", *dc
);
3788 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
3790 TRACE("surface %p, dc %p.\n", surface
, dc
);
3792 if (!(surface
->flags
& SFLAG_DCINUSE
))
3793 return WINEDDERR_NODC
;
3795 if (surface
->hDC
!= dc
)
3797 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
3799 return WINEDDERR_NODC
;
3802 /* Copy the contents of the DIB over to the PBO. */
3803 if ((surface
->flags
& SFLAG_PBO
) && surface
->resource
.allocatedMemory
)
3804 memcpy(surface
->resource
.allocatedMemory
, surface
->dib
.bitmap_data
, surface
->resource
.size
);
3806 /* We locked first, so unlock now. */
3807 wined3d_surface_unmap(surface
);
3809 surface
->flags
&= ~SFLAG_DCINUSE
;
3814 HRESULT CDECL
wined3d_surface_flip(struct wined3d_surface
*surface
, struct wined3d_surface
*override
, DWORD flags
)
3816 TRACE("surface %p, override %p, flags %#x.\n", surface
, override
, flags
);
3822 FIXME("Ignoring flags %#x.\n", flags
);
3824 WARN("Ignoring flags %#x.\n", flags
);
3827 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
3829 ERR("Not supported on swapchain surfaces.\n");
3830 return WINEDDERR_NOTFLIPPABLE
;
3833 /* Flipping is only supported on render targets and overlays. */
3834 if (!(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_OVERLAY
)))
3836 WARN("Tried to flip a non-render target, non-overlay surface.\n");
3837 return WINEDDERR_NOTFLIPPABLE
;
3840 flip_surface(surface
, override
);
3842 /* Update overlays if they're visible. */
3843 if ((surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
) && surface
->overlay_dest
)
3844 return surface
->surface_ops
->surface_draw_overlay(surface
);
3849 /* Do not call while under the GL lock. */
3850 void surface_internal_preload(struct wined3d_surface
*surface
, enum WINED3DSRGB srgb
)
3852 struct wined3d_device
*device
= surface
->resource
.device
;
3854 TRACE("iface %p, srgb %#x.\n", surface
, srgb
);
3856 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
3858 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
3860 TRACE("Passing to container (%p).\n", texture
);
3861 texture
->texture_ops
->texture_preload(texture
, srgb
);
3865 struct wined3d_context
*context
;
3867 TRACE("(%p) : About to load surface\n", surface
);
3869 /* TODO: Use already acquired context when possible. */
3870 context
= context_acquire(device
, NULL
);
3872 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3873 || surface
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
)
3875 if (palette9_changed(surface
))
3877 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
3878 /* TODO: This is not necessarily needed with hw palettized texture support */
3879 surface_load_location(surface
, SFLAG_INSYSMEM
, NULL
);
3880 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
3881 surface_modify_location(surface
, SFLAG_INTEXTURE
, FALSE
);
3885 surface_load(surface
, srgb
== SRGB_SRGB
? TRUE
: FALSE
);
3887 if (surface
->resource
.pool
== WINED3DPOOL_DEFAULT
)
3889 /* Tell opengl to try and keep this texture in video ram (well mostly) */
3893 glPrioritizeTextures(1, &surface
->texture_name
, &tmp
);
3897 context_release(context
);
3901 BOOL
surface_init_sysmem(struct wined3d_surface
*surface
)
3903 if (!surface
->resource
.allocatedMemory
)
3905 surface
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
3906 surface
->resource
.size
+ RESOURCE_ALIGNMENT
);
3907 if (!surface
->resource
.heapMemory
)
3909 ERR("Out of memory\n");
3912 surface
->resource
.allocatedMemory
=
3913 (BYTE
*)(((ULONG_PTR
)surface
->resource
.heapMemory
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
3917 memset(surface
->resource
.allocatedMemory
, 0, surface
->resource
.size
);
3920 surface_modify_location(surface
, SFLAG_INSYSMEM
, TRUE
);
3925 /* Read the framebuffer back into the surface */
3926 static void read_from_framebuffer(struct wined3d_surface
*surface
, const RECT
*rect
, void *dest
, UINT pitch
)
3928 struct wined3d_device
*device
= surface
->resource
.device
;
3929 const struct wined3d_gl_info
*gl_info
;
3930 struct wined3d_context
*context
;
3934 BYTE
*row
, *top
, *bottom
;
3938 BOOL srcIsUpsideDown
;
3943 if(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
) {
3944 static BOOL warned
= FALSE
;
3946 ERR("The application tries to lock the render target, but render target locking is disabled\n");
3952 context
= context_acquire(device
, surface
);
3953 context_apply_blit_state(context
, device
);
3954 gl_info
= context
->gl_info
;
3958 /* Select the correct read buffer, and give some debug output.
3959 * There is no need to keep track of the current read buffer or reset it, every part of the code
3960 * that reads sets the read buffer as desired.
3962 if (surface_is_offscreen(surface
))
3964 /* Mapping the primary render target which is not on a swapchain.
3965 * Read from the back buffer. */
3966 TRACE("Mapping offscreen render target.\n");
3967 glReadBuffer(device
->offscreenBuffer
);
3968 srcIsUpsideDown
= TRUE
;
3972 /* Onscreen surfaces are always part of a swapchain */
3973 GLenum buffer
= surface_get_gl_buffer(surface
);
3974 TRACE("Mapping %#x buffer.\n", buffer
);
3975 glReadBuffer(buffer
);
3976 checkGLcall("glReadBuffer");
3977 srcIsUpsideDown
= FALSE
;
3980 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
3983 local_rect
.left
= 0;
3985 local_rect
.right
= surface
->resource
.width
;
3986 local_rect
.bottom
= surface
->resource
.height
;
3992 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
3994 switch (surface
->resource
.format
->id
)
3996 case WINED3DFMT_P8_UINT
:
3998 if (primary_render_target_is_p8(device
))
4000 /* In case of P8 render targets the index is stored in the alpha component */
4002 type
= GL_UNSIGNED_BYTE
;
4004 bpp
= surface
->resource
.format
->byte_count
;
4008 /* GL can't return palettized data, so read ARGB pixels into a
4009 * separate block of memory and convert them into palettized format
4010 * in software. Slow, but if the app means to use palettized render
4011 * targets and locks it...
4013 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4014 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4015 * for the color channels when palettizing the colors.
4018 type
= GL_UNSIGNED_BYTE
;
4020 mem
= HeapAlloc(GetProcessHeap(), 0, surface
->resource
.size
* 3);
4023 ERR("Out of memory\n");
4027 bpp
= surface
->resource
.format
->byte_count
* 3;
4034 fmt
= surface
->resource
.format
->glFormat
;
4035 type
= surface
->resource
.format
->glType
;
4036 bpp
= surface
->resource
.format
->byte_count
;
4039 if (surface
->flags
& SFLAG_PBO
)
4041 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, surface
->pbo
));
4042 checkGLcall("glBindBufferARB");
4045 ERR("mem not null for pbo -- unexpected\n");
4050 /* Save old pixel store pack state */
4051 glGetIntegerv(GL_PACK_ROW_LENGTH
, &rowLen
);
4052 checkGLcall("glGetIntegerv");
4053 glGetIntegerv(GL_PACK_SKIP_PIXELS
, &skipPix
);
4054 checkGLcall("glGetIntegerv");
4055 glGetIntegerv(GL_PACK_SKIP_ROWS
, &skipRow
);
4056 checkGLcall("glGetIntegerv");
4058 /* Setup pixel store pack state -- to glReadPixels into the correct place */
4059 glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
4060 checkGLcall("glPixelStorei");
4061 glPixelStorei(GL_PACK_SKIP_PIXELS
, local_rect
.left
);
4062 checkGLcall("glPixelStorei");
4063 glPixelStorei(GL_PACK_SKIP_ROWS
, local_rect
.top
);
4064 checkGLcall("glPixelStorei");
4066 glReadPixels(local_rect
.left
, !srcIsUpsideDown
? (surface
->resource
.height
- local_rect
.bottom
) : local_rect
.top
,
4067 local_rect
.right
- local_rect
.left
,
4068 local_rect
.bottom
- local_rect
.top
,
4070 checkGLcall("glReadPixels");
4072 /* Reset previous pixel store pack state */
4073 glPixelStorei(GL_PACK_ROW_LENGTH
, rowLen
);
4074 checkGLcall("glPixelStorei");
4075 glPixelStorei(GL_PACK_SKIP_PIXELS
, skipPix
);
4076 checkGLcall("glPixelStorei");
4077 glPixelStorei(GL_PACK_SKIP_ROWS
, skipRow
);
4078 checkGLcall("glPixelStorei");
4080 if (surface
->flags
& SFLAG_PBO
)
4082 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
4083 checkGLcall("glBindBufferARB");
4085 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4086 * to get a pointer to it and perform the flipping in software. This is a lot
4087 * faster than calling glReadPixels for each line. In case we want more speed
4088 * we should rerender it flipped in a FBO and read the data back from the FBO. */
4089 if (!srcIsUpsideDown
)
4091 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
4092 checkGLcall("glBindBufferARB");
4094 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
4095 checkGLcall("glMapBufferARB");
4099 /* TODO: Merge this with the palettization loop below for P8 targets */
4100 if(!srcIsUpsideDown
) {
4102 /* glReadPixels returns the image upside down, and there is no way to prevent this.
4103 Flip the lines in software */
4104 len
= (local_rect
.right
- local_rect
.left
) * bpp
;
4105 off
= local_rect
.left
* bpp
;
4107 row
= HeapAlloc(GetProcessHeap(), 0, len
);
4109 ERR("Out of memory\n");
4110 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
4111 HeapFree(GetProcessHeap(), 0, mem
);
4116 top
= mem
+ pitch
* local_rect
.top
;
4117 bottom
= mem
+ pitch
* (local_rect
.bottom
- 1);
4118 for(i
= 0; i
< (local_rect
.bottom
- local_rect
.top
) / 2; i
++) {
4119 memcpy(row
, top
+ off
, len
);
4120 memcpy(top
+ off
, bottom
+ off
, len
);
4121 memcpy(bottom
+ off
, row
, len
);
4125 HeapFree(GetProcessHeap(), 0, row
);
4127 /* Unmap the temp PBO buffer */
4128 if (surface
->flags
& SFLAG_PBO
)
4130 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
4131 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4136 context_release(context
);
4138 /* For P8 textures we need to perform an inverse palette lookup. This is
4139 * done by searching for a palette index which matches the RGB value.
4140 * Note this isn't guaranteed to work when there are multiple entries for
4141 * the same color but we have no choice. In case of P8 render targets,
4142 * the index is stored in the alpha component so no conversion is needed. */
4143 if (surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
&& !primary_render_target_is_p8(device
))
4145 const PALETTEENTRY
*pal
= NULL
;
4146 DWORD width
= pitch
/ 3;
4149 if (surface
->palette
)
4151 pal
= surface
->palette
->palents
;
4155 ERR("Palette is missing, cannot perform inverse palette lookup\n");
4156 HeapFree(GetProcessHeap(), 0, mem
);
4160 for(y
= local_rect
.top
; y
< local_rect
.bottom
; y
++) {
4161 for(x
= local_rect
.left
; x
< local_rect
.right
; x
++) {
4162 /* start lines pixels */
4163 const BYTE
*blue
= mem
+ y
* pitch
+ x
* (sizeof(BYTE
) * 3);
4164 const BYTE
*green
= blue
+ 1;
4165 const BYTE
*red
= green
+ 1;
4167 for(c
= 0; c
< 256; c
++) {
4168 if(*red
== pal
[c
].peRed
&&
4169 *green
== pal
[c
].peGreen
&&
4170 *blue
== pal
[c
].peBlue
)
4172 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
4178 HeapFree(GetProcessHeap(), 0, mem
);
4182 /* Read the framebuffer contents into a texture */
4183 static void read_from_framebuffer_texture(struct wined3d_surface
*surface
, BOOL srgb
)
4185 struct wined3d_device
*device
= surface
->resource
.device
;
4186 struct wined3d_context
*context
;
4188 if (!surface_is_offscreen(surface
))
4190 /* We would need to flip onscreen surfaces, but there's no efficient
4191 * way to do that here. It makes more sense for the caller to
4192 * explicitly go through sysmem. */
4193 ERR("Not supported for onscreen targets.\n");
4197 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
4198 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
4199 * states in the stateblock, and no driver was found yet that had bugs in that regard.
4201 context
= context_acquire(device
, surface
);
4202 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
4204 surface_prepare_texture(surface
, context
, srgb
);
4205 surface_bind_and_dirtify(surface
, context
, srgb
);
4207 TRACE("Reading back offscreen render target %p.\n", surface
);
4211 glReadBuffer(device
->offscreenBuffer
);
4212 checkGLcall("glReadBuffer");
4214 glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
4215 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
4216 checkGLcall("glCopyTexSubImage2D");
4220 context_release(context
);
4223 /* Context activation is done by the caller. */
4224 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
4225 struct wined3d_context
*context
, BOOL srgb
)
4227 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
4228 CONVERT_TYPES convert
;
4229 struct wined3d_format format
;
4231 if (surface
->flags
& alloc_flag
) return;
4233 d3dfmt_get_conv(surface
, TRUE
, TRUE
, &format
, &convert
);
4234 if (convert
!= NO_CONVERSION
|| format
.convert
) surface
->flags
|= SFLAG_CONVERTED
;
4235 else surface
->flags
&= ~SFLAG_CONVERTED
;
4237 surface_bind_and_dirtify(surface
, context
, srgb
);
4238 surface_allocate_surface(surface
, context
->gl_info
, &format
, srgb
);
4239 surface
->flags
|= alloc_flag
;
4242 /* Context activation is done by the caller. */
4243 void surface_prepare_texture(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
4245 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
4247 struct wined3d_texture
*texture
= surface
->container
.u
.texture
;
4248 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
4251 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
4253 for (i
= 0; i
< sub_count
; ++i
)
4255 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
4256 surface_prepare_texture_internal(s
, context
, srgb
);
4262 surface_prepare_texture_internal(surface
, context
, srgb
);
4265 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
4269 if (surface
->rb_multisample
)
4272 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
4273 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
4274 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
4275 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
4276 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
4280 if (surface
->rb_resolved
)
4283 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
4284 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
4285 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
4286 surface
->pow2Width
, surface
->pow2Height
);
4287 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
4291 static void flush_to_framebuffer_drawpixels(struct wined3d_surface
*surface
,
4292 const RECT
*rect
, GLenum fmt
, GLenum type
, UINT bpp
, const BYTE
*mem
)
4294 struct wined3d_device
*device
= surface
->resource
.device
;
4295 UINT pitch
= wined3d_surface_get_pitch(surface
);
4296 const struct wined3d_gl_info
*gl_info
;
4297 struct wined3d_context
*context
;
4301 surface_get_rect(surface
, rect
, &local_rect
);
4303 mem
+= local_rect
.top
* pitch
+ local_rect
.left
* bpp
;
4304 w
= local_rect
.right
- local_rect
.left
;
4305 h
= local_rect
.bottom
- local_rect
.top
;
4307 /* Activate the correct context for the render target */
4308 context
= context_acquire(device
, surface
);
4309 context_apply_blit_state(context
, device
);
4310 gl_info
= context
->gl_info
;
4314 if (!surface_is_offscreen(surface
))
4316 GLenum buffer
= surface_get_gl_buffer(surface
);
4317 TRACE("Unlocking %#x buffer.\n", buffer
);
4318 context_set_draw_buffer(context
, buffer
);
4320 surface_translate_drawable_coords(surface
, context
->win_handle
, &local_rect
);
4321 glPixelZoom(1.0f
, -1.0f
);
4325 /* Primary offscreen render target */
4326 TRACE("Offscreen render target.\n");
4327 context_set_draw_buffer(context
, device
->offscreenBuffer
);
4329 glPixelZoom(1.0f
, 1.0f
);
4332 glRasterPos3i(local_rect
.left
, local_rect
.top
, 1);
4333 checkGLcall("glRasterPos3i");
4335 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4336 glPixelStorei(GL_UNPACK_ROW_LENGTH
, surface
->resource
.width
);
4338 if (surface
->flags
& SFLAG_PBO
)
4340 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
4341 checkGLcall("glBindBufferARB");
4344 glDrawPixels(w
, h
, fmt
, type
, mem
);
4345 checkGLcall("glDrawPixels");
4347 if (surface
->flags
& SFLAG_PBO
)
4349 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4350 checkGLcall("glBindBufferARB");
4353 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
4354 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4358 if (wined3d_settings
.strict_draw_ordering
4359 || (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
4360 && surface
->container
.u
.swapchain
->front_buffer
== surface
))
4363 context_release(context
);
4366 HRESULT
d3dfmt_get_conv(const struct wined3d_surface
*surface
, BOOL need_alpha_ck
,
4367 BOOL use_texturing
, struct wined3d_format
*format
, CONVERT_TYPES
*convert
)
4369 BOOL colorkey_active
= need_alpha_ck
&& (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
4370 const struct wined3d_device
*device
= surface
->resource
.device
;
4371 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4372 BOOL blit_supported
= FALSE
;
4374 /* Copy the default values from the surface. Below we might perform fixups */
4375 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
4376 *format
= *surface
->resource
.format
;
4377 *convert
= NO_CONVERSION
;
4379 /* Ok, now look if we have to do any conversion */
4380 switch (surface
->resource
.format
->id
)
4382 case WINED3DFMT_P8_UINT
:
4383 /* Below the call to blit_supported is disabled for Wine 1.2
4384 * because the function isn't operating correctly yet. At the
4385 * moment 8-bit blits are handled in software and if certain GL
4386 * extensions are around, surface conversion is performed at
4387 * upload time. The blit_supported call recognizes it as a
4388 * destination fixup. This type of upload 'fixup' and 8-bit to
4389 * 8-bit blits need to be handled by the blit_shader.
4390 * TODO: get rid of this #if 0. */
4392 blit_supported
= device
->blitter
->blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4393 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4394 &rect
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
);
4396 blit_supported
= gl_info
->supported
[EXT_PALETTED_TEXTURE
] || gl_info
->supported
[ARB_FRAGMENT_PROGRAM
];
4398 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
4399 * texturing. Further also use conversion in case of color keying.
4400 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
4401 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
4402 * conflicts with this.
4404 if (!((blit_supported
&& device
->fb
.render_targets
&& surface
== device
->fb
.render_targets
[0]))
4405 || colorkey_active
|| !use_texturing
)
4407 format
->glFormat
= GL_RGBA
;
4408 format
->glInternal
= GL_RGBA
;
4409 format
->glType
= GL_UNSIGNED_BYTE
;
4410 format
->conv_byte_count
= 4;
4411 if (colorkey_active
)
4412 *convert
= CONVERT_PALETTED_CK
;
4414 *convert
= CONVERT_PALETTED
;
4418 case WINED3DFMT_B2G3R3_UNORM
:
4419 /* **********************
4420 GL_UNSIGNED_BYTE_3_3_2
4421 ********************** */
4422 if (colorkey_active
) {
4423 /* This texture format will never be used.. So do not care about color keying
4424 up until the point in time it will be needed :-) */
4425 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
4429 case WINED3DFMT_B5G6R5_UNORM
:
4430 if (colorkey_active
)
4432 *convert
= CONVERT_CK_565
;
4433 format
->glFormat
= GL_RGBA
;
4434 format
->glInternal
= GL_RGB5_A1
;
4435 format
->glType
= GL_UNSIGNED_SHORT_5_5_5_1
;
4436 format
->conv_byte_count
= 2;
4440 case WINED3DFMT_B5G5R5X1_UNORM
:
4441 if (colorkey_active
)
4443 *convert
= CONVERT_CK_5551
;
4444 format
->glFormat
= GL_BGRA
;
4445 format
->glInternal
= GL_RGB5_A1
;
4446 format
->glType
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
4447 format
->conv_byte_count
= 2;
4451 case WINED3DFMT_B8G8R8_UNORM
:
4452 if (colorkey_active
)
4454 *convert
= CONVERT_CK_RGB24
;
4455 format
->glFormat
= GL_RGBA
;
4456 format
->glInternal
= GL_RGBA8
;
4457 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
4458 format
->conv_byte_count
= 4;
4462 case WINED3DFMT_B8G8R8X8_UNORM
:
4463 if (colorkey_active
)
4465 *convert
= CONVERT_RGB32_888
;
4466 format
->glFormat
= GL_RGBA
;
4467 format
->glInternal
= GL_RGBA8
;
4468 format
->glType
= GL_UNSIGNED_INT_8_8_8_8
;
4469 format
->conv_byte_count
= 4;
4480 void d3dfmt_p8_init_palette(const struct wined3d_surface
*surface
, BYTE table
[256][4], BOOL colorkey
)
4482 const struct wined3d_device
*device
= surface
->resource
.device
;
4483 const struct wined3d_palette
*pal
= surface
->palette
;
4484 BOOL index_in_alpha
= FALSE
;
4487 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4488 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4489 * is slow. Further RGB->P8 conversion is not possible because palettes can have
4490 * duplicate entries. Store the color key in the unused alpha component to speed the
4491 * download up and to make conversion unneeded. */
4492 index_in_alpha
= primary_render_target_is_p8(device
);
4496 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
4497 if (device
->wined3d
->flags
& WINED3D_PALETTE_PER_SURFACE
)
4499 ERR("This code should never get entered for DirectDraw!, expect problems\n");
4502 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4503 * there's no palette at this time. */
4504 for (i
= 0; i
< 256; i
++) table
[i
][3] = i
;
4509 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
4510 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
4511 * capability flag is present (wine does advertise this capability) */
4512 for (i
= 0; i
< 256; ++i
)
4514 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
4515 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
4516 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
4517 table
[i
][3] = device
->palettes
[device
->currentPalette
][i
].peFlags
;
4523 TRACE("Using surface palette %p\n", pal
);
4524 /* Get the surface's palette */
4525 for (i
= 0; i
< 256; ++i
)
4527 table
[i
][0] = pal
->palents
[i
].peRed
;
4528 table
[i
][1] = pal
->palents
[i
].peGreen
;
4529 table
[i
][2] = pal
->palents
[i
].peBlue
;
4531 /* When index_in_alpha is set the palette index is stored in the
4532 * alpha component. In case of a readback we can then read
4533 * GL_ALPHA. Color keying is handled in BltOverride using a
4534 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4535 * color key itself is passed to glAlphaFunc in other cases the
4536 * alpha component of pixels that should be masked away is set to 0. */
4541 else if (colorkey
&& (i
>= surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4542 && (i
<= surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4546 else if (pal
->flags
& WINEDDPCAPS_ALPHA
)
4548 table
[i
][3] = pal
->palents
[i
].peFlags
;
4558 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
,
4559 UINT height
, UINT outpitch
, CONVERT_TYPES convert
, struct wined3d_surface
*surface
)
4563 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src
, dst
, pitch
, height
, outpitch
, convert
, surface
);
4568 memcpy(dst
, src
, pitch
* height
);
4571 case CONVERT_PALETTED
:
4572 case CONVERT_PALETTED_CK
:
4577 d3dfmt_p8_init_palette(surface
, table
, (convert
== CONVERT_PALETTED_CK
));
4579 for (y
= 0; y
< height
; y
++)
4581 source
= src
+ pitch
* y
;
4582 dest
= dst
+ outpitch
* y
;
4583 /* This is an 1 bpp format, using the width here is fine */
4584 for (x
= 0; x
< width
; x
++) {
4585 BYTE color
= *source
++;
4586 *dest
++ = table
[color
][0];
4587 *dest
++ = table
[color
][1];
4588 *dest
++ = table
[color
][2];
4589 *dest
++ = table
[color
][3];
4595 case CONVERT_CK_565
:
4597 /* Converting the 565 format in 5551 packed to emulate color-keying.
4599 Note : in all these conversion, it would be best to average the averaging
4600 pixels to get the color of the pixel that will be color-keyed to
4601 prevent 'color bleeding'. This will be done later on if ever it is
4604 Note2: Nvidia documents say that their driver does not support alpha + color keying
4605 on the same surface and disables color keying in such a case
4611 TRACE("Color keyed 565\n");
4613 for (y
= 0; y
< height
; y
++) {
4614 Source
= (const WORD
*)(src
+ y
* pitch
);
4615 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4616 for (x
= 0; x
< width
; x
++ ) {
4617 WORD color
= *Source
++;
4618 *Dest
= ((color
& 0xFFC0) | ((color
& 0x1F) << 1));
4619 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4620 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4628 case CONVERT_CK_5551
:
4630 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4634 TRACE("Color keyed 5551\n");
4635 for (y
= 0; y
< height
; y
++) {
4636 Source
= (const WORD
*)(src
+ y
* pitch
);
4637 Dest
= (WORD
*) (dst
+ y
* outpitch
);
4638 for (x
= 0; x
< width
; x
++ ) {
4639 WORD color
= *Source
++;
4641 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4642 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4645 *Dest
&= ~(1 << 15);
4652 case CONVERT_CK_RGB24
:
4654 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4656 for (y
= 0; y
< height
; y
++)
4658 source
= src
+ pitch
* y
;
4659 dest
= dst
+ outpitch
* y
;
4660 for (x
= 0; x
< width
; x
++) {
4661 DWORD color
= ((DWORD
)source
[0] << 16) + ((DWORD
)source
[1] << 8) + (DWORD
)source
[2] ;
4662 DWORD dstcolor
= color
<< 8;
4663 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4664 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4666 *(DWORD
*)dest
= dstcolor
;
4674 case CONVERT_RGB32_888
:
4676 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4678 for (y
= 0; y
< height
; y
++)
4680 source
= src
+ pitch
* y
;
4681 dest
= dst
+ outpitch
* y
;
4682 for (x
= 0; x
< width
; x
++) {
4683 DWORD color
= 0xffffff & *(const DWORD
*)source
;
4684 DWORD dstcolor
= color
<< 8;
4685 if ((color
< surface
->SrcBltCKey
.dwColorSpaceLowValue
)
4686 || (color
> surface
->SrcBltCKey
.dwColorSpaceHighValue
))
4688 *(DWORD
*)dest
= dstcolor
;
4697 ERR("Unsupported conversion type %#x.\n", convert
);
4702 BOOL
palette9_changed(struct wined3d_surface
*surface
)
4704 struct wined3d_device
*device
= surface
->resource
.device
;
4706 if (surface
->palette
|| (surface
->resource
.format
->id
!= WINED3DFMT_P8_UINT
4707 && surface
->resource
.format
->id
!= WINED3DFMT_P8_UINT_A8_UNORM
))
4709 /* If a ddraw-style palette is attached assume no d3d9 palette change.
4710 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
4715 if (surface
->palette9
)
4717 if (!memcmp(surface
->palette9
, device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256))
4724 surface
->palette9
= HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
4726 memcpy(surface
->palette9
, device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256);
4731 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
4733 /* Flip the surface contents */
4738 front
->hDC
= back
->hDC
;
4742 /* Flip the DIBsection */
4745 BOOL hasDib
= front
->flags
& SFLAG_DIBSECTION
;
4746 tmp
= front
->dib
.DIBsection
;
4747 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
4748 back
->dib
.DIBsection
= tmp
;
4750 if (back
->flags
& SFLAG_DIBSECTION
) front
->flags
|= SFLAG_DIBSECTION
;
4751 else front
->flags
&= ~SFLAG_DIBSECTION
;
4752 if (hasDib
) back
->flags
|= SFLAG_DIBSECTION
;
4753 else back
->flags
&= ~SFLAG_DIBSECTION
;
4756 /* Flip the surface data */
4760 tmp
= front
->dib
.bitmap_data
;
4761 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
4762 back
->dib
.bitmap_data
= tmp
;
4764 tmp
= front
->resource
.allocatedMemory
;
4765 front
->resource
.allocatedMemory
= back
->resource
.allocatedMemory
;
4766 back
->resource
.allocatedMemory
= tmp
;
4768 tmp
= front
->resource
.heapMemory
;
4769 front
->resource
.heapMemory
= back
->resource
.heapMemory
;
4770 back
->resource
.heapMemory
= tmp
;
4775 GLuint tmp_pbo
= front
->pbo
;
4776 front
->pbo
= back
->pbo
;
4777 back
->pbo
= tmp_pbo
;
4780 /* client_memory should not be different, but just in case */
4783 tmp
= front
->dib
.client_memory
;
4784 front
->dib
.client_memory
= back
->dib
.client_memory
;
4785 back
->dib
.client_memory
= tmp
;
4788 /* Flip the opengl texture */
4792 tmp
= back
->texture_name
;
4793 back
->texture_name
= front
->texture_name
;
4794 front
->texture_name
= tmp
;
4796 tmp
= back
->texture_name_srgb
;
4797 back
->texture_name_srgb
= front
->texture_name_srgb
;
4798 front
->texture_name_srgb
= tmp
;
4800 tmp
= back
->rb_multisample
;
4801 back
->rb_multisample
= front
->rb_multisample
;
4802 front
->rb_multisample
= tmp
;
4804 tmp
= back
->rb_resolved
;
4805 back
->rb_resolved
= front
->rb_resolved
;
4806 front
->rb_resolved
= tmp
;
4808 resource_unload(&back
->resource
);
4809 resource_unload(&front
->resource
);
4813 DWORD tmp_flags
= back
->flags
;
4814 back
->flags
= front
->flags
;
4815 front
->flags
= tmp_flags
;
4819 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4820 * pixel copy calls. */
4821 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4822 const RECT
*src_rect
, const RECT
*dst_rect_in
, WINED3DTEXTUREFILTERTYPE Filter
)
4824 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4827 struct wined3d_context
*context
;
4828 BOOL upsidedown
= FALSE
;
4829 RECT dst_rect
= *dst_rect_in
;
4831 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4832 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4834 if(dst_rect
.top
> dst_rect
.bottom
) {
4835 UINT tmp
= dst_rect
.bottom
;
4836 dst_rect
.bottom
= dst_rect
.top
;
4841 context
= context_acquire(device
, src_surface
);
4842 context_apply_blit_state(context
, device
);
4843 surface_internal_preload(dst_surface
, SRGB_RGB
);
4846 /* Bind the target texture */
4847 context_bind_texture(context
, dst_surface
->texture_target
, dst_surface
->texture_name
);
4848 if (surface_is_offscreen(src_surface
))
4850 TRACE("Reading from an offscreen target\n");
4851 upsidedown
= !upsidedown
;
4852 glReadBuffer(device
->offscreenBuffer
);
4856 glReadBuffer(surface_get_gl_buffer(src_surface
));
4858 checkGLcall("glReadBuffer");
4860 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
4861 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
4863 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4865 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4867 if(Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
) {
4868 ERR("Texture filtering not supported in direct blit\n");
4871 else if ((Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
)
4872 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4874 ERR("Texture filtering not supported in direct blit\n");
4878 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4879 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
4881 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
4883 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4884 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
4885 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
4886 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
4890 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
4891 /* I have to process this row by row to swap the image,
4892 * otherwise it would be upside down, so stretching in y direction
4893 * doesn't cost extra time
4895 * However, stretching in x direction can be avoided if not necessary
4897 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
4898 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
4900 /* Well, that stuff works, but it's very slow.
4901 * find a better way instead
4905 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
4907 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4908 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
4909 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
4914 glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
4915 dst_rect
.left
/* x offset */, row
/* y offset */,
4916 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
4920 checkGLcall("glCopyTexSubImage2D");
4923 context_release(context
);
4925 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
4926 * path is never entered
4928 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
4931 /* Uses the hardware to stretch and flip the image */
4932 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
4933 const RECT
*src_rect
, const RECT
*dst_rect_in
, WINED3DTEXTUREFILTERTYPE Filter
)
4935 struct wined3d_device
*device
= dst_surface
->resource
.device
;
4936 struct wined3d_swapchain
*src_swapchain
= NULL
;
4937 GLuint src
, backup
= 0;
4938 float left
, right
, top
, bottom
; /* Texture coordinates */
4939 UINT fbwidth
= src_surface
->resource
.width
;
4940 UINT fbheight
= src_surface
->resource
.height
;
4941 struct wined3d_context
*context
;
4942 GLenum drawBuffer
= GL_BACK
;
4943 GLenum texture_target
;
4944 BOOL noBackBufferBackup
;
4946 BOOL upsidedown
= FALSE
;
4947 RECT dst_rect
= *dst_rect_in
;
4949 TRACE("Using hwstretch blit\n");
4950 /* Activate the Proper context for reading from the source surface, set it up for blitting */
4951 context
= context_acquire(device
, src_surface
);
4952 context_apply_blit_state(context
, device
);
4953 surface_internal_preload(dst_surface
, SRGB_RGB
);
4955 src_offscreen
= surface_is_offscreen(src_surface
);
4956 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
4957 if (!noBackBufferBackup
&& !src_surface
->texture_name
)
4959 /* Get it a description */
4960 surface_internal_preload(src_surface
, SRGB_RGB
);
4964 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
4965 * This way we don't have to wait for the 2nd readback to finish to leave this function.
4967 if (context
->aux_buffers
>= 2)
4969 /* Got more than one aux buffer? Use the 2nd aux buffer */
4970 drawBuffer
= GL_AUX1
;
4972 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
4974 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
4975 drawBuffer
= GL_AUX0
;
4978 if(noBackBufferBackup
) {
4979 glGenTextures(1, &backup
);
4980 checkGLcall("glGenTextures");
4981 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
4982 texture_target
= GL_TEXTURE_2D
;
4984 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
4985 * we are reading from the back buffer, the backup can be used as source texture
4987 texture_target
= src_surface
->texture_target
;
4988 context_bind_texture(context
, texture_target
, src_surface
->texture_name
);
4989 glEnable(texture_target
);
4990 checkGLcall("glEnable(texture_target)");
4992 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
4993 src_surface
->flags
&= ~SFLAG_INTEXTURE
;
4996 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4997 * glCopyTexSubImage is a bit picky about the parameters we pass to it
4999 if(dst_rect
.top
> dst_rect
.bottom
) {
5000 UINT tmp
= dst_rect
.bottom
;
5001 dst_rect
.bottom
= dst_rect
.top
;
5008 TRACE("Reading from an offscreen target\n");
5009 upsidedown
= !upsidedown
;
5010 glReadBuffer(device
->offscreenBuffer
);
5014 glReadBuffer(surface_get_gl_buffer(src_surface
));
5017 /* TODO: Only back up the part that will be overwritten */
5018 glCopyTexSubImage2D(texture_target
, 0,
5019 0, 0 /* read offsets */,
5024 checkGLcall("glCopyTexSubImage2D");
5026 /* No issue with overriding these - the sampler is dirty due to blit usage */
5027 glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
5028 wined3d_gl_mag_filter(magLookup
, Filter
));
5029 checkGLcall("glTexParameteri");
5030 glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
5031 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
5032 checkGLcall("glTexParameteri");
5034 if (src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5035 src_swapchain
= src_surface
->container
.u
.swapchain
;
5036 if (!src_swapchain
|| src_surface
== src_swapchain
->back_buffers
[0])
5038 src
= backup
? backup
: src_surface
->texture_name
;
5042 glReadBuffer(GL_FRONT
);
5043 checkGLcall("glReadBuffer(GL_FRONT)");
5045 glGenTextures(1, &src
);
5046 checkGLcall("glGenTextures(1, &src)");
5047 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
5049 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5050 * out for power of 2 sizes
5052 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
5053 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
5054 checkGLcall("glTexImage2D");
5055 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0,
5056 0, 0 /* read offsets */,
5061 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5062 checkGLcall("glTexParameteri");
5063 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5064 checkGLcall("glTexParameteri");
5066 glReadBuffer(GL_BACK
);
5067 checkGLcall("glReadBuffer(GL_BACK)");
5069 if(texture_target
!= GL_TEXTURE_2D
) {
5070 glDisable(texture_target
);
5071 glEnable(GL_TEXTURE_2D
);
5072 texture_target
= GL_TEXTURE_2D
;
5075 checkGLcall("glEnd and previous");
5077 left
= src_rect
->left
;
5078 right
= src_rect
->right
;
5082 top
= src_surface
->resource
.height
- src_rect
->top
;
5083 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
5087 top
= src_surface
->resource
.height
- src_rect
->bottom
;
5088 bottom
= src_surface
->resource
.height
- src_rect
->top
;
5091 if (src_surface
->flags
& SFLAG_NORMCOORD
)
5093 left
/= src_surface
->pow2Width
;
5094 right
/= src_surface
->pow2Width
;
5095 top
/= src_surface
->pow2Height
;
5096 bottom
/= src_surface
->pow2Height
;
5099 /* draw the source texture stretched and upside down. The correct surface is bound already */
5100 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
5101 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
5103 context_set_draw_buffer(context
, drawBuffer
);
5104 glReadBuffer(drawBuffer
);
5108 glTexCoord2f(left
, bottom
);
5112 glTexCoord2f(left
, top
);
5113 glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
5116 glTexCoord2f(right
, top
);
5117 glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
5120 glTexCoord2f(right
, bottom
);
5121 glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
5123 checkGLcall("glEnd and previous");
5125 if (texture_target
!= dst_surface
->texture_target
)
5127 glDisable(texture_target
);
5128 glEnable(dst_surface
->texture_target
);
5129 texture_target
= dst_surface
->texture_target
;
5132 /* Now read the stretched and upside down image into the destination texture */
5133 context_bind_texture(context
, texture_target
, dst_surface
->texture_name
);
5134 glCopyTexSubImage2D(texture_target
,
5136 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
5137 0, 0, /* We blitted the image to the origin */
5138 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
5139 checkGLcall("glCopyTexSubImage2D");
5141 if(drawBuffer
== GL_BACK
) {
5142 /* Write the back buffer backup back */
5144 if(texture_target
!= GL_TEXTURE_2D
) {
5145 glDisable(texture_target
);
5146 glEnable(GL_TEXTURE_2D
);
5147 texture_target
= GL_TEXTURE_2D
;
5149 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
5153 if (texture_target
!= src_surface
->texture_target
)
5155 glDisable(texture_target
);
5156 glEnable(src_surface
->texture_target
);
5157 texture_target
= src_surface
->texture_target
;
5159 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->texture_name
);
5164 glTexCoord2f(0.0f
, 0.0f
);
5165 glVertex2i(0, fbheight
);
5168 glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
5172 glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
5173 (float)fbheight
/ (float)src_surface
->pow2Height
);
5174 glVertex2i(fbwidth
, 0);
5177 glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
5178 glVertex2i(fbwidth
, fbheight
);
5181 glDisable(texture_target
);
5182 checkGLcall("glDisable(texture_target)");
5185 if (src
!= src_surface
->texture_name
&& src
!= backup
)
5187 glDeleteTextures(1, &src
);
5188 checkGLcall("glDeleteTextures(1, &src)");
5191 glDeleteTextures(1, &backup
);
5192 checkGLcall("glDeleteTextures(1, &backup)");
5197 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5199 context_release(context
);
5201 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5202 * path is never entered
5204 surface_modify_location(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
5207 /* Front buffer coordinates are always full screen coordinates, but our GL
5208 * drawable is limited to the window's client area. The sysmem and texture
5209 * copies do have the full screen size. Note that GL has a bottom-left
5210 * origin, while D3D has a top-left origin. */
5211 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
5213 UINT drawable_height
;
5215 if (surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
5216 && surface
== surface
->container
.u
.swapchain
->front_buffer
)
5218 POINT offset
= {0, 0};
5221 ScreenToClient(window
, &offset
);
5222 OffsetRect(rect
, offset
.x
, offset
.y
);
5224 GetClientRect(window
, &windowsize
);
5225 drawable_height
= windowsize
.bottom
- windowsize
.top
;
5229 drawable_height
= surface
->resource
.height
;
5232 rect
->top
= drawable_height
- rect
->top
;
5233 rect
->bottom
= drawable_height
- rect
->bottom
;
5236 static void surface_blt_to_drawable(struct wined3d_device
*device
,
5237 WINED3DTEXTUREFILTERTYPE filter
, BOOL color_key
,
5238 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
5239 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
5241 struct wined3d_context
*context
;
5242 RECT src_rect
, dst_rect
;
5244 src_rect
= *src_rect_in
;
5245 dst_rect
= *dst_rect_in
;
5247 /* Make sure the surface is up-to-date. This should probably use
5248 * surface_load_location() and worry about the destination surface too,
5249 * unless we're overwriting it completely. */
5250 surface_internal_preload(src_surface
, SRGB_RGB
);
5252 /* Activate the destination context, set it up for blitting */
5253 context
= context_acquire(device
, dst_surface
);
5254 context_apply_blit_state(context
, device
);
5256 if (!surface_is_offscreen(dst_surface
))
5257 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
5259 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
5265 glEnable(GL_ALPHA_TEST
);
5266 checkGLcall("glEnable(GL_ALPHA_TEST)");
5268 /* When the primary render target uses P8, the alpha component
5269 * contains the palette index. Which means that the colorkey is one of
5270 * the palette entries. In other cases pixels that should be masked
5271 * away have alpha set to 0. */
5272 if (primary_render_target_is_p8(device
))
5273 glAlphaFunc(GL_NOTEQUAL
, (float)src_surface
->SrcBltCKey
.dwColorSpaceLowValue
/ 256.0f
);
5275 glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
5276 checkGLcall("glAlphaFunc");
5280 glDisable(GL_ALPHA_TEST
);
5281 checkGLcall("glDisable(GL_ALPHA_TEST)");
5284 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
5288 glDisable(GL_ALPHA_TEST
);
5289 checkGLcall("glDisable(GL_ALPHA_TEST)");
5294 /* Leave the opengl state valid for blitting */
5295 device
->blitter
->unset_shader(context
->gl_info
);
5297 if (wined3d_settings
.strict_draw_ordering
5298 || (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
5299 && (dst_surface
->container
.u
.swapchain
->front_buffer
== dst_surface
)))
5300 wglFlush(); /* Flush to ensure ordering across contexts. */
5302 context_release(context
);
5305 /* Do not call while under the GL lock. */
5306 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const WINED3DCOLORVALUE
*color
)
5308 struct wined3d_device
*device
= s
->resource
.device
;
5309 const struct blit_shader
*blitter
;
5311 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
5312 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
5315 FIXME("No blitter is capable of performing the requested color fill operation.\n");
5316 return WINED3DERR_INVALIDCALL
;
5319 return blitter
->color_fill(device
, s
, rect
, color
);
5322 /* Do not call while under the GL lock. */
5323 static HRESULT
IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5324 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
5325 WINED3DTEXTUREFILTERTYPE Filter
)
5327 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5328 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5329 struct wined3d_swapchain
*srcSwapchain
= NULL
, *dstSwapchain
= NULL
;
5331 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5332 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5333 flags
, DDBltFx
, debug_d3dtexturefiltertype(Filter
));
5335 /* Get the swapchain. One of the surfaces has to be a primary surface */
5336 if (dst_surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
5338 WARN("Destination is in sysmem, rejecting gl blt\n");
5339 return WINED3DERR_INVALIDCALL
;
5342 if (dst_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5343 dstSwapchain
= dst_surface
->container
.u
.swapchain
;
5347 if (src_surface
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
)
5349 WARN("Src is in sysmem, rejecting gl blt\n");
5350 return WINED3DERR_INVALIDCALL
;
5353 if (src_surface
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
)
5354 srcSwapchain
= src_surface
->container
.u
.swapchain
;
5357 /* Early sort out of cases where no render target is used */
5358 if (!dstSwapchain
&& !srcSwapchain
5359 && src_surface
!= device
->fb
.render_targets
[0]
5360 && dst_surface
!= device
->fb
.render_targets
[0])
5362 TRACE("No surface is render target, not using hardware blit.\n");
5363 return WINED3DERR_INVALIDCALL
;
5366 /* No destination color keying supported */
5367 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
5369 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5370 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5371 return WINED3DERR_INVALIDCALL
;
5374 if (dstSwapchain
&& dstSwapchain
== srcSwapchain
)
5376 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5377 return WINED3DERR_INVALIDCALL
;
5380 if (dstSwapchain
&& srcSwapchain
)
5382 FIXME("Implement hardware blit between two different swapchains\n");
5383 return WINED3DERR_INVALIDCALL
;
5388 /* Handled with regular texture -> swapchain blit */
5389 if (src_surface
== device
->fb
.render_targets
[0])
5390 TRACE("Blit from active render target to a swapchain\n");
5392 else if (srcSwapchain
&& dst_surface
== device
->fb
.render_targets
[0])
5394 FIXME("Implement blit from a swapchain to the active render target\n");
5395 return WINED3DERR_INVALIDCALL
;
5398 if ((srcSwapchain
|| src_surface
== device
->fb
.render_targets
[0]) && !dstSwapchain
)
5400 /* Blit from render target to texture */
5403 /* P8 read back is not implemented */
5404 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
5405 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
5407 TRACE("P8 read back not supported by frame buffer to texture blit\n");
5408 return WINED3DERR_INVALIDCALL
;
5411 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
5413 TRACE("Color keying not supported by frame buffer to texture blit\n");
5414 return WINED3DERR_INVALIDCALL
;
5415 /* Destination color key is checked above */
5418 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
5423 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5424 * flip the image nor scale it.
5426 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5427 * -> If the app wants a image width an unscaled width, copy it line per line
5428 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5429 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5430 * back buffer. This is slower than reading line per line, thus not used for flipping
5431 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5432 * pixel by pixel. */
5433 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
5434 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
5436 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
5437 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, Filter
);
5439 TRACE("Using hardware stretching to flip / stretch the texture\n");
5440 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, Filter
);
5443 if (!(dst_surface
->flags
& SFLAG_DONOTFREE
))
5445 HeapFree(GetProcessHeap(), 0, dst_surface
->resource
.heapMemory
);
5446 dst_surface
->resource
.allocatedMemory
= NULL
;
5447 dst_surface
->resource
.heapMemory
= NULL
;
5451 dst_surface
->flags
&= ~SFLAG_INSYSMEM
;
5456 else if (src_surface
)
5458 /* Blit from offscreen surface to render target */
5459 DWORD oldCKeyFlags
= src_surface
->CKeyFlags
;
5460 WINEDDCOLORKEY oldBltCKey
= src_surface
->SrcBltCKey
;
5462 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
5464 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5465 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5466 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5468 FIXME("Unsupported blit operation falling back to software\n");
5469 return WINED3DERR_INVALIDCALL
;
5472 /* Color keying: Check if we have to do a color keyed blt,
5473 * and if not check if a color key is activated.
5475 * Just modify the color keying parameters in the surface and restore them afterwards
5476 * The surface keeps track of the color key last used to load the opengl surface.
5477 * PreLoad will catch the change to the flags and color key and reload if necessary.
5479 if (flags
& WINEDDBLT_KEYSRC
)
5481 /* Use color key from surface */
5483 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5485 /* Use color key from DDBltFx */
5486 src_surface
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
5487 src_surface
->SrcBltCKey
= DDBltFx
->ddckSrcColorkey
;
5491 /* Do not use color key */
5492 src_surface
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
5495 surface_blt_to_drawable(device
, Filter
, flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
),
5496 src_surface
, src_rect
, dst_surface
, dst_rect
);
5498 /* Restore the color key parameters */
5499 src_surface
->CKeyFlags
= oldCKeyFlags
;
5500 src_surface
->SrcBltCKey
= oldBltCKey
;
5502 surface_modify_location(dst_surface
, dst_surface
->draw_binding
, TRUE
);
5507 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5508 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5509 return WINED3DERR_INVALIDCALL
;
5512 /* GL locking is done by the caller */
5513 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
5514 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
5516 struct wined3d_device
*device
= surface
->resource
.device
;
5517 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
5518 GLint compare_mode
= GL_NONE
;
5519 struct blt_info info
;
5520 GLint old_binding
= 0;
5523 glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
5525 glDisable(GL_CULL_FACE
);
5526 glDisable(GL_BLEND
);
5527 glDisable(GL_ALPHA_TEST
);
5528 glDisable(GL_SCISSOR_TEST
);
5529 glDisable(GL_STENCIL_TEST
);
5530 glEnable(GL_DEPTH_TEST
);
5531 glDepthFunc(GL_ALWAYS
);
5532 glDepthMask(GL_TRUE
);
5533 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
5534 glViewport(x
, y
, w
, h
);
5536 SetRect(&rect
, 0, h
, w
, 0);
5537 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
5538 context_active_texture(context
, context
->gl_info
, 0);
5539 glGetIntegerv(info
.binding
, &old_binding
);
5540 glBindTexture(info
.bind_target
, texture
);
5541 if (gl_info
->supported
[ARB_SHADOW
])
5543 glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
5544 if (compare_mode
!= GL_NONE
) glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
5547 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
5548 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
5550 glBegin(GL_TRIANGLE_STRIP
);
5551 glTexCoord3fv(info
.coords
[0]);
5552 glVertex2f(-1.0f
, -1.0f
);
5553 glTexCoord3fv(info
.coords
[1]);
5554 glVertex2f(1.0f
, -1.0f
);
5555 glTexCoord3fv(info
.coords
[2]);
5556 glVertex2f(-1.0f
, 1.0f
);
5557 glTexCoord3fv(info
.coords
[3]);
5558 glVertex2f(1.0f
, 1.0f
);
5561 if (compare_mode
!= GL_NONE
) glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
5562 glBindTexture(info
.bind_target
, old_binding
);
5566 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
5569 void surface_modify_ds_location(struct wined3d_surface
*surface
,
5570 DWORD location
, UINT w
, UINT h
)
5572 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
5574 if (location
& ~SFLAG_DS_LOCATIONS
)
5575 FIXME("Invalid location (%#x) specified.\n", location
);
5577 surface
->ds_current_size
.cx
= w
;
5578 surface
->ds_current_size
.cy
= h
;
5579 surface
->flags
&= ~SFLAG_DS_LOCATIONS
;
5580 surface
->flags
|= location
;
5583 /* Context activation is done by the caller. */
5584 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
5586 struct wined3d_device
*device
= surface
->resource
.device
;
5589 TRACE("surface %p, new location %#x.\n", surface
, location
);
5591 /* TODO: Make this work for modes other than FBO */
5592 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
5594 if (!(surface
->flags
& location
))
5596 w
= surface
->ds_current_size
.cx
;
5597 h
= surface
->ds_current_size
.cy
;
5598 surface
->ds_current_size
.cx
= 0;
5599 surface
->ds_current_size
.cy
= 0;
5603 w
= surface
->resource
.width
;
5604 h
= surface
->resource
.height
;
5607 if (surface
->ds_current_size
.cx
== surface
->resource
.width
5608 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
5610 TRACE("Location (%#x) is already up to date.\n", location
);
5614 if (surface
->current_renderbuffer
)
5616 FIXME("Not supported with fixed up depth stencil.\n");
5620 if (!(surface
->flags
& SFLAG_DS_LOCATIONS
))
5622 /* This mostly happens when a depth / stencil is used without being
5623 * cleared first. In principle we could upload from sysmem, or
5624 * explicitly clear before first usage. For the moment there don't
5625 * appear to be a lot of applications depending on this, so a FIXME
5627 FIXME("No up to date depth stencil location.\n");
5628 surface
->flags
|= location
;
5629 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5630 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5634 if (location
== SFLAG_DS_OFFSCREEN
)
5636 GLint old_binding
= 0;
5639 /* The render target is allowed to be smaller than the depth/stencil
5640 * buffer, so the onscreen depth/stencil buffer is potentially smaller
5641 * than the offscreen surface. Don't overwrite the offscreen surface
5642 * with undefined data. */
5643 w
= min(w
, context
->swapchain
->presentParms
.BackBufferWidth
);
5644 h
= min(h
, context
->swapchain
->presentParms
.BackBufferHeight
);
5646 TRACE("Copying onscreen depth buffer to depth texture.\n");
5650 if (!device
->depth_blt_texture
)
5652 glGenTextures(1, &device
->depth_blt_texture
);
5655 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5656 * directly on the FBO texture. That's because we need to flip. */
5657 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5658 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5659 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
5661 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
5662 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
5666 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
5667 bind_target
= GL_TEXTURE_2D
;
5669 glBindTexture(bind_target
, device
->depth_blt_texture
);
5670 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5671 * internal format, because the internal format might include stencil
5672 * data. In principle we should copy stencil data as well, but unless
5673 * the driver supports stencil export it's hard to do, and doesn't
5674 * seem to be needed in practice. If the hardware doesn't support
5675 * writing stencil data, the glCopyTexImage2D() call might trigger
5676 * software fallbacks. */
5677 glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
5678 glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
5679 glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
5680 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
5681 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
5682 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
5683 glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
5684 glBindTexture(bind_target
, old_binding
);
5686 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5687 NULL
, surface
, SFLAG_INTEXTURE
);
5688 context_set_draw_buffer(context
, GL_NONE
);
5689 glReadBuffer(GL_NONE
);
5691 /* Do the actual blit */
5692 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
5693 checkGLcall("depth_blt");
5695 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5699 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5701 else if (location
== SFLAG_DS_ONSCREEN
)
5703 TRACE("Copying depth texture to onscreen depth buffer.\n");
5707 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
5708 context
->swapchain
->front_buffer
, NULL
, SFLAG_INDRAWABLE
);
5709 surface_depth_blt(surface
, context
, surface
->texture_name
,
5710 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
5711 checkGLcall("depth_blt");
5713 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
5717 if (wined3d_settings
.strict_draw_ordering
) wglFlush(); /* Flush to ensure ordering across contexts. */
5721 ERR("Invalid location (%#x) specified.\n", location
);
5724 surface
->flags
|= location
;
5725 surface
->ds_current_size
.cx
= surface
->resource
.width
;
5726 surface
->ds_current_size
.cy
= surface
->resource
.height
;
5729 void surface_modify_location(struct wined3d_surface
*surface
, DWORD location
, BOOL persistent
)
5731 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
5732 struct wined3d_surface
*overlay
;
5734 TRACE("surface %p, location %s, persistent %#x.\n",
5735 surface
, debug_surflocation(location
), persistent
);
5737 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
)
5738 && (location
& SFLAG_INDRAWABLE
))
5739 ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5741 if (location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)
5742 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
5743 location
|= (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
5747 if (((surface
->flags
& SFLAG_INTEXTURE
) && !(location
& SFLAG_INTEXTURE
))
5748 || ((surface
->flags
& SFLAG_INSRGBTEX
) && !(location
& SFLAG_INSRGBTEX
)))
5750 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5752 TRACE("Passing to container.\n");
5753 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5756 surface
->flags
&= ~SFLAG_LOCATIONS
;
5757 surface
->flags
|= location
;
5759 /* Redraw emulated overlays, if any */
5760 if (location
& SFLAG_INDRAWABLE
&& !list_empty(&surface
->overlays
))
5762 LIST_FOR_EACH_ENTRY(overlay
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
5764 overlay
->surface_ops
->surface_draw_overlay(overlay
);
5770 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)) && (location
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)))
5772 if (surface
->container
.type
== WINED3D_CONTAINER_TEXTURE
)
5774 TRACE("Passing to container\n");
5775 wined3d_texture_set_dirty(surface
->container
.u
.texture
, TRUE
);
5778 surface
->flags
&= ~location
;
5781 if (!(surface
->flags
& SFLAG_LOCATIONS
))
5783 ERR("Surface %p does not have any up to date location.\n", surface
);
5787 static DWORD
resource_access_from_location(DWORD location
)
5791 case SFLAG_INSYSMEM
:
5792 return WINED3D_RESOURCE_ACCESS_CPU
;
5794 case SFLAG_INDRAWABLE
:
5795 case SFLAG_INSRGBTEX
:
5796 case SFLAG_INTEXTURE
:
5797 case SFLAG_INRB_MULTISAMPLE
:
5798 case SFLAG_INRB_RESOLVED
:
5799 return WINED3D_RESOURCE_ACCESS_GPU
;
5802 FIXME("Unhandled location %#x.\n", location
);
5807 static void surface_load_sysmem(struct wined3d_surface
*surface
,
5808 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5810 surface_prepare_system_memory(surface
);
5812 /* Download the surface to system memory. */
5813 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
))
5815 struct wined3d_device
*device
= surface
->resource
.device
;
5816 struct wined3d_context
*context
;
5818 /* TODO: Use already acquired context when possible. */
5819 context
= context_acquire(device
, NULL
);
5821 surface_bind_and_dirtify(surface
, context
, !(surface
->flags
& SFLAG_INTEXTURE
));
5822 surface_download_data(surface
, gl_info
);
5824 context_release(context
);
5829 /* Note: It might be faster to download into a texture first. */
5830 read_from_framebuffer(surface
, rect
, surface
->resource
.allocatedMemory
,
5831 wined3d_surface_get_pitch(surface
));
5834 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
5835 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
)
5837 struct wined3d_device
*device
= surface
->resource
.device
;
5838 struct wined3d_format format
;
5839 CONVERT_TYPES convert
;
5843 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
&& surface_is_offscreen(surface
))
5845 ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5846 return WINED3DERR_INVALIDCALL
;
5849 if (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
)
5850 surface_load_location(surface
, SFLAG_INTEXTURE
, NULL
);
5852 if (surface
->flags
& SFLAG_INTEXTURE
)
5856 surface_get_rect(surface
, rect
, &r
);
5857 surface_blt_to_drawable(device
, WINED3DTEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
5862 if ((surface
->flags
& SFLAG_LOCATIONS
) == SFLAG_INSRGBTEX
)
5864 /* This needs colorspace conversion from sRGB to RGB. We take the slow
5865 * path through sysmem. */
5866 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5869 d3dfmt_get_conv(surface
, FALSE
, FALSE
, &format
, &convert
);
5871 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
5872 * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
5874 if ((convert
!= NO_CONVERSION
) && (surface
->flags
& SFLAG_PBO
))
5876 struct wined3d_context
*context
;
5878 TRACE("Removing the pbo attached to surface %p.\n", surface
);
5880 /* TODO: Use already acquired context when possible. */
5881 context
= context_acquire(device
, NULL
);
5883 surface_remove_pbo(surface
, gl_info
);
5885 context_release(context
);
5888 if ((convert
!= NO_CONVERSION
) && surface
->resource
.allocatedMemory
)
5890 UINT height
= surface
->resource
.height
;
5891 UINT width
= surface
->resource
.width
;
5892 UINT src_pitch
, dst_pitch
;
5894 byte_count
= format
.conv_byte_count
;
5895 src_pitch
= wined3d_surface_get_pitch(surface
);
5897 /* Stick to the alignment for the converted surface too, makes it
5898 * easier to load the surface. */
5899 dst_pitch
= width
* byte_count
;
5900 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
5902 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
5904 ERR("Out of memory (%u).\n", dst_pitch
* height
);
5905 return E_OUTOFMEMORY
;
5908 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
,
5909 src_pitch
, width
, height
, dst_pitch
, convert
, surface
);
5911 surface
->flags
|= SFLAG_CONVERTED
;
5915 surface
->flags
&= ~SFLAG_CONVERTED
;
5916 mem
= surface
->resource
.allocatedMemory
;
5917 byte_count
= format
.byte_count
;
5920 flush_to_framebuffer_drawpixels(surface
, rect
, format
.glFormat
, format
.glType
, byte_count
, mem
);
5922 /* Don't delete PBO memory. */
5923 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
5924 HeapFree(GetProcessHeap(), 0, mem
);
5929 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
5930 const struct wined3d_gl_info
*gl_info
, const RECT
*rect
, BOOL srgb
)
5932 const DWORD attach_flags
= WINED3DFMT_FLAG_FBO_ATTACHABLE
| WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
;
5933 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
5934 struct wined3d_device
*device
= surface
->resource
.device
;
5935 struct wined3d_context
*context
;
5936 UINT width
, src_pitch
, dst_pitch
;
5937 struct wined3d_bo_address data
;
5938 struct wined3d_format format
;
5939 POINT dst_point
= {0, 0};
5940 CONVERT_TYPES convert
;
5943 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
5944 && surface_is_offscreen(surface
)
5945 && (surface
->flags
& SFLAG_INDRAWABLE
))
5947 read_from_framebuffer_texture(surface
, srgb
);
5952 if (surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INTEXTURE
)
5953 && (surface
->resource
.format
->flags
& attach_flags
) == attach_flags
5954 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5955 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
5956 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
5959 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, SFLAG_INTEXTURE
,
5960 &src_rect
, surface
, SFLAG_INSRGBTEX
, &src_rect
);
5962 surface_blt_fbo(device
, WINED3DTEXF_POINT
, surface
, SFLAG_INSRGBTEX
,
5963 &src_rect
, surface
, SFLAG_INTEXTURE
, &src_rect
);
5968 /* Upload from system memory */
5970 d3dfmt_get_conv(surface
, TRUE
/* We need color keying */,
5971 TRUE
/* We will use textures */, &format
, &convert
);
5975 if ((surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSYSMEM
)) == SFLAG_INTEXTURE
)
5977 /* Performance warning... */
5978 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
5979 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5984 if ((surface
->flags
& (SFLAG_INSRGBTEX
| SFLAG_INSYSMEM
)) == SFLAG_INSRGBTEX
)
5986 /* Performance warning... */
5987 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
5988 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5992 if (!(surface
->flags
& SFLAG_INSYSMEM
))
5994 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
5995 /* Lets hope we get it from somewhere... */
5996 surface_load_location(surface
, SFLAG_INSYSMEM
, rect
);
5999 /* TODO: Use already acquired context when possible. */
6000 context
= context_acquire(device
, NULL
);
6002 surface_prepare_texture(surface
, context
, srgb
);
6003 surface_bind_and_dirtify(surface
, context
, srgb
);
6005 if (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
)
6007 surface
->flags
|= SFLAG_GLCKEY
;
6008 surface
->glCKey
= surface
->SrcBltCKey
;
6010 else surface
->flags
&= ~SFLAG_GLCKEY
;
6012 width
= surface
->resource
.width
;
6013 src_pitch
= wined3d_surface_get_pitch(surface
);
6015 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6016 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6018 if ((convert
!= NO_CONVERSION
|| format
.convert
) && (surface
->flags
& SFLAG_PBO
))
6020 TRACE("Removing the pbo attached to surface %p.\n", surface
);
6021 surface_remove_pbo(surface
, gl_info
);
6026 /* This code is entered for texture formats which need a fixup. */
6027 UINT height
= surface
->resource
.height
;
6029 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6030 dst_pitch
= width
* format
.conv_byte_count
;
6031 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
6033 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
6035 ERR("Out of memory (%u).\n", dst_pitch
* height
);
6036 context_release(context
);
6037 return E_OUTOFMEMORY
;
6039 format
.convert(surface
->resource
.allocatedMemory
, mem
, src_pitch
, width
, height
);
6041 else if (convert
!= NO_CONVERSION
&& surface
->resource
.allocatedMemory
)
6043 /* This code is only entered for color keying fixups */
6044 UINT height
= surface
->resource
.height
;
6046 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6047 dst_pitch
= width
* format
.conv_byte_count
;
6048 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
6050 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
6052 ERR("Out of memory (%u).\n", dst_pitch
* height
);
6053 context_release(context
);
6054 return E_OUTOFMEMORY
;
6056 d3dfmt_convert_surface(surface
->resource
.allocatedMemory
, mem
, src_pitch
,
6057 width
, height
, dst_pitch
, convert
, surface
);
6061 mem
= surface
->resource
.allocatedMemory
;
6064 data
.buffer_object
= surface
->flags
& SFLAG_PBO
? surface
->pbo
: 0;
6066 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, width
, &dst_point
, srgb
, &data
);
6068 context_release(context
);
6070 /* Don't delete PBO memory. */
6071 if ((mem
!= surface
->resource
.allocatedMemory
) && !(surface
->flags
& SFLAG_PBO
))
6072 HeapFree(GetProcessHeap(), 0, mem
);
6077 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
6079 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
6081 if (!(surface
->flags
& SFLAG_INRB_MULTISAMPLE
))
6082 ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface
);
6084 surface_blt_fbo(surface
->resource
.device
, WINED3DTEXF_POINT
,
6085 surface
, SFLAG_INRB_MULTISAMPLE
, &rect
, surface
, SFLAG_INRB_RESOLVED
, &rect
);
6088 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
, const RECT
*rect
)
6090 struct wined3d_device
*device
= surface
->resource
.device
;
6091 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6094 TRACE("surface %p, location %s, rect %s.\n", surface
, debug_surflocation(location
), wine_dbgstr_rect(rect
));
6096 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
6098 if (location
== SFLAG_INTEXTURE
)
6100 struct wined3d_context
*context
= context_acquire(device
, NULL
);
6101 surface_load_ds_location(surface
, context
, SFLAG_DS_OFFSCREEN
);
6102 context_release(context
);
6107 FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location
));
6108 return WINED3DERR_INVALIDCALL
;
6112 if (location
== SFLAG_INSRGBTEX
&& gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
6113 location
= SFLAG_INTEXTURE
;
6115 if (surface
->flags
& location
)
6117 TRACE("Location already up to date.\n");
6121 if (WARN_ON(d3d_surface
))
6123 DWORD required_access
= resource_access_from_location(location
);
6124 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
6125 WARN("Operation requires %#x access, but surface only has %#x.\n",
6126 required_access
, surface
->resource
.access_flags
);
6129 if (!(surface
->flags
& SFLAG_LOCATIONS
))
6131 ERR("Surface %p does not have any up to date location.\n", surface
);
6132 surface
->flags
|= SFLAG_LOST
;
6133 return WINED3DERR_DEVICELOST
;
6138 case SFLAG_INSYSMEM
:
6139 surface_load_sysmem(surface
, gl_info
, rect
);
6142 case SFLAG_INDRAWABLE
:
6143 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
, rect
)))
6147 case SFLAG_INRB_RESOLVED
:
6148 surface_multisample_resolve(surface
);
6151 case SFLAG_INTEXTURE
:
6152 case SFLAG_INSRGBTEX
:
6153 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, rect
, location
== SFLAG_INSRGBTEX
)))
6158 ERR("Don't know how to handle location %#x.\n", location
);
6164 surface
->flags
|= location
;
6166 if (location
!= SFLAG_INSYSMEM
&& (surface
->flags
& SFLAG_INSYSMEM
))
6167 surface_evict_sysmem(surface
);
6170 if (surface
->flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)
6171 && gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
6173 surface
->flags
|= (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
);
6179 BOOL
surface_is_offscreen(const struct wined3d_surface
*surface
)
6181 struct wined3d_swapchain
*swapchain
= surface
->container
.u
.swapchain
;
6183 /* Not on a swapchain - must be offscreen */
6184 if (surface
->container
.type
!= WINED3D_CONTAINER_SWAPCHAIN
) return TRUE
;
6186 /* The front buffer is always onscreen */
6187 if (surface
== swapchain
->front_buffer
) return FALSE
;
6189 /* If the swapchain is rendered to an FBO, the backbuffer is
6190 * offscreen, otherwise onscreen */
6191 return swapchain
->render_to_fbo
;
6194 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
6195 /* Context activation is done by the caller. */
6196 static void ffp_blit_free(struct wined3d_device
*device
) { }
6198 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6199 /* Context activation is done by the caller. */
6200 static void ffp_blit_p8_upload_palette(const struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
6203 BOOL colorkey_active
= (surface
->CKeyFlags
& WINEDDSD_CKSRCBLT
) ? TRUE
: FALSE
;
6205 d3dfmt_p8_init_palette(surface
, table
, colorkey_active
);
6207 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6209 GL_EXTCALL(glColorTableEXT(surface
->texture_target
, GL_RGBA
, 256, GL_RGBA
, GL_UNSIGNED_BYTE
, table
));
6213 /* Context activation is done by the caller. */
6214 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, struct wined3d_surface
*surface
)
6216 enum complex_fixup fixup
= get_complex_fixup(surface
->resource
.format
->color_fixup
);
6218 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6219 * else the surface is converted in software at upload time in LoadLocation.
6221 if(fixup
== COMPLEX_FIXUP_P8
&& context
->gl_info
->supported
[EXT_PALETTED_TEXTURE
])
6222 ffp_blit_p8_upload_palette(surface
, context
->gl_info
);
6225 glEnable(surface
->texture_target
);
6226 checkGLcall("glEnable(surface->texture_target)");
6231 /* Context activation is done by the caller. */
6232 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
6235 glDisable(GL_TEXTURE_2D
);
6236 checkGLcall("glDisable(GL_TEXTURE_2D)");
6237 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
6239 glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
6240 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6242 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
6244 glDisable(GL_TEXTURE_RECTANGLE_ARB
);
6245 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6250 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
6251 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
6252 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
6254 enum complex_fixup src_fixup
;
6258 case WINED3D_BLIT_OP_COLOR_BLIT
:
6259 if (src_pool
== WINED3DPOOL_SYSTEMMEM
|| dst_pool
== WINED3DPOOL_SYSTEMMEM
)
6262 src_fixup
= get_complex_fixup(src_format
->color_fixup
);
6263 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
6265 TRACE("Checking support for fixup:\n");
6266 dump_color_fixup_desc(src_format
->color_fixup
);
6269 if (!is_identity_fixup(dst_format
->color_fixup
))
6271 TRACE("Destination fixups are not supported\n");
6275 if (src_fixup
== COMPLEX_FIXUP_P8
&& gl_info
->supported
[EXT_PALETTED_TEXTURE
])
6277 TRACE("P8 fixup supported\n");
6281 /* We only support identity conversions. */
6282 if (is_identity_fixup(src_format
->color_fixup
))
6288 TRACE("[FAILED]\n");
6291 case WINED3D_BLIT_OP_COLOR_FILL
:
6292 if (dst_pool
== WINED3DPOOL_SYSTEMMEM
)
6295 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6297 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
6300 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
6302 TRACE("Color fill not supported\n");
6306 /* FIXME: We should reject color fills on formats with fixups,
6307 * but this would break P8 color fills for example. */
6311 case WINED3D_BLIT_OP_DEPTH_FILL
:
6315 TRACE("Unsupported blit_op=%d\n", blit_op
);
6320 /* Do not call while under the GL lock. */
6321 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
6322 const RECT
*dst_rect
, const WINED3DCOLORVALUE
*color
)
6324 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
6325 struct wined3d_fb_state fb
= {&dst_surface
, NULL
};
6327 return device_clear_render_targets(device
, 1, &fb
,
6328 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
6331 /* Do not call while under the GL lock. */
6332 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
,
6333 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
6335 const RECT draw_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
6336 struct wined3d_fb_state fb
= {NULL
, surface
};
6338 return device_clear_render_targets(device
, 0, &fb
,
6339 1, rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
6342 const struct blit_shader ffp_blit
= {
6348 ffp_blit_color_fill
,
6349 ffp_blit_depth_fill
,
6352 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
6357 /* Context activation is done by the caller. */
6358 static void cpu_blit_free(struct wined3d_device
*device
)
6362 /* Context activation is done by the caller. */
6363 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, struct wined3d_surface
*surface
)
6368 /* Context activation is done by the caller. */
6369 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
6373 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
6374 const RECT
*src_rect
, DWORD src_usage
, WINED3DPOOL src_pool
, const struct wined3d_format
*src_format
,
6375 const RECT
*dst_rect
, DWORD dst_usage
, WINED3DPOOL dst_pool
, const struct wined3d_format
*dst_format
)
6377 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
6385 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
6386 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
6387 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
6389 UINT row_block_count
;
6390 const BYTE
*src_row
;
6397 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
6401 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
6403 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
6404 src_row
+= src_pitch
;
6405 dst_row
+= dst_pitch
;
6411 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
6413 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
6417 case WINED3DFMT_DXT1
:
6418 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
6423 BYTE control_row
[4];
6426 const struct block
*s
= (const struct block
*)src_row
;
6427 struct block
*d
= (struct block
*)dst_row
;
6429 for (x
= 0; x
< row_block_count
; ++x
)
6431 d
[x
].color
[0] = s
[x
].color
[0];
6432 d
[x
].color
[1] = s
[x
].color
[1];
6433 d
[x
].control_row
[0] = s
[x
].control_row
[3];
6434 d
[x
].control_row
[1] = s
[x
].control_row
[2];
6435 d
[x
].control_row
[2] = s
[x
].control_row
[1];
6436 d
[x
].control_row
[3] = s
[x
].control_row
[0];
6438 src_row
-= src_pitch
;
6439 dst_row
+= dst_pitch
;
6443 case WINED3DFMT_DXT3
:
6444 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
6450 BYTE control_row
[4];
6453 const struct block
*s
= (const struct block
*)src_row
;
6454 struct block
*d
= (struct block
*)dst_row
;
6456 for (x
= 0; x
< row_block_count
; ++x
)
6458 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
6459 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
6460 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
6461 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
6462 d
[x
].color
[0] = s
[x
].color
[0];
6463 d
[x
].color
[1] = s
[x
].color
[1];
6464 d
[x
].control_row
[0] = s
[x
].control_row
[3];
6465 d
[x
].control_row
[1] = s
[x
].control_row
[2];
6466 d
[x
].control_row
[2] = s
[x
].control_row
[1];
6467 d
[x
].control_row
[3] = s
[x
].control_row
[0];
6469 src_row
-= src_pitch
;
6470 dst_row
+= dst_pitch
;
6475 FIXME("Compressed flip not implemented for format %s.\n",
6476 debug_d3dformat(format
->id
));
6481 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
6482 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
6487 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
6488 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
6489 const WINEDDBLTFX
*fx
, WINED3DTEXTUREFILTERTYPE filter
)
6491 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
6492 const struct wined3d_format
*src_format
, *dst_format
;
6493 struct wined3d_surface
*orig_src
= src_surface
;
6494 WINED3DLOCKED_RECT dlock
, slock
;
6495 HRESULT hr
= WINED3D_OK
;
6501 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6502 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
6503 flags
, fx
, debug_d3dtexturefiltertype(filter
));
6513 full_rect
.right
= dst_surface
->resource
.width
;
6514 full_rect
.bottom
= dst_surface
->resource
.height
;
6515 IntersectRect(&xdst
, &full_rect
, dst_rect
);
6519 BOOL clip_horiz
, clip_vert
;
6522 clip_horiz
= xdst
.left
< 0 || xdst
.right
> (int)dst_surface
->resource
.width
;
6523 clip_vert
= xdst
.top
< 0 || xdst
.bottom
> (int)dst_surface
->resource
.height
;
6525 if (clip_vert
|| clip_horiz
)
6527 /* Now check if this is a special case or not... */
6528 if ((flags
& WINEDDBLT_DDFX
)
6529 || (clip_horiz
&& xdst
.right
- xdst
.left
!= xsrc
.right
- xsrc
.left
)
6530 || (clip_vert
&& xdst
.bottom
- xdst
.top
!= xsrc
.bottom
- xsrc
.top
))
6532 WARN("Out of screen rectangle in special case. Not handled right now.\n");
6540 xsrc
.left
-= xdst
.left
;
6543 if (xdst
.right
> dst_surface
->resource
.width
)
6545 xsrc
.right
-= (xdst
.right
- (int)dst_surface
->resource
.width
);
6546 xdst
.right
= (int)dst_surface
->resource
.width
;
6554 xsrc
.top
-= xdst
.top
;
6557 if (xdst
.bottom
> dst_surface
->resource
.height
)
6559 xsrc
.bottom
-= (xdst
.bottom
- (int)dst_surface
->resource
.height
);
6560 xdst
.bottom
= (int)dst_surface
->resource
.height
;
6564 /* And check if after clipping something is still to be done... */
6565 if ((xdst
.right
<= 0) || (xdst
.bottom
<= 0)
6566 || (xdst
.left
>= (int)dst_surface
->resource
.width
)
6567 || (xdst
.top
>= (int)dst_surface
->resource
.height
)
6568 || (xsrc
.right
<= 0) || (xsrc
.bottom
<= 0)
6569 || (xsrc
.left
>= (int)src_surface
->resource
.width
)
6570 || (xsrc
.top
>= (int)src_surface
->resource
.height
))
6572 TRACE("Nothing to be done after clipping.\n");
6578 if (src_surface
== dst_surface
)
6580 wined3d_surface_map(dst_surface
, &dlock
, NULL
, 0);
6582 src_format
= dst_surface
->resource
.format
;
6583 dst_format
= src_format
;
6587 dst_format
= dst_surface
->resource
.format
;
6590 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
6592 src_surface
= surface_convert_format(src_surface
, dst_format
->id
);
6595 /* The conv function writes a FIXME */
6596 WARN("Cannot convert source surface format to dest format.\n");
6600 wined3d_surface_map(src_surface
, &slock
, NULL
, WINED3DLOCK_READONLY
);
6601 src_format
= src_surface
->resource
.format
;
6605 src_format
= dst_format
;
6608 wined3d_surface_map(dst_surface
, &dlock
, &xdst
, 0);
6610 wined3d_surface_map(dst_surface
, &dlock
, NULL
, 0);
6613 bpp
= dst_surface
->resource
.format
->byte_count
;
6614 srcheight
= xsrc
.bottom
- xsrc
.top
;
6615 srcwidth
= xsrc
.right
- xsrc
.left
;
6616 dstheight
= xdst
.bottom
- xdst
.top
;
6617 dstwidth
= xdst
.right
- xdst
.left
;
6618 width
= (xdst
.right
- xdst
.left
) * bpp
;
6620 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
6622 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
6624 if (src_surface
== dst_surface
)
6626 FIXME("Only plain blits supported on compressed surfaces.\n");
6631 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
6633 WARN("Stretching not supported on compressed surfaces.\n");
6634 hr
= WINED3DERR_INVALIDCALL
;
6638 if (srcwidth
& (src_format
->block_width
- 1) || srcheight
& (src_format
->block_height
- 1))
6640 WARN("Rectangle not block-aligned.\n");
6641 hr
= WINED3DERR_INVALIDCALL
;
6645 hr
= surface_cpu_blt_compressed(slock
.pBits
, dlock
.pBits
,
6646 slock
.Pitch
, dlock
.Pitch
, dstwidth
, dstheight
,
6647 src_format
, flags
, fx
);
6651 if (dst_rect
&& src_surface
!= dst_surface
)
6654 dbuf
= (BYTE
*)dlock
.pBits
+(xdst
.top
*dlock
.Pitch
)+(xdst
.left
*bpp
);
6656 /* First, all the 'source-less' blits */
6657 if (flags
& WINEDDBLT_COLORFILL
)
6659 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dlock
.Pitch
, fx
->u5
.dwFillColor
);
6660 flags
&= ~WINEDDBLT_COLORFILL
;
6663 if (flags
& WINEDDBLT_DEPTHFILL
)
6665 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6667 if (flags
& WINEDDBLT_ROP
)
6669 /* Catch some degenerate cases here. */
6673 hr
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,0);
6675 case 0xAA0029: /* No-op */
6678 hr
= _Blt_ColorFill(dbuf
,dstwidth
,dstheight
,bpp
,dlock
.Pitch
,~0);
6680 case SRCCOPY
: /* Well, we do that below? */
6683 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
6686 flags
&= ~WINEDDBLT_ROP
;
6688 if (flags
& WINEDDBLT_DDROPS
)
6690 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
6692 /* Now the 'with source' blits. */
6696 int sx
, xinc
, sy
, yinc
;
6698 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
6701 if (filter
!= WINED3DTEXF_NONE
&& filter
!= WINED3DTEXF_POINT
6702 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
6704 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6705 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
6708 sbase
= (BYTE
*)slock
.pBits
+(xsrc
.top
*slock
.Pitch
)+xsrc
.left
*bpp
;
6709 xinc
= (srcwidth
<< 16) / dstwidth
;
6710 yinc
= (srcheight
<< 16) / dstheight
;
6714 /* No effects, we can cheat here. */
6715 if (dstwidth
== srcwidth
)
6717 if (dstheight
== srcheight
)
6719 /* No stretching in either direction. This needs to be as
6720 * fast as possible. */
6723 /* Check for overlapping surfaces. */
6724 if (src_surface
!= dst_surface
|| xdst
.top
< xsrc
.top
6725 || xdst
.right
<= xsrc
.left
|| xsrc
.right
<= xdst
.left
)
6727 /* No overlap, or dst above src, so copy from top downwards. */
6728 for (y
= 0; y
< dstheight
; ++y
)
6730 memcpy(dbuf
, sbuf
, width
);
6731 sbuf
+= slock
.Pitch
;
6732 dbuf
+= dlock
.Pitch
;
6735 else if (xdst
.top
> xsrc
.top
)
6737 /* Copy from bottom upwards. */
6738 sbuf
+= (slock
.Pitch
*dstheight
);
6739 dbuf
+= (dlock
.Pitch
*dstheight
);
6740 for (y
= 0; y
< dstheight
; ++y
)
6742 sbuf
-= slock
.Pitch
;
6743 dbuf
-= dlock
.Pitch
;
6744 memcpy(dbuf
, sbuf
, width
);
6749 /* Src and dst overlapping on the same line, use memmove. */
6750 for (y
= 0; y
< dstheight
; ++y
)
6752 memmove(dbuf
, sbuf
, width
);
6753 sbuf
+= slock
.Pitch
;
6754 dbuf
+= dlock
.Pitch
;
6760 /* Stretching in y direction only. */
6761 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6763 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
6764 memcpy(dbuf
, sbuf
, width
);
6765 dbuf
+= dlock
.Pitch
;
6771 /* Stretching in X direction. */
6773 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6775 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
6777 if ((sy
>> 16) == (last_sy
>> 16))
6779 /* This source row is the same as last source row -
6780 * Copy the already stretched row. */
6781 memcpy(dbuf
, dbuf
- dlock
.Pitch
, width
);
6785 #define STRETCH_ROW(type) \
6787 const type *s = (const type *)sbuf; \
6788 type *d = (type *)dbuf; \
6789 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6790 d[x] = s[sx >> 16]; \
6808 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
6812 s
= sbuf
+ 3 * (sx
>> 16);
6813 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
6814 d
[0] = (pixel
) & 0xff;
6815 d
[1] = (pixel
>> 8) & 0xff;
6816 d
[2] = (pixel
>> 16) & 0xff;
6822 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
6823 hr
= WINED3DERR_NOTAVAILABLE
;
6828 dbuf
+= dlock
.Pitch
;
6835 LONG dstyinc
= dlock
.Pitch
, dstxinc
= bpp
;
6836 DWORD keylow
= 0xFFFFFFFF, keyhigh
= 0, keymask
= 0xFFFFFFFF;
6837 DWORD destkeylow
= 0x0, destkeyhigh
= 0xFFFFFFFF, destkeymask
= 0xFFFFFFFF;
6838 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
6840 /* The color keying flags are checked for correctness in ddraw */
6841 if (flags
& WINEDDBLT_KEYSRC
)
6843 keylow
= src_surface
->SrcBltCKey
.dwColorSpaceLowValue
;
6844 keyhigh
= src_surface
->SrcBltCKey
.dwColorSpaceHighValue
;
6846 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
6848 keylow
= fx
->ddckSrcColorkey
.dwColorSpaceLowValue
;
6849 keyhigh
= fx
->ddckSrcColorkey
.dwColorSpaceHighValue
;
6852 if (flags
& WINEDDBLT_KEYDEST
)
6854 /* Destination color keys are taken from the source surface! */
6855 destkeylow
= src_surface
->DestBltCKey
.dwColorSpaceLowValue
;
6856 destkeyhigh
= src_surface
->DestBltCKey
.dwColorSpaceHighValue
;
6858 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
6860 destkeylow
= fx
->ddckDestColorkey
.dwColorSpaceLowValue
;
6861 destkeyhigh
= fx
->ddckDestColorkey
.dwColorSpaceHighValue
;
6870 keymask
= src_format
->red_mask
6871 | src_format
->green_mask
6872 | src_format
->blue_mask
;
6874 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
6877 if (flags
& WINEDDBLT_DDFX
)
6879 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
6882 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
6883 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dlock
.Pitch
);
6884 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
6886 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
6888 /* I don't think we need to do anything about this flag */
6889 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6891 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
6894 dTopRight
= dTopLeft
;
6897 dBottomRight
= dBottomLeft
;
6899 dstxinc
= dstxinc
* -1;
6901 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
6904 dTopLeft
= dBottomLeft
;
6907 dTopRight
= dBottomRight
;
6909 dstyinc
= dstyinc
* -1;
6911 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
6913 /* I don't think we need to do anything about this flag */
6914 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
6916 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
6919 dBottomRight
= dTopLeft
;
6922 dBottomLeft
= dTopRight
;
6924 dstxinc
= dstxinc
* -1;
6925 dstyinc
= dstyinc
* -1;
6927 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
6930 dTopLeft
= dBottomLeft
;
6931 dBottomLeft
= dBottomRight
;
6932 dBottomRight
= dTopRight
;
6937 dstxinc
= dstxinc
* -1;
6939 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
6942 dTopLeft
= dTopRight
;
6943 dTopRight
= dBottomRight
;
6944 dBottomRight
= dBottomLeft
;
6949 dstyinc
= dstyinc
* -1;
6951 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
6953 /* I don't think we need to do anything about this flag */
6954 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
6957 flags
&= ~(WINEDDBLT_DDFX
);
6960 #define COPY_COLORKEY_FX(type) \
6963 type *d = (type *)dbuf, *dx, tmp; \
6964 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
6966 s = (const type *)(sbase + (sy >> 16) * slock.Pitch); \
6968 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6970 tmp = s[sx >> 16]; \
6971 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
6972 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
6976 dx = (type *)(((BYTE *)dx) + dstxinc); \
6978 d = (type *)(((BYTE *)d) + dstyinc); \
6985 COPY_COLORKEY_FX(BYTE
);
6988 COPY_COLORKEY_FX(WORD
);
6991 COPY_COLORKEY_FX(DWORD
);
6996 BYTE
*d
= dbuf
, *dx
;
6997 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
6999 sbuf
= sbase
+ (sy
>> 16) * slock
.Pitch
;
7001 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
7003 DWORD pixel
, dpixel
= 0;
7004 s
= sbuf
+ 3 * (sx
>>16);
7005 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
7006 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
7007 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
7008 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
7010 dx
[0] = (pixel
) & 0xff;
7011 dx
[1] = (pixel
>> 8) & 0xff;
7012 dx
[2] = (pixel
>> 16) & 0xff;
7021 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7022 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
7023 hr
= WINED3DERR_NOTAVAILABLE
;
7025 #undef COPY_COLORKEY_FX
7031 if (flags
&& FIXME_ON(d3d_surface
))
7033 FIXME("\tUnsupported flags: %#x.\n", flags
);
7037 wined3d_surface_unmap(dst_surface
);
7038 if (src_surface
&& src_surface
!= dst_surface
)
7039 wined3d_surface_unmap(src_surface
);
7040 /* Release the converted surface, if any. */
7041 if (src_surface
&& src_surface
!= orig_src
)
7042 wined3d_surface_decref(src_surface
);
7047 /* Do not call while under the GL lock. */
7048 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
7049 const RECT
*dst_rect
, const WINED3DCOLORVALUE
*color
)
7051 static const RECT src_rect
;
7054 memset(&BltFx
, 0, sizeof(BltFx
));
7055 BltFx
.dwSize
= sizeof(BltFx
);
7056 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
7057 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
7058 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
7061 /* Do not call while under the GL lock. */
7062 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
7063 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
7065 FIXME("Depth filling not implemented by cpu_blit.\n");
7066 return WINED3DERR_INVALIDCALL
;
7069 const struct blit_shader cpu_blit
= {
7075 cpu_blit_color_fill
,
7076 cpu_blit_depth_fill
,
7079 static HRESULT
surface_init(struct wined3d_surface
*surface
, WINED3DSURFTYPE surface_type
, UINT alignment
,
7080 UINT width
, UINT height
, UINT level
, BOOL lockable
, BOOL discard
, WINED3DMULTISAMPLE_TYPE multisample_type
,
7081 UINT multisample_quality
, struct wined3d_device
*device
, DWORD usage
, enum wined3d_format_id format_id
,
7082 WINED3DPOOL pool
, void *parent
, const struct wined3d_parent_ops
*parent_ops
)
7084 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
7085 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, format_id
);
7086 unsigned int resource_size
;
7089 if (multisample_quality
> 0)
7091 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
7092 multisample_quality
= 0;
7095 /* Quick lockable sanity check.
7096 * TODO: remove this after surfaces, usage and lockability have been debugged properly
7097 * this function is too deep to need to care about things like this.
7098 * Levels need to be checked too, since they all affect what can be done. */
7101 case WINED3DPOOL_SCRATCH
:
7104 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7105 "which are mutually exclusive, setting lockable to TRUE.\n");
7110 case WINED3DPOOL_SYSTEMMEM
:
7112 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7115 case WINED3DPOOL_MANAGED
:
7116 if (usage
& WINED3DUSAGE_DYNAMIC
)
7117 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7120 case WINED3DPOOL_DEFAULT
:
7121 if (lockable
&& !(usage
& (WINED3DUSAGE_DYNAMIC
| WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
7122 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7126 FIXME("Unknown pool %#x.\n", pool
);
7130 if (usage
& WINED3DUSAGE_RENDERTARGET
&& pool
!= WINED3DPOOL_DEFAULT
)
7131 FIXME("Trying to create a render target that isn't in the default pool.\n");
7133 /* FIXME: Check that the format is supported by the device. */
7135 resource_size
= wined3d_format_calculate_size(format
, alignment
, width
, height
);
7137 return WINED3DERR_INVALIDCALL
;
7139 surface
->surface_type
= surface_type
;
7141 switch (surface_type
)
7143 case SURFACE_OPENGL
:
7144 surface
->surface_ops
= &surface_ops
;
7148 surface
->surface_ops
= &gdi_surface_ops
;
7152 ERR("Requested unknown surface implementation %#x.\n", surface_type
);
7153 return WINED3DERR_INVALIDCALL
;
7156 hr
= resource_init(&surface
->resource
, device
, WINED3DRTYPE_SURFACE
, format
,
7157 multisample_type
, multisample_quality
, usage
, pool
, width
, height
, 1,
7158 resource_size
, parent
, parent_ops
, &surface_resource_ops
);
7161 WARN("Failed to initialize resource, returning %#x.\n", hr
);
7165 /* "Standalone" surface. */
7166 surface_set_container(surface
, WINED3D_CONTAINER_NONE
, NULL
);
7168 surface
->texture_level
= level
;
7169 list_init(&surface
->overlays
);
7172 surface
->flags
= SFLAG_NORMCOORD
; /* Default to normalized coords. */
7174 surface
->flags
|= SFLAG_DISCARD
;
7175 if (lockable
|| format_id
== WINED3DFMT_D16_LOCKABLE
)
7176 surface
->flags
|= SFLAG_LOCKABLE
;
7177 /* I'm not sure if this qualifies as a hack or as an optimization. It
7178 * seems reasonable to assume that lockable render targets will get
7179 * locked, so we might as well set SFLAG_DYNLOCK right at surface
7180 * creation. However, the other reason we want to do this is that several
7181 * ddraw applications access surface memory while the surface isn't
7182 * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7183 * future locks prevents these from crashing. */
7184 if (lockable
&& (usage
& WINED3DUSAGE_RENDERTARGET
))
7185 surface
->flags
|= SFLAG_DYNLOCK
;
7187 /* Mark the texture as dirty so that it gets loaded first time around. */
7188 surface_add_dirty_rect(surface
, NULL
);
7189 list_init(&surface
->renderbuffers
);
7191 TRACE("surface %p, memory %p, size %u\n",
7192 surface
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
7194 /* Call the private setup routine */
7195 hr
= surface
->surface_ops
->surface_private_setup(surface
);
7198 ERR("Private setup failed, returning %#x\n", hr
);
7199 surface
->surface_ops
->surface_cleanup(surface
);
7206 HRESULT CDECL
wined3d_surface_create(struct wined3d_device
*device
, UINT width
, UINT height
,
7207 enum wined3d_format_id format_id
, BOOL lockable
, BOOL discard
, UINT level
, DWORD usage
, WINED3DPOOL pool
,
7208 WINED3DMULTISAMPLE_TYPE multisample_type
, DWORD multisample_quality
, WINED3DSURFTYPE surface_type
,
7209 void *parent
, const struct wined3d_parent_ops
*parent_ops
, struct wined3d_surface
**surface
)
7211 struct wined3d_surface
*object
;
7214 TRACE("device %p, width %u, height %u, format %s, lockable %#x, discard %#x, level %u\n",
7215 device
, width
, height
, debug_d3dformat(format_id
), lockable
, discard
, level
);
7216 TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7217 surface
, debug_d3dusage(usage
), usage
, debug_d3dpool(pool
), multisample_type
, multisample_quality
);
7218 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", surface_type
, parent
, parent_ops
);
7220 if (surface_type
== SURFACE_OPENGL
&& !device
->adapter
)
7222 ERR("OpenGL surfaces are not available without OpenGL.\n");
7223 return WINED3DERR_NOTAVAILABLE
;
7226 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
7229 ERR("Failed to allocate surface memory.\n");
7230 return WINED3DERR_OUTOFVIDEOMEMORY
;
7233 hr
= surface_init(object
, surface_type
, device
->surface_alignment
, width
, height
, level
, lockable
,
7234 discard
, multisample_type
, multisample_quality
, device
, usage
, format_id
, pool
, parent
, parent_ops
);
7237 WARN("Failed to initialize surface, returning %#x.\n", hr
);
7238 HeapFree(GetProcessHeap(), 0, object
);
7242 TRACE("Created surface %p.\n", object
);