2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2002-2003 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2011, 2013-2014 Stefan Dösinger for CodeWeavers
10 * Copyright 2007-2008 Henri Verbeet
11 * Copyright 2006-2008 Roderick Colenbrander
12 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
34 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d
);
37 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
39 static const DWORD surface_simple_locations
=
40 WINED3D_LOCATION_SYSMEM
| WINED3D_LOCATION_USER_MEMORY
41 | WINED3D_LOCATION_DIB
| WINED3D_LOCATION_BUFFER
;
43 static void surface_cleanup(struct wined3d_surface
*surface
)
45 struct wined3d_surface
*overlay
, *cur
;
47 TRACE("surface %p.\n", surface
);
49 if (surface
->pbo
|| surface
->rb_multisample
50 || surface
->rb_resolved
|| !list_empty(&surface
->renderbuffers
))
52 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
53 const struct wined3d_gl_info
*gl_info
;
54 struct wined3d_context
*context
;
56 context
= context_acquire(surface
->resource
.device
, NULL
);
57 gl_info
= context
->gl_info
;
61 TRACE("Deleting PBO %u.\n", surface
->pbo
);
62 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
65 if (surface
->rb_multisample
)
67 TRACE("Deleting multisample renderbuffer %u.\n", surface
->rb_multisample
);
68 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
71 if (surface
->rb_resolved
)
73 TRACE("Deleting resolved renderbuffer %u.\n", surface
->rb_resolved
);
74 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
77 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
79 TRACE("Deleting renderbuffer %u.\n", entry
->id
);
80 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
81 HeapFree(GetProcessHeap(), 0, entry
);
84 context_release(context
);
87 if (surface
->flags
& SFLAG_DIBSECTION
)
89 DeleteDC(surface
->hDC
);
90 DeleteObject(surface
->dib
.DIBsection
);
91 surface
->dib
.bitmap_data
= NULL
;
94 if (surface
->overlay_dest
)
95 list_remove(&surface
->overlay_entry
);
97 LIST_FOR_EACH_ENTRY_SAFE(overlay
, cur
, &surface
->overlays
, struct wined3d_surface
, overlay_entry
)
99 list_remove(&overlay
->overlay_entry
);
100 overlay
->overlay_dest
= NULL
;
103 resource_cleanup(&surface
->resource
);
106 void wined3d_surface_destroy(struct wined3d_surface
*surface
)
108 TRACE("surface %p.\n", surface
);
110 surface_cleanup(surface
);
111 surface
->resource
.parent_ops
->wined3d_object_destroyed(surface
->resource
.parent
);
112 HeapFree(GetProcessHeap(), 0, surface
);
115 void surface_get_drawable_size(const struct wined3d_surface
*surface
, const struct wined3d_context
*context
,
116 unsigned int *width
, unsigned int *height
)
118 if (surface
->container
->swapchain
)
120 /* The drawable size of an onscreen drawable is the surface size.
121 * (Actually: The window size, but the surface is created in window
123 *width
= context
->current_rt
->resource
.width
;
124 *height
= context
->current_rt
->resource
.height
;
126 else if (wined3d_settings
.offscreen_rendering_mode
== ORM_BACKBUFFER
)
128 const struct wined3d_swapchain
*swapchain
= context
->swapchain
;
130 /* The drawable size of a backbuffer / aux buffer offscreen target is
131 * the size of the current context's drawable, which is the size of
132 * the back buffer of the swapchain the active context belongs to. */
133 *width
= swapchain
->desc
.backbuffer_width
;
134 *height
= swapchain
->desc
.backbuffer_height
;
138 /* The drawable size of an FBO target is the OpenGL texture size,
139 * which is the power of two size. */
140 *width
= context
->current_rt
->pow2Width
;
141 *height
= context
->current_rt
->pow2Height
;
149 enum tex_types tex_type
;
150 GLfloat coords
[4][3];
161 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
163 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
164 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
165 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
166 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
169 static void surface_get_blt_info(GLenum target
, const RECT
*rect
, GLsizei w
, GLsizei h
, struct blt_info
*info
)
171 GLfloat (*coords
)[3] = info
->coords
;
177 FIXME("Unsupported texture target %#x\n", target
);
178 /* Fall back to GL_TEXTURE_2D */
180 info
->binding
= GL_TEXTURE_BINDING_2D
;
181 info
->bind_target
= GL_TEXTURE_2D
;
182 info
->tex_type
= tex_2d
;
183 coords
[0][0] = (float)rect
->left
/ w
;
184 coords
[0][1] = (float)rect
->top
/ h
;
187 coords
[1][0] = (float)rect
->right
/ w
;
188 coords
[1][1] = (float)rect
->top
/ h
;
191 coords
[2][0] = (float)rect
->left
/ w
;
192 coords
[2][1] = (float)rect
->bottom
/ h
;
195 coords
[3][0] = (float)rect
->right
/ w
;
196 coords
[3][1] = (float)rect
->bottom
/ h
;
200 case GL_TEXTURE_RECTANGLE_ARB
:
201 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
202 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
203 info
->tex_type
= tex_rect
;
204 coords
[0][0] = rect
->left
; coords
[0][1] = rect
->top
; coords
[0][2] = 0.0f
;
205 coords
[1][0] = rect
->right
; coords
[1][1] = rect
->top
; coords
[1][2] = 0.0f
;
206 coords
[2][0] = rect
->left
; coords
[2][1] = rect
->bottom
; coords
[2][2] = 0.0f
;
207 coords
[3][0] = rect
->right
; coords
[3][1] = rect
->bottom
; coords
[3][2] = 0.0f
;
210 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
211 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
212 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
213 info
->tex_type
= tex_cube
;
214 cube_coords_float(rect
, w
, h
, &f
);
216 coords
[0][0] = 1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = -f
.l
;
217 coords
[1][0] = 1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = -f
.r
;
218 coords
[2][0] = 1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = -f
.l
;
219 coords
[3][0] = 1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = -f
.r
;
222 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
223 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
224 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
225 info
->tex_type
= tex_cube
;
226 cube_coords_float(rect
, w
, h
, &f
);
228 coords
[0][0] = -1.0f
; coords
[0][1] = -f
.t
; coords
[0][2] = f
.l
;
229 coords
[1][0] = -1.0f
; coords
[1][1] = -f
.t
; coords
[1][2] = f
.r
;
230 coords
[2][0] = -1.0f
; coords
[2][1] = -f
.b
; coords
[2][2] = f
.l
;
231 coords
[3][0] = -1.0f
; coords
[3][1] = -f
.b
; coords
[3][2] = f
.r
;
234 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
235 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
236 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
237 info
->tex_type
= tex_cube
;
238 cube_coords_float(rect
, w
, h
, &f
);
240 coords
[0][0] = f
.l
; coords
[0][1] = 1.0f
; coords
[0][2] = f
.t
;
241 coords
[1][0] = f
.r
; coords
[1][1] = 1.0f
; coords
[1][2] = f
.t
;
242 coords
[2][0] = f
.l
; coords
[2][1] = 1.0f
; coords
[2][2] = f
.b
;
243 coords
[3][0] = f
.r
; coords
[3][1] = 1.0f
; coords
[3][2] = f
.b
;
246 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
247 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
248 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
249 info
->tex_type
= tex_cube
;
250 cube_coords_float(rect
, w
, h
, &f
);
252 coords
[0][0] = f
.l
; coords
[0][1] = -1.0f
; coords
[0][2] = -f
.t
;
253 coords
[1][0] = f
.r
; coords
[1][1] = -1.0f
; coords
[1][2] = -f
.t
;
254 coords
[2][0] = f
.l
; coords
[2][1] = -1.0f
; coords
[2][2] = -f
.b
;
255 coords
[3][0] = f
.r
; coords
[3][1] = -1.0f
; coords
[3][2] = -f
.b
;
258 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
259 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
260 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
261 info
->tex_type
= tex_cube
;
262 cube_coords_float(rect
, w
, h
, &f
);
264 coords
[0][0] = f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = 1.0f
;
265 coords
[1][0] = f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = 1.0f
;
266 coords
[2][0] = f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = 1.0f
;
267 coords
[3][0] = f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = 1.0f
;
270 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
271 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
272 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
273 info
->tex_type
= tex_cube
;
274 cube_coords_float(rect
, w
, h
, &f
);
276 coords
[0][0] = -f
.l
; coords
[0][1] = -f
.t
; coords
[0][2] = -1.0f
;
277 coords
[1][0] = -f
.r
; coords
[1][1] = -f
.t
; coords
[1][2] = -1.0f
;
278 coords
[2][0] = -f
.l
; coords
[2][1] = -f
.b
; coords
[2][2] = -1.0f
;
279 coords
[3][0] = -f
.r
; coords
[3][1] = -f
.b
; coords
[3][2] = -1.0f
;
284 static void surface_get_rect(const struct wined3d_surface
*surface
, const RECT
*rect_in
, RECT
*rect_out
)
287 *rect_out
= *rect_in
;
292 rect_out
->right
= surface
->resource
.width
;
293 rect_out
->bottom
= surface
->resource
.height
;
297 /* Context activation is done by the caller. */
298 void draw_textured_quad(const struct wined3d_surface
*src_surface
, struct wined3d_context
*context
,
299 const RECT
*src_rect
, const RECT
*dst_rect
, enum wined3d_texture_filter_type filter
)
301 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
302 struct wined3d_texture
*texture
= src_surface
->container
;
303 struct blt_info info
;
305 surface_get_blt_info(src_surface
->texture_target
, src_rect
, src_surface
->pow2Width
, src_surface
->pow2Height
, &info
);
307 gl_info
->gl_ops
.gl
.p_glEnable(info
.bind_target
);
308 checkGLcall("glEnable(bind_target)");
310 context_bind_texture(context
, info
.bind_target
, texture
->texture_rgb
.name
);
312 /* Filtering for StretchRect */
313 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MAG_FILTER
,
314 wined3d_gl_mag_filter(magLookup
, filter
));
315 checkGLcall("glTexParameteri");
316 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_MIN_FILTER
,
317 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
318 checkGLcall("glTexParameteri");
319 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
320 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
321 if (context
->gl_info
->supported
[EXT_TEXTURE_SRGB_DECODE
])
322 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_SRGB_DECODE_EXT
, GL_SKIP_DECODE_EXT
);
323 gl_info
->gl_ops
.gl
.p_glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
324 checkGLcall("glTexEnvi");
327 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
328 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
329 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->top
);
331 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
332 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->top
);
334 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
335 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->left
, dst_rect
->bottom
);
337 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
338 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
->right
, dst_rect
->bottom
);
339 gl_info
->gl_ops
.gl
.p_glEnd();
341 /* Unbind the texture */
342 context_bind_texture(context
, info
.bind_target
, 0);
344 /* We changed the filtering settings on the texture. Inform the
345 * container about this to get the filters reset properly next draw. */
346 texture
->texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3D_TEXF_POINT
;
347 texture
->texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3D_TEXF_POINT
;
348 texture
->texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3D_TEXF_NONE
;
349 texture
->texture_rgb
.states
[WINED3DTEXSTA_SRGBTEXTURE
] = FALSE
;
352 /* Works correctly only for <= 4 bpp formats. */
353 static void get_color_masks(const struct wined3d_format
*format
, DWORD
*masks
)
355 masks
[0] = ((1 << format
->red_size
) - 1) << format
->red_offset
;
356 masks
[1] = ((1 << format
->green_size
) - 1) << format
->green_offset
;
357 masks
[2] = ((1 << format
->blue_size
) - 1) << format
->blue_offset
;
360 static HRESULT
surface_create_dib_section(struct wined3d_surface
*surface
)
362 const struct wined3d_format
*format
= surface
->resource
.format
;
368 TRACE("surface %p.\n", surface
);
370 if (!(format
->flags
& WINED3DFMT_FLAG_GETDC
))
372 WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format
->id
));
373 return WINED3DERR_INVALIDCALL
;
376 switch (format
->byte_count
)
380 /* Allocate extra space to store the RGB bit masks. */
381 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 3 * sizeof(DWORD
));
385 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
));
389 /* Allocate extra space for a palette. */
390 b_info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
391 sizeof(BITMAPINFOHEADER
) + sizeof(RGBQUAD
) * (1 << (format
->byte_count
* 8)));
396 return E_OUTOFMEMORY
;
398 /* Some applications access the surface in via DWORDs, and do not take
399 * the necessary care at the end of the surface. So we need at least
400 * 4 extra bytes at the end of the surface. Check against the page size,
401 * if the last page used for the surface has at least 4 spare bytes we're
402 * safe, otherwise add an extra line to the DIB section. */
403 GetSystemInfo(&sysInfo
);
404 if( ((surface
->resource
.size
+ 3) % sysInfo
.dwPageSize
) < 4)
407 TRACE("Adding an extra line to the DIB section.\n");
410 b_info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
411 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
412 b_info
->bmiHeader
.biWidth
= wined3d_surface_get_pitch(surface
) / format
->byte_count
;
413 b_info
->bmiHeader
.biHeight
= 0 - surface
->resource
.height
- extraline
;
414 b_info
->bmiHeader
.biSizeImage
= (surface
->resource
.height
+ extraline
)
415 * wined3d_surface_get_pitch(surface
);
416 b_info
->bmiHeader
.biPlanes
= 1;
417 b_info
->bmiHeader
.biBitCount
= format
->byte_count
* 8;
419 b_info
->bmiHeader
.biXPelsPerMeter
= 0;
420 b_info
->bmiHeader
.biYPelsPerMeter
= 0;
421 b_info
->bmiHeader
.biClrUsed
= 0;
422 b_info
->bmiHeader
.biClrImportant
= 0;
424 /* Get the bit masks */
425 masks
= (DWORD
*)b_info
->bmiColors
;
426 switch (surface
->resource
.format
->id
)
428 case WINED3DFMT_B8G8R8_UNORM
:
429 b_info
->bmiHeader
.biCompression
= BI_RGB
;
432 case WINED3DFMT_B5G5R5X1_UNORM
:
433 case WINED3DFMT_B5G5R5A1_UNORM
:
434 case WINED3DFMT_B4G4R4A4_UNORM
:
435 case WINED3DFMT_B4G4R4X4_UNORM
:
436 case WINED3DFMT_B2G3R3_UNORM
:
437 case WINED3DFMT_B2G3R3A8_UNORM
:
438 case WINED3DFMT_R10G10B10A2_UNORM
:
439 case WINED3DFMT_R8G8B8A8_UNORM
:
440 case WINED3DFMT_R8G8B8X8_UNORM
:
441 case WINED3DFMT_B10G10R10A2_UNORM
:
442 case WINED3DFMT_B5G6R5_UNORM
:
443 case WINED3DFMT_R16G16B16A16_UNORM
:
444 b_info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
445 get_color_masks(format
, masks
);
449 /* Don't know palette */
450 b_info
->bmiHeader
.biCompression
= BI_RGB
;
454 TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
455 b_info
->bmiHeader
.biWidth
, b_info
->bmiHeader
.biHeight
,
456 b_info
->bmiHeader
.biBitCount
, b_info
->bmiHeader
.biSizeImage
);
457 surface
->dib
.DIBsection
= CreateDIBSection(0, b_info
, DIB_RGB_COLORS
, &surface
->dib
.bitmap_data
, 0, 0);
459 if (!surface
->dib
.DIBsection
)
461 ERR("Failed to create DIB section.\n");
462 HeapFree(GetProcessHeap(), 0, b_info
);
463 return HRESULT_FROM_WIN32(GetLastError());
466 TRACE("DIBSection at %p.\n", surface
->dib
.bitmap_data
);
467 surface
->dib
.bitmap_size
= b_info
->bmiHeader
.biSizeImage
;
469 HeapFree(GetProcessHeap(), 0, b_info
);
471 /* Now allocate a DC. */
472 surface
->hDC
= CreateCompatibleDC(0);
473 SelectObject(surface
->hDC
, surface
->dib
.DIBsection
);
475 surface
->flags
|= SFLAG_DIBSECTION
;
480 static void surface_get_memory(const struct wined3d_surface
*surface
, struct wined3d_bo_address
*data
,
483 if (location
& WINED3D_LOCATION_BUFFER
)
486 data
->buffer_object
= surface
->pbo
;
489 if (location
& WINED3D_LOCATION_USER_MEMORY
)
491 data
->addr
= surface
->user_memory
;
492 data
->buffer_object
= 0;
495 if (location
& WINED3D_LOCATION_DIB
)
497 data
->addr
= surface
->dib
.bitmap_data
;
498 data
->buffer_object
= 0;
501 if (location
& WINED3D_LOCATION_SYSMEM
)
503 data
->addr
= surface
->resource
.heap_memory
;
504 data
->buffer_object
= 0;
508 ERR("Unexpected locations %s.\n", wined3d_debug_location(location
));
510 data
->buffer_object
= 0;
513 static void surface_prepare_buffer(struct wined3d_surface
*surface
)
515 struct wined3d_context
*context
;
517 const struct wined3d_gl_info
*gl_info
;
522 context
= context_acquire(surface
->resource
.device
, NULL
);
523 gl_info
= context
->gl_info
;
525 GL_EXTCALL(glGenBuffersARB(1, &surface
->pbo
));
526 error
= gl_info
->gl_ops
.gl
.p_glGetError();
527 if (!surface
->pbo
|| error
!= GL_NO_ERROR
)
528 ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error
), error
);
530 TRACE("Binding PBO %u.\n", surface
->pbo
);
532 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
533 checkGLcall("glBindBufferARB");
535 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->resource
.size
+ 4,
536 NULL
, GL_STREAM_DRAW_ARB
));
537 checkGLcall("glBufferDataARB");
539 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
540 checkGLcall("glBindBufferARB");
542 context_release(context
);
545 static void surface_prepare_system_memory(struct wined3d_surface
*surface
)
547 TRACE("surface %p.\n", surface
);
549 if (surface
->resource
.heap_memory
)
552 /* Whatever surface we have, make sure that there is memory allocated
553 * for the downloaded copy, or a PBO to map. */
554 if (!wined3d_resource_allocate_sysmem(&surface
->resource
))
555 ERR("Failed to allocate system memory.\n");
557 if (surface
->locations
& WINED3D_LOCATION_SYSMEM
)
558 ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
561 void surface_prepare_map_memory(struct wined3d_surface
*surface
)
563 switch (surface
->resource
.map_binding
)
565 case WINED3D_LOCATION_SYSMEM
:
566 surface_prepare_system_memory(surface
);
569 case WINED3D_LOCATION_USER_MEMORY
:
570 if (!surface
->user_memory
)
571 ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
574 case WINED3D_LOCATION_DIB
:
575 if (!surface
->dib
.bitmap_data
)
576 ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
579 case WINED3D_LOCATION_BUFFER
:
580 surface_prepare_buffer(surface
);
584 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
588 static void surface_evict_sysmem(struct wined3d_surface
*surface
)
590 /* In some conditions the surface memory must not be freed:
591 * SFLAG_CONVERTED: Converting the data back would take too long
592 * SFLAG_DYNLOCK: Avoid freeing the data for performance
593 * SFLAG_CLIENT: OpenGL uses our memory as backup */
594 if (surface
->resource
.map_count
|| surface
->flags
& (SFLAG_CONVERTED
| SFLAG_DYNLOCK
595 | SFLAG_CLIENT
| SFLAG_PIN_SYSMEM
))
598 wined3d_resource_free_sysmem(&surface
->resource
);
599 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
602 static void surface_force_reload(struct wined3d_surface
*surface
)
604 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
607 static void surface_release_client_storage(struct wined3d_surface
*surface
)
609 struct wined3d_context
*context
= context_acquire(surface
->resource
.device
, NULL
);
610 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
612 if (surface
->container
->texture_rgb
.name
)
614 wined3d_texture_bind_and_dirtify(surface
->container
, context
, FALSE
);
615 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
616 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
618 if (surface
->container
->texture_srgb
.name
)
620 wined3d_texture_bind_and_dirtify(surface
->container
, context
, TRUE
);
621 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
622 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
625 context_release(context
);
627 surface_invalidate_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
);
628 surface_force_reload(surface
);
631 static BOOL
surface_use_pbo(const struct wined3d_surface
*surface
)
633 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
635 return surface
->resource
.pool
== WINED3D_POOL_DEFAULT
636 && surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
637 && gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
]
638 && !surface
->resource
.format
->convert
639 && !(surface
->flags
& (SFLAG_NONPOW2
| SFLAG_PIN_SYSMEM
));
642 static HRESULT
surface_private_setup(struct wined3d_surface
*surface
)
644 /* TODO: Check against the maximum texture sizes supported by the video card. */
645 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
646 unsigned int pow2Width
, pow2Height
;
648 TRACE("surface %p.\n", surface
);
650 /* Non-power2 support */
651 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
]
652 || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
654 pow2Width
= surface
->resource
.width
;
655 pow2Height
= surface
->resource
.height
;
659 /* Find the nearest pow2 match */
660 pow2Width
= pow2Height
= 1;
661 while (pow2Width
< surface
->resource
.width
)
663 while (pow2Height
< surface
->resource
.height
)
666 surface
->pow2Width
= pow2Width
;
667 surface
->pow2Height
= pow2Height
;
669 if (pow2Width
> surface
->resource
.width
|| pow2Height
> surface
->resource
.height
)
671 /* TODO: Add support for non power two compressed textures. */
672 if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_COMPRESSED
| WINED3DFMT_FLAG_HEIGHT_SCALE
))
674 FIXME("(%p) Compressed or height scaled non-power-two textures are not supported w(%d) h(%d)\n",
675 surface
, surface
->resource
.width
, surface
->resource
.height
);
676 return WINED3DERR_NOTAVAILABLE
;
680 if (pow2Width
!= surface
->resource
.width
681 || pow2Height
!= surface
->resource
.height
)
683 surface
->flags
|= SFLAG_NONPOW2
;
686 if ((surface
->pow2Width
> gl_info
->limits
.texture_size
|| surface
->pow2Height
> gl_info
->limits
.texture_size
)
687 && !(surface
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
689 /* One of three options:
690 * 1: Do the same as we do with NPOT and scale the texture, (any
691 * texture ops would require the texture to be scaled which is
693 * 2: Set the texture to the maximum size (bad idea).
694 * 3: WARN and return WINED3DERR_NOTAVAILABLE;
695 * 4: Create the surface, but allow it to be used only for DirectDraw
696 * Blts. Some apps (e.g. Swat 3) create textures with a Height of
697 * 16 and a Width > 3000 and blt 16x16 letter areas from them to
698 * the render target. */
699 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
|| surface
->resource
.pool
== WINED3D_POOL_MANAGED
)
701 WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
702 return WINED3DERR_NOTAVAILABLE
;
705 /* We should never use this surface in combination with OpenGL! */
706 TRACE("Creating an oversized surface: %ux%u.\n",
707 surface
->pow2Width
, surface
->pow2Height
);
710 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
711 surface
->locations
= WINED3D_LOCATION_DISCARDED
;
713 if (surface_use_pbo(surface
))
714 surface
->resource
.map_binding
= WINED3D_LOCATION_BUFFER
;
719 static void surface_unmap(struct wined3d_surface
*surface
)
721 struct wined3d_device
*device
= surface
->resource
.device
;
722 const struct wined3d_gl_info
*gl_info
;
723 struct wined3d_context
*context
;
725 TRACE("surface %p.\n", surface
);
727 memset(&surface
->lockedRect
, 0, sizeof(surface
->lockedRect
));
729 switch (surface
->resource
.map_binding
)
731 case WINED3D_LOCATION_SYSMEM
:
732 case WINED3D_LOCATION_USER_MEMORY
:
733 case WINED3D_LOCATION_DIB
:
736 case WINED3D_LOCATION_BUFFER
:
737 context
= context_acquire(device
, NULL
);
738 gl_info
= context
->gl_info
;
740 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
741 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
742 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
743 checkGLcall("glUnmapBufferARB");
744 context_release(context
);
748 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
751 if (surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_TEXTURE_RGB
))
753 TRACE("Not dirtified, nothing to do.\n");
757 if (surface
->container
->swapchain
&& surface
->container
->swapchain
->front_buffer
== surface
->container
)
758 surface_load_location(surface
, surface
->container
->resource
.draw_binding
);
759 else if (surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
))
760 FIXME("Depth / stencil buffer locking is not implemented.\n");
763 static BOOL
surface_is_full_rect(const struct wined3d_surface
*surface
, const RECT
*r
)
765 if ((r
->left
&& r
->right
) || abs(r
->right
- r
->left
) != surface
->resource
.width
)
767 if ((r
->top
&& r
->bottom
) || abs(r
->bottom
- r
->top
) != surface
->resource
.height
)
772 static void surface_depth_blt_fbo(const struct wined3d_device
*device
,
773 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
774 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
776 const struct wined3d_gl_info
*gl_info
;
777 struct wined3d_context
*context
;
778 DWORD src_mask
, dst_mask
;
781 TRACE("device %p\n", device
);
782 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
783 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect
));
784 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
785 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect
));
787 src_mask
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
788 dst_mask
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
790 if (src_mask
!= dst_mask
)
792 ERR("Incompatible formats %s and %s.\n",
793 debug_d3dformat(src_surface
->resource
.format
->id
),
794 debug_d3dformat(dst_surface
->resource
.format
->id
));
800 ERR("Not a depth / stencil format: %s.\n",
801 debug_d3dformat(src_surface
->resource
.format
->id
));
806 if (src_mask
& WINED3DFMT_FLAG_DEPTH
)
807 gl_mask
|= GL_DEPTH_BUFFER_BIT
;
808 if (src_mask
& WINED3DFMT_FLAG_STENCIL
)
809 gl_mask
|= GL_STENCIL_BUFFER_BIT
;
811 /* Make sure the locations are up-to-date. Loading the destination
812 * surface isn't required if the entire surface is overwritten. */
813 surface_load_location(src_surface
, src_location
);
814 if (!surface_is_full_rect(dst_surface
, dst_rect
))
815 surface_load_location(dst_surface
, dst_location
);
817 context
= context_acquire(device
, NULL
);
820 context_release(context
);
821 WARN("Invalid context, skipping blit.\n");
825 gl_info
= context
->gl_info
;
827 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, NULL
, src_surface
, src_location
);
828 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
830 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, NULL
, dst_surface
, dst_location
);
831 context_set_draw_buffer(context
, GL_NONE
);
832 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
833 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
835 if (gl_mask
& GL_DEPTH_BUFFER_BIT
)
837 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
838 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_ZWRITEENABLE
));
840 if (gl_mask
& GL_STENCIL_BUFFER_BIT
)
842 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
844 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
845 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE
));
847 gl_info
->gl_ops
.gl
.p_glStencilMask(~0U);
848 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK
));
851 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
852 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
854 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->left
, src_rect
->top
, src_rect
->right
, src_rect
->bottom
,
855 dst_rect
->left
, dst_rect
->top
, dst_rect
->right
, dst_rect
->bottom
, gl_mask
, GL_NEAREST
);
856 checkGLcall("glBlitFramebuffer()");
858 if (wined3d_settings
.strict_draw_ordering
)
859 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
861 context_release(context
);
864 /* Blit between surface locations. Onscreen on different swapchains is not supported.
865 * Depth / stencil is not supported. */
866 static void surface_blt_fbo(const struct wined3d_device
*device
, enum wined3d_texture_filter_type filter
,
867 struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect_in
,
868 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect_in
)
870 const struct wined3d_gl_info
*gl_info
;
871 struct wined3d_context
*context
;
872 RECT src_rect
, dst_rect
;
876 TRACE("device %p, filter %s,\n", device
, debug_d3dtexturefiltertype(filter
));
877 TRACE("src_surface %p, src_location %s, src_rect %s,\n",
878 src_surface
, wined3d_debug_location(src_location
), wine_dbgstr_rect(src_rect_in
));
879 TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
880 dst_surface
, wined3d_debug_location(dst_location
), wine_dbgstr_rect(dst_rect_in
));
882 src_rect
= *src_rect_in
;
883 dst_rect
= *dst_rect_in
;
887 case WINED3D_TEXF_LINEAR
:
888 gl_filter
= GL_LINEAR
;
892 FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter
), filter
);
893 case WINED3D_TEXF_NONE
:
894 case WINED3D_TEXF_POINT
:
895 gl_filter
= GL_NEAREST
;
899 /* Resolve the source surface first if needed. */
900 if (src_location
== WINED3D_LOCATION_RB_MULTISAMPLE
901 && (src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
902 || abs(src_rect
.bottom
- src_rect
.top
) != abs(dst_rect
.bottom
- dst_rect
.top
)
903 || abs(src_rect
.right
- src_rect
.left
) != abs(dst_rect
.right
- dst_rect
.left
)))
904 src_location
= WINED3D_LOCATION_RB_RESOLVED
;
906 /* Make sure the locations are up-to-date. Loading the destination
907 * surface isn't required if the entire surface is overwritten. (And is
908 * in fact harmful if we're being called by surface_load_location() with
909 * the purpose of loading the destination surface.) */
910 surface_load_location(src_surface
, src_location
);
911 if (!surface_is_full_rect(dst_surface
, &dst_rect
))
912 surface_load_location(dst_surface
, dst_location
);
914 if (src_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, src_surface
);
915 else if (dst_location
== WINED3D_LOCATION_DRAWABLE
) context
= context_acquire(device
, dst_surface
);
916 else context
= context_acquire(device
, NULL
);
920 context_release(context
);
921 WARN("Invalid context, skipping blit.\n");
925 gl_info
= context
->gl_info
;
927 if (src_location
== WINED3D_LOCATION_DRAWABLE
)
929 TRACE("Source surface %p is onscreen.\n", src_surface
);
930 buffer
= surface_get_gl_buffer(src_surface
);
931 surface_translate_drawable_coords(src_surface
, context
->win_handle
, &src_rect
);
935 TRACE("Source surface %p is offscreen.\n", src_surface
);
936 buffer
= GL_COLOR_ATTACHMENT0
;
939 context_apply_fbo_state_blit(context
, GL_READ_FRAMEBUFFER
, src_surface
, NULL
, src_location
);
940 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
941 checkGLcall("glReadBuffer()");
942 context_check_fbo_status(context
, GL_READ_FRAMEBUFFER
);
944 if (dst_location
== WINED3D_LOCATION_DRAWABLE
)
946 TRACE("Destination surface %p is onscreen.\n", dst_surface
);
947 buffer
= surface_get_gl_buffer(dst_surface
);
948 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
952 TRACE("Destination surface %p is offscreen.\n", dst_surface
);
953 buffer
= GL_COLOR_ATTACHMENT0
;
956 context_apply_fbo_state_blit(context
, GL_DRAW_FRAMEBUFFER
, dst_surface
, NULL
, dst_location
);
957 context_set_draw_buffer(context
, buffer
);
958 context_check_fbo_status(context
, GL_DRAW_FRAMEBUFFER
);
959 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
961 gl_info
->gl_ops
.gl
.p_glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
962 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE
));
963 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1
));
964 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2
));
965 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3
));
967 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
968 context_invalidate_state(context
, STATE_RENDER(WINED3D_RS_SCISSORTESTENABLE
));
970 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
971 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, GL_COLOR_BUFFER_BIT
, gl_filter
);
972 checkGLcall("glBlitFramebuffer()");
974 if (wined3d_settings
.strict_draw_ordering
975 || (dst_location
== WINED3D_LOCATION_DRAWABLE
976 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
977 gl_info
->gl_ops
.gl
.p_glFlush();
979 context_release(context
);
982 static BOOL
fbo_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
983 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
984 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
986 if ((wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) || !gl_info
->fbo_ops
.glBlitFramebuffer
)
989 /* Source and/or destination need to be on the GL side */
990 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
995 case WINED3D_BLIT_OP_COLOR_BLIT
:
996 if (!((src_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (src_usage
& WINED3DUSAGE_RENDERTARGET
)))
998 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
1002 case WINED3D_BLIT_OP_DEPTH_BLIT
:
1003 if (!(src_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1005 if (!(dst_format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
)))
1013 if (!(src_format
->id
== dst_format
->id
1014 || (is_identity_fixup(src_format
->color_fixup
)
1015 && is_identity_fixup(dst_format
->color_fixup
))))
1021 static BOOL
surface_convert_color_to_float(const struct wined3d_surface
*surface
,
1022 DWORD color
, struct wined3d_color
*float_color
)
1024 const struct wined3d_format
*format
= surface
->resource
.format
;
1025 const struct wined3d_palette
*palette
;
1029 case WINED3DFMT_P8_UINT
:
1030 palette
= surface
->container
->swapchain
? surface
->container
->swapchain
->palette
: NULL
;
1034 float_color
->r
= palette
->colors
[color
].rgbRed
/ 255.0f
;
1035 float_color
->g
= palette
->colors
[color
].rgbGreen
/ 255.0f
;
1036 float_color
->b
= palette
->colors
[color
].rgbBlue
/ 255.0f
;
1040 float_color
->r
= 0.0f
;
1041 float_color
->g
= 0.0f
;
1042 float_color
->b
= 0.0f
;
1044 float_color
->a
= color
/ 255.0f
;
1047 case WINED3DFMT_B5G6R5_UNORM
:
1048 float_color
->r
= ((color
>> 11) & 0x1f) / 31.0f
;
1049 float_color
->g
= ((color
>> 5) & 0x3f) / 63.0f
;
1050 float_color
->b
= (color
& 0x1f) / 31.0f
;
1051 float_color
->a
= 1.0f
;
1054 case WINED3DFMT_B8G8R8_UNORM
:
1055 case WINED3DFMT_B8G8R8X8_UNORM
:
1056 float_color
->r
= D3DCOLOR_R(color
);
1057 float_color
->g
= D3DCOLOR_G(color
);
1058 float_color
->b
= D3DCOLOR_B(color
);
1059 float_color
->a
= 1.0f
;
1062 case WINED3DFMT_B8G8R8A8_UNORM
:
1063 float_color
->r
= D3DCOLOR_R(color
);
1064 float_color
->g
= D3DCOLOR_G(color
);
1065 float_color
->b
= D3DCOLOR_B(color
);
1066 float_color
->a
= D3DCOLOR_A(color
);
1070 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1077 static BOOL
surface_convert_depth_to_float(const struct wined3d_surface
*surface
, DWORD depth
, float *float_depth
)
1079 const struct wined3d_format
*format
= surface
->resource
.format
;
1083 case WINED3DFMT_S1_UINT_D15_UNORM
:
1084 *float_depth
= depth
/ (float)0x00007fff;
1087 case WINED3DFMT_D16_UNORM
:
1088 *float_depth
= depth
/ (float)0x0000ffff;
1091 case WINED3DFMT_D24_UNORM_S8_UINT
:
1092 case WINED3DFMT_X8D24_UNORM
:
1093 *float_depth
= depth
/ (float)0x00ffffff;
1096 case WINED3DFMT_D32_UNORM
:
1097 *float_depth
= depth
/ (float)0xffffffff;
1101 ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format
->id
));
1108 static HRESULT
wined3d_surface_depth_fill(struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
1110 const struct wined3d_resource
*resource
= &surface
->container
->resource
;
1111 struct wined3d_device
*device
= resource
->device
;
1112 const struct blit_shader
*blitter
;
1114 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_FILL
,
1115 NULL
, 0, 0, NULL
, rect
, resource
->usage
, resource
->pool
, resource
->format
);
1118 FIXME("No blitter is capable of performing the requested depth fill operation.\n");
1119 return WINED3DERR_INVALIDCALL
;
1122 return blitter
->depth_fill(device
, surface
, rect
, depth
);
1125 static HRESULT
wined3d_surface_depth_blt(struct wined3d_surface
*src_surface
, DWORD src_location
, const RECT
*src_rect
,
1126 struct wined3d_surface
*dst_surface
, DWORD dst_location
, const RECT
*dst_rect
)
1128 struct wined3d_device
*device
= src_surface
->resource
.device
;
1130 if (!fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_DEPTH_BLIT
,
1131 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
1132 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
1133 return WINED3DERR_INVALIDCALL
;
1135 surface_depth_blt_fbo(device
, src_surface
, src_location
, src_rect
, dst_surface
, dst_location
, dst_rect
);
1137 surface_modify_ds_location(dst_surface
, dst_location
,
1138 dst_surface
->ds_current_size
.cx
, dst_surface
->ds_current_size
.cy
);
1143 HRESULT CDECL
wined3d_surface_get_render_target_data(struct wined3d_surface
*surface
,
1144 struct wined3d_surface
*render_target
)
1146 TRACE("surface %p, render_target %p.\n", surface
, render_target
);
1148 /* TODO: Check surface sizes, pools, etc. */
1150 if (render_target
->resource
.multisample_type
)
1151 return WINED3DERR_INVALIDCALL
;
1153 return wined3d_surface_blt(surface
, NULL
, render_target
, NULL
, 0, NULL
, WINED3D_TEXF_POINT
);
1156 /* Context activation is done by the caller. */
1157 static void surface_remove_pbo(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
)
1159 GL_EXTCALL(glDeleteBuffersARB(1, &surface
->pbo
));
1160 checkGLcall("glDeleteBuffersARB(1, &surface->pbo)");
1163 surface_invalidate_location(surface
, WINED3D_LOCATION_BUFFER
);
1166 static ULONG
surface_resource_incref(struct wined3d_resource
*resource
)
1168 return wined3d_surface_incref(surface_from_resource(resource
));
1171 static ULONG
surface_resource_decref(struct wined3d_resource
*resource
)
1173 return wined3d_surface_decref(surface_from_resource(resource
));
1176 static void surface_unload(struct wined3d_resource
*resource
)
1178 struct wined3d_surface
*surface
= surface_from_resource(resource
);
1179 struct wined3d_renderbuffer_entry
*entry
, *entry2
;
1180 struct wined3d_device
*device
= resource
->device
;
1181 const struct wined3d_gl_info
*gl_info
;
1182 struct wined3d_context
*context
;
1184 TRACE("surface %p.\n", surface
);
1186 if (resource
->pool
== WINED3D_POOL_DEFAULT
)
1188 /* Default pool resources are supposed to be destroyed before Reset is called.
1189 * Implicit resources stay however. So this means we have an implicit render target
1190 * or depth stencil. The content may be destroyed, but we still have to tear down
1191 * opengl resources, so we cannot leave early.
1193 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1194 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1195 * or the depth stencil into an FBO the texture or render buffer will be removed
1196 * and all flags get lost */
1197 surface_prepare_system_memory(surface
);
1198 memset(surface
->resource
.heap_memory
, 0, surface
->resource
.size
);
1199 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
1200 surface_invalidate_location(surface
, ~WINED3D_LOCATION_SYSMEM
);
1202 /* We also get here when the ddraw swapchain is destroyed, for example
1203 * for a mode switch. In this case this surface won't necessarily be
1204 * an implicit surface. We have to mark it lost so that the
1205 * application can restore it after the mode switch. */
1206 surface
->flags
|= SFLAG_LOST
;
1210 surface_prepare_map_memory(surface
);
1211 surface_load_location(surface
, surface
->resource
.map_binding
);
1212 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
1214 surface
->flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
1216 context
= context_acquire(device
, NULL
);
1217 gl_info
= context
->gl_info
;
1219 /* Destroy PBOs, but load them into real sysmem before */
1221 surface_remove_pbo(surface
, gl_info
);
1223 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1224 * all application-created targets the application has to release the surface
1225 * before calling _Reset
1227 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1229 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
1230 list_remove(&entry
->entry
);
1231 HeapFree(GetProcessHeap(), 0, entry
);
1233 list_init(&surface
->renderbuffers
);
1234 surface
->current_renderbuffer
= NULL
;
1236 if (surface
->rb_multisample
)
1238 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_multisample
);
1239 surface
->rb_multisample
= 0;
1241 if (surface
->rb_resolved
)
1243 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &surface
->rb_resolved
);
1244 surface
->rb_resolved
= 0;
1247 context_release(context
);
1249 resource_unload(resource
);
1252 static const struct wined3d_resource_ops surface_resource_ops
=
1254 surface_resource_incref
,
1255 surface_resource_decref
,
1259 static const struct wined3d_surface_ops surface_ops
=
1261 surface_private_setup
,
1265 /*****************************************************************************
1266 * Initializes the GDI surface, aka creates the DIB section we render to
1267 * The DIB section creation is done by calling GetDC, which will create the
1268 * section and releasing the dc to allow the app to use it. The dib section
1269 * will stay until the surface is released
1271 * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
1272 * are set to the real sizes to save memory. The NONPOW2 flag is unset to
1273 * avoid confusion in the shared surface code.
1276 * WINED3D_OK on success
1277 * The return values of called methods on failure
1279 *****************************************************************************/
1280 static HRESULT
gdi_surface_private_setup(struct wined3d_surface
*surface
)
1284 TRACE("surface %p.\n", surface
);
1286 if (surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
)
1288 ERR("Overlays not yet supported by GDI surfaces.\n");
1289 return WINED3DERR_INVALIDCALL
;
1292 /* Sysmem textures have memory already allocated - release it,
1293 * this avoids an unnecessary memcpy. */
1294 hr
= surface_create_dib_section(surface
);
1297 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
1299 /* We don't mind the nonpow2 stuff in GDI. */
1300 surface
->pow2Width
= surface
->resource
.width
;
1301 surface
->pow2Height
= surface
->resource
.height
;
1306 static void gdi_surface_unmap(struct wined3d_surface
*surface
)
1308 TRACE("surface %p.\n", surface
);
1310 /* Tell the swapchain to update the screen. */
1311 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
1312 x11_copy_to_screen(surface
->container
->swapchain
, &surface
->lockedRect
);
1314 memset(&surface
->lockedRect
, 0, sizeof(RECT
));
1317 static const struct wined3d_surface_ops gdi_surface_ops
=
1319 gdi_surface_private_setup
,
1323 /* This call just downloads data, the caller is responsible for binding the
1324 * correct texture. */
1325 /* Context activation is done by the caller. */
1326 static void surface_download_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1329 const struct wined3d_format
*format
= surface
->resource
.format
;
1330 struct wined3d_bo_address data
;
1332 /* Only support read back of converted P8 surfaces. */
1333 if (surface
->flags
& SFLAG_CONVERTED
&& format
->id
!= WINED3DFMT_P8_UINT
)
1335 ERR("Trying to read back converted surface %p with format %s.\n", surface
, debug_d3dformat(format
->id
));
1339 surface_get_memory(surface
, &data
, dst_location
);
1341 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1343 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1344 surface
, surface
->texture_level
, format
->glFormat
, format
->glType
, data
.addr
);
1346 if (data
.buffer_object
)
1348 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
1349 checkGLcall("glBindBufferARB");
1350 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
, surface
->texture_level
, NULL
));
1351 checkGLcall("glGetCompressedTexImageARB");
1352 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1353 checkGLcall("glBindBufferARB");
1357 GL_EXTCALL(glGetCompressedTexImageARB(surface
->texture_target
,
1358 surface
->texture_level
, data
.addr
));
1359 checkGLcall("glGetCompressedTexImageARB");
1365 GLenum gl_format
= format
->glFormat
;
1366 GLenum gl_type
= format
->glType
;
1370 if (surface
->flags
& SFLAG_NONPOW2
)
1372 unsigned char alignment
= surface
->resource
.device
->surface_alignment
;
1373 src_pitch
= format
->byte_count
* surface
->pow2Width
;
1374 dst_pitch
= wined3d_surface_get_pitch(surface
);
1375 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
1376 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* surface
->pow2Height
);
1383 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1384 surface
, surface
->texture_level
, gl_format
, gl_type
, mem
);
1386 if (data
.buffer_object
)
1388 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
1389 checkGLcall("glBindBufferARB");
1391 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1392 gl_format
, gl_type
, NULL
);
1393 checkGLcall("glGetTexImage");
1395 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1396 checkGLcall("glBindBufferARB");
1400 gl_info
->gl_ops
.gl
.p_glGetTexImage(surface
->texture_target
, surface
->texture_level
,
1401 gl_format
, gl_type
, mem
);
1402 checkGLcall("glGetTexImage");
1405 if (surface
->flags
& SFLAG_NONPOW2
)
1407 const BYTE
*src_data
;
1411 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1412 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1413 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1415 * We're doing this...
1417 * instead of boxing the texture :
1418 * |<-texture width ->| -->pow2width| /\
1419 * |111111111111111111| | |
1420 * |222 Texture 222222| boxed empty | texture height
1421 * |3333 Data 33333333| | |
1422 * |444444444444444444| | \/
1423 * ----------------------------------- |
1424 * | boxed empty | boxed empty | pow2height
1426 * -----------------------------------
1429 * we're repacking the data to the expected texture width
1431 * |<-texture width ->| -->pow2width| /\
1432 * |111111111111111111222222222222222| |
1433 * |222333333333333333333444444444444| texture height
1437 * | empty | pow2height
1439 * -----------------------------------
1443 * |<-texture width ->| /\
1444 * |111111111111111111|
1445 * |222222222222222222|texture height
1446 * |333333333333333333|
1447 * |444444444444444444| \/
1448 * --------------------
1450 * This also means that any references to surface memory should work with the data as if it were a
1451 * standard texture with a non-power2 width instead of a texture boxed up to be a power2 texture.
1453 * internally the texture is still stored in a boxed format so any references to textureName will
1454 * get a boxed texture with width pow2width and not a texture of width resource.width.
1456 * Performance should not be an issue, because applications normally do not lock the surfaces when
1457 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
1458 * and doesn't have to be re-read. */
1460 dst_data
= data
.addr
;
1461 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface
, src_pitch
, dst_pitch
);
1462 for (y
= 0; y
< surface
->resource
.height
; ++y
)
1464 memcpy(dst_data
, src_data
, dst_pitch
);
1465 src_data
+= src_pitch
;
1466 dst_data
+= dst_pitch
;
1469 HeapFree(GetProcessHeap(), 0, mem
);
1474 /* This call just uploads data, the caller is responsible for binding the
1475 * correct texture. */
1476 /* Context activation is done by the caller. */
1477 static void surface_upload_data(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1478 const struct wined3d_format
*format
, const RECT
*src_rect
, UINT src_pitch
, const POINT
*dst_point
,
1479 BOOL srgb
, const struct wined3d_bo_address
*data
)
1481 UINT update_w
= src_rect
->right
- src_rect
->left
;
1482 UINT update_h
= src_rect
->bottom
- src_rect
->top
;
1484 TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
1485 surface
, gl_info
, debug_d3dformat(format
->id
), wine_dbgstr_rect(src_rect
), src_pitch
,
1486 wine_dbgstr_point(dst_point
), srgb
, data
->buffer_object
, data
->addr
);
1488 if (surface
->resource
.map_count
)
1490 WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
1491 surface
->flags
|= SFLAG_PIN_SYSMEM
;
1494 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1496 update_h
*= format
->height_scale
.numerator
;
1497 update_h
/= format
->height_scale
.denominator
;
1500 if (data
->buffer_object
)
1502 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, data
->buffer_object
));
1503 checkGLcall("glBindBufferARB");
1506 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
1508 UINT row_length
= wined3d_format_calculate_size(format
, 1, update_w
, 1, 1);
1509 UINT row_count
= (update_h
+ format
->block_height
- 1) / format
->block_height
;
1510 const BYTE
*addr
= data
->addr
;
1513 addr
+= (src_rect
->top
/ format
->block_height
) * src_pitch
;
1514 addr
+= (src_rect
->left
/ format
->block_width
) * format
->block_byte_count
;
1517 internal
= format
->glGammaInternal
;
1518 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1519 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
1520 internal
= format
->rtInternal
;
1522 internal
= format
->glInternal
;
1524 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
1525 "format %#x, image_size %#x, addr %p.\n", surface
->texture_target
, surface
->texture_level
,
1526 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
);
1528 if (row_length
== src_pitch
)
1530 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1531 dst_point
->x
, dst_point
->y
, update_w
, update_h
, internal
, row_count
* row_length
, addr
));
1537 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
1538 * can't use the unpack row length like below. */
1539 for (row
= 0, y
= dst_point
->y
; row
< row_count
; ++row
)
1541 GL_EXTCALL(glCompressedTexSubImage2DARB(surface
->texture_target
, surface
->texture_level
,
1542 dst_point
->x
, y
, update_w
, format
->block_height
, internal
, row_length
, addr
));
1543 y
+= format
->block_height
;
1547 checkGLcall("glCompressedTexSubImage2DARB");
1551 const BYTE
*addr
= data
->addr
;
1553 addr
+= src_rect
->top
* src_pitch
;
1554 addr
+= src_rect
->left
* format
->byte_count
;
1556 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
1557 surface
->texture_target
, surface
->texture_level
, dst_point
->x
, dst_point
->y
,
1558 update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1560 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_pitch
/ format
->byte_count
);
1561 gl_info
->gl_ops
.gl
.p_glTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
1562 dst_point
->x
, dst_point
->y
, update_w
, update_h
, format
->glFormat
, format
->glType
, addr
);
1563 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
1564 checkGLcall("glTexSubImage2D");
1567 if (data
->buffer_object
)
1569 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1570 checkGLcall("glBindBufferARB");
1573 if (wined3d_settings
.strict_draw_ordering
)
1574 gl_info
->gl_ops
.gl
.p_glFlush();
1576 if (gl_info
->quirks
& WINED3D_QUIRK_FBO_TEX_UPDATE
)
1578 struct wined3d_device
*device
= surface
->resource
.device
;
1581 for (i
= 0; i
< device
->context_count
; ++i
)
1583 context_surface_update(device
->contexts
[i
], surface
);
1588 static void d3dfmt_get_conv(const struct wined3d_texture
*texture
, BOOL need_alpha_ck
,
1589 struct wined3d_format
*format
, enum wined3d_conversion_type
*conversion_type
)
1591 BOOL colorkey_active
= need_alpha_ck
&& (texture
->color_key_flags
& WINEDDSD_CKSRCBLT
);
1592 const struct wined3d_device
*device
= texture
->resource
.device
;
1593 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1594 const struct wined3d_format
*dst_format
;
1595 enum wined3d_format_id dst_format_id
;
1600 enum wined3d_format_id src_format
;
1601 enum wined3d_conversion_type conversion_type
;
1602 enum wined3d_format_id dst_format
;
1606 {WINED3DFMT_B5G6R5_UNORM
, WINED3D_CT_CK_B5G6R5
, WINED3DFMT_B5G5R5A1_UNORM
},
1607 {WINED3DFMT_B5G5R5X1_UNORM
, WINED3D_CT_CK_B5G5R5X1
, WINED3DFMT_B5G5R5A1_UNORM
},
1608 {WINED3DFMT_B8G8R8_UNORM
, WINED3D_CT_CK_B8G8R8
, WINED3DFMT_B8G8R8A8_UNORM
},
1609 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3D_CT_CK_B8G8R8X8
, WINED3DFMT_B8G8R8A8_UNORM
},
1610 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3D_CT_CK_B8G8R8A8
, WINED3DFMT_B8G8R8A8_UNORM
},
1613 *format
= *texture
->resource
.format
;
1614 *conversion_type
= WINED3D_CT_NONE
;
1615 dst_format_id
= format
->id
;
1617 if (colorkey_active
)
1619 for (i
= 0; i
< sizeof(color_key_info
) / sizeof(*color_key_info
); ++i
)
1621 if (color_key_info
[i
].src_format
!= texture
->resource
.format
->id
)
1624 *conversion_type
= color_key_info
[i
].conversion_type
;
1625 dst_format_id
= color_key_info
[i
].dst_format
;
1630 if (texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
1632 /* FIXME: This should check if the blitter backend can do P8
1633 * conversion, instead of checking for ARB_fragment_program. */
1634 if (!((gl_info
->supported
[ARB_FRAGMENT_PROGRAM
] && texture
->swapchain
1635 && texture
== texture
->swapchain
->front_buffer
)) || colorkey_active
)
1637 *conversion_type
= WINED3D_CT_P8
;
1638 dst_format_id
= WINED3DFMT_B8G8R8A8_UNORM
;
1641 else if (texture
->resource
.format
->id
== WINED3DFMT_B2G3R3_UNORM
&& colorkey_active
)
1643 /* This texture format will never be used... So do not care about
1644 * color-keying up until the point in time it will be needed. */
1645 FIXME("Color-keying not supported with WINED3DFMT_B2G3R3_UNORM.\n");
1648 if (*conversion_type
!= WINED3D_CT_NONE
)
1650 dst_format
= wined3d_get_format(gl_info
, dst_format_id
);
1651 format
->glInternal
= dst_format
->glInternal
;
1652 format
->glGammaInternal
= format
->glInternal
;
1653 format
->rtInternal
= format
->glInternal
;
1654 format
->glFormat
= dst_format
->glFormat
;
1655 format
->glType
= dst_format
->glType
;
1656 format
->conv_byte_count
= dst_format
->byte_count
;
1660 static BOOL
surface_check_block_align(struct wined3d_surface
*surface
, const RECT
*rect
)
1662 UINT width_mask
, height_mask
;
1664 if (!rect
->left
&& !rect
->top
1665 && rect
->right
== surface
->resource
.width
1666 && rect
->bottom
== surface
->resource
.height
)
1669 /* This assumes power of two block sizes, but NPOT block sizes would be
1671 width_mask
= surface
->resource
.format
->block_width
- 1;
1672 height_mask
= surface
->resource
.format
->block_height
- 1;
1674 if (!(rect
->left
& width_mask
) && !(rect
->top
& height_mask
)
1675 && !(rect
->right
& width_mask
) && !(rect
->bottom
& height_mask
))
1681 HRESULT
surface_upload_from_surface(struct wined3d_surface
*dst_surface
, const POINT
*dst_point
,
1682 struct wined3d_surface
*src_surface
, const RECT
*src_rect
)
1684 const struct wined3d_format
*src_format
;
1685 const struct wined3d_format
*dst_format
;
1686 const struct wined3d_gl_info
*gl_info
;
1687 enum wined3d_conversion_type convert
;
1688 struct wined3d_context
*context
;
1689 struct wined3d_bo_address data
;
1690 struct wined3d_format format
;
1691 UINT update_w
, update_h
;
1697 TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
1698 dst_surface
, wine_dbgstr_point(dst_point
),
1699 src_surface
, wine_dbgstr_rect(src_rect
));
1701 src_format
= src_surface
->resource
.format
;
1702 dst_format
= dst_surface
->resource
.format
;
1704 if (src_format
->id
!= dst_format
->id
)
1706 WARN("Source and destination surfaces should have the same format.\n");
1707 return WINED3DERR_INVALIDCALL
;
1716 else if (dst_point
->x
< 0 || dst_point
->y
< 0)
1718 WARN("Invalid destination point.\n");
1719 return WINED3DERR_INVALIDCALL
;
1726 r
.right
= src_surface
->resource
.width
;
1727 r
.bottom
= src_surface
->resource
.height
;
1730 else if (src_rect
->left
< 0 || src_rect
->left
>= src_rect
->right
1731 || src_rect
->top
< 0 || src_rect
->top
>= src_rect
->bottom
)
1733 WARN("Invalid source rectangle.\n");
1734 return WINED3DERR_INVALIDCALL
;
1737 dst_w
= dst_surface
->resource
.width
;
1738 dst_h
= dst_surface
->resource
.height
;
1740 update_w
= src_rect
->right
- src_rect
->left
;
1741 update_h
= src_rect
->bottom
- src_rect
->top
;
1743 if (update_w
> dst_w
|| dst_point
->x
> dst_w
- update_w
1744 || update_h
> dst_h
|| dst_point
->y
> dst_h
- update_h
)
1746 WARN("Destination out of bounds.\n");
1747 return WINED3DERR_INVALIDCALL
;
1750 if ((src_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(src_surface
, src_rect
))
1752 WARN("Source rectangle not block-aligned.\n");
1753 return WINED3DERR_INVALIDCALL
;
1756 SetRect(&dst_rect
, dst_point
->x
, dst_point
->y
, dst_point
->x
+ update_w
, dst_point
->y
+ update_h
);
1757 if ((dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && !surface_check_block_align(dst_surface
, &dst_rect
))
1759 WARN("Destination rectangle not block-aligned.\n");
1760 return WINED3DERR_INVALIDCALL
;
1763 /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
1764 d3dfmt_get_conv(dst_surface
->container
, FALSE
, &format
, &convert
);
1765 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
1766 return wined3d_surface_blt(dst_surface
, &dst_rect
, src_surface
, src_rect
, 0, NULL
, WINED3D_TEXF_POINT
);
1768 context
= context_acquire(dst_surface
->resource
.device
, NULL
);
1769 gl_info
= context
->gl_info
;
1771 /* Only load the surface for partial updates. For newly allocated texture
1772 * the texture wouldn't be the current location, and we'd upload zeroes
1773 * just to overwrite them again. */
1774 if (update_w
== dst_w
&& update_h
== dst_h
)
1775 surface_prepare_texture(dst_surface
, context
, FALSE
);
1777 surface_load_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1778 wined3d_texture_bind(dst_surface
->container
, context
, FALSE
);
1780 surface_get_memory(src_surface
, &data
, src_surface
->locations
);
1781 src_pitch
= wined3d_surface_get_pitch(src_surface
);
1783 surface_upload_data(dst_surface
, gl_info
, src_format
, src_rect
, src_pitch
, dst_point
, FALSE
, &data
);
1785 context_invalidate_active_texture(context
);
1787 context_release(context
);
1789 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
1790 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
1795 /* This call just allocates the texture, the caller is responsible for binding
1796 * the correct texture. */
1797 /* Context activation is done by the caller. */
1798 static void surface_allocate_surface(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
,
1799 const struct wined3d_format
*format
, BOOL srgb
)
1801 BOOL disable_client_storage
= FALSE
;
1802 GLsizei width
= surface
->pow2Width
;
1803 GLsizei height
= surface
->pow2Height
;
1804 const BYTE
*mem
= NULL
;
1808 internal
= format
->glGammaInternal
;
1809 else if (surface
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1810 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
1811 internal
= format
->rtInternal
;
1813 internal
= format
->glInternal
;
1816 FIXME("No GL internal format for format %s.\n", debug_d3dformat(format
->id
));
1818 if (format
->flags
& WINED3DFMT_FLAG_HEIGHT_SCALE
)
1820 height
*= format
->height_scale
.numerator
;
1821 height
/= format
->height_scale
.denominator
;
1824 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",
1825 surface
, surface
->texture_target
, surface
->texture_level
, debug_d3dformat(format
->id
),
1826 internal
, width
, height
, format
->glFormat
, format
->glType
);
1828 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1830 if (surface
->flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_CONVERTED
)
1831 || !surface
->resource
.heap_memory
)
1833 /* In some cases we want to disable client storage.
1834 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
1835 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
1836 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
1837 * heap_memory == NULL: Not defined in the extension. Seems to disable client storage effectively
1839 surface
->flags
&= ~SFLAG_CLIENT
;
1843 surface
->flags
|= SFLAG_CLIENT
;
1844 mem
= surface
->resource
.heap_memory
;
1846 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1847 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1848 disable_client_storage
= TRUE
;
1852 if (format
->flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
1854 GL_EXTCALL(glCompressedTexImage2DARB(surface
->texture_target
, surface
->texture_level
,
1855 internal
, width
, height
, 0, surface
->resource
.size
, mem
));
1856 checkGLcall("glCompressedTexImage2DARB");
1860 gl_info
->gl_ops
.gl
.p_glTexImage2D(surface
->texture_target
, surface
->texture_level
,
1861 internal
, width
, height
, 0, format
->glFormat
, format
->glType
, mem
);
1862 checkGLcall("glTexImage2D");
1865 if (disable_client_storage
)
1867 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1868 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1872 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1873 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1874 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1875 /* Context activation is done by the caller. */
1876 void surface_set_compatible_renderbuffer(struct wined3d_surface
*surface
, const struct wined3d_surface
*rt
)
1878 const struct wined3d_gl_info
*gl_info
= &surface
->resource
.device
->adapter
->gl_info
;
1879 struct wined3d_renderbuffer_entry
*entry
;
1880 GLuint renderbuffer
= 0;
1881 unsigned int src_width
, src_height
;
1882 unsigned int width
, height
;
1884 if (rt
&& rt
->resource
.format
->id
!= WINED3DFMT_NULL
)
1886 width
= rt
->pow2Width
;
1887 height
= rt
->pow2Height
;
1891 width
= surface
->pow2Width
;
1892 height
= surface
->pow2Height
;
1895 src_width
= surface
->pow2Width
;
1896 src_height
= surface
->pow2Height
;
1898 /* A depth stencil smaller than the render target is not valid */
1899 if (width
> src_width
|| height
> src_height
) return;
1901 /* Remove any renderbuffer set if the sizes match */
1902 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1903 || (width
== src_width
&& height
== src_height
))
1905 surface
->current_renderbuffer
= NULL
;
1909 /* Look if we've already got a renderbuffer of the correct dimensions */
1910 LIST_FOR_EACH_ENTRY(entry
, &surface
->renderbuffers
, struct wined3d_renderbuffer_entry
, entry
)
1912 if (entry
->width
== width
&& entry
->height
== height
)
1914 renderbuffer
= entry
->id
;
1915 surface
->current_renderbuffer
= entry
;
1922 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
1923 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
1924 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
1925 surface
->resource
.format
->glInternal
, width
, height
);
1927 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
1928 entry
->width
= width
;
1929 entry
->height
= height
;
1930 entry
->id
= renderbuffer
;
1931 list_add_head(&surface
->renderbuffers
, &entry
->entry
);
1933 surface
->current_renderbuffer
= entry
;
1936 checkGLcall("set_compatible_renderbuffer");
1939 GLenum
surface_get_gl_buffer(const struct wined3d_surface
*surface
)
1941 const struct wined3d_swapchain
*swapchain
= surface
->container
->swapchain
;
1943 TRACE("surface %p.\n", surface
);
1947 ERR("Surface %p is not on a swapchain.\n", surface
);
1951 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0] == surface
->container
)
1953 if (swapchain
->render_to_fbo
)
1955 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1956 return GL_COLOR_ATTACHMENT0
;
1958 TRACE("Returning GL_BACK\n");
1961 else if (surface
->container
== swapchain
->front_buffer
)
1963 TRACE("Returning GL_FRONT\n");
1967 FIXME("Higher back buffer, returning GL_BACK\n");
1971 void surface_load(struct wined3d_surface
*surface
, BOOL srgb
)
1973 DWORD location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
1976 TRACE("surface %p, srgb %#x.\n", surface
, srgb
);
1978 if (surface
->resource
.pool
== WINED3D_POOL_SCRATCH
)
1979 ERR("Not supported on scratch surfaces.\n");
1981 ck_changed
= !(surface
->flags
& SFLAG_GLCKEY
) != !(surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
);
1983 /* Reload if either the texture and sysmem have different ideas about the
1984 * color key, or the actual key values changed. */
1985 if (ck_changed
|| ((surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
1986 && (surface
->gl_color_key
.color_space_low_value
1987 != surface
->container
->src_blt_color_key
.color_space_low_value
1988 || surface
->gl_color_key
.color_space_high_value
1989 != surface
->container
->src_blt_color_key
.color_space_high_value
)))
1991 TRACE("Reloading because of color keying\n");
1992 /* To perform the color key conversion we need a sysmem copy of
1993 * the surface. Make sure we have it. */
1995 surface_prepare_map_memory(surface
);
1996 surface_load_location(surface
, surface
->resource
.map_binding
);
1997 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
1998 /* Switching color keying on / off may change the internal format. */
2000 surface_force_reload(surface
);
2002 else if (!(surface
->locations
& location
))
2004 TRACE("Reloading because surface is dirty.\n");
2008 TRACE("surface is already in texture\n");
2012 surface_load_location(surface
, location
);
2013 surface_evict_sysmem(surface
);
2016 /* See also float_16_to_32() in wined3d_private.h */
2017 static inline unsigned short float_32_to_16(const float *in
)
2020 float tmp
= fabsf(*in
);
2021 unsigned int mantissa
;
2024 /* Deal with special numbers */
2030 return (*in
< 0.0f
? 0xfc00 : 0x7c00);
2032 if (tmp
< powf(2, 10))
2038 } while (tmp
< powf(2, 10));
2040 else if (tmp
>= powf(2, 11))
2046 } while (tmp
>= powf(2, 11));
2049 mantissa
= (unsigned int)tmp
;
2050 if (tmp
- mantissa
>= 0.5f
)
2051 ++mantissa
; /* Round to nearest, away from zero. */
2053 exp
+= 10; /* Normalize the mantissa. */
2054 exp
+= 15; /* Exponent is encoded with excess 15. */
2056 if (exp
> 30) /* too big */
2058 ret
= 0x7c00; /* INF */
2062 /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2065 mantissa
= mantissa
>> 1;
2068 ret
= mantissa
& 0x3ff;
2072 ret
= (exp
<< 10) | (mantissa
& 0x3ff);
2075 ret
|= ((*in
< 0.0f
? 1 : 0) << 15); /* Add the sign */
2079 ULONG CDECL
wined3d_surface_incref(struct wined3d_surface
*surface
)
2081 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
2083 return wined3d_texture_incref(surface
->container
);
2086 ULONG CDECL
wined3d_surface_decref(struct wined3d_surface
*surface
)
2088 TRACE("surface %p, container %p.\n", surface
, surface
->container
);
2090 return wined3d_texture_decref(surface
->container
);
2093 void CDECL
wined3d_surface_preload(struct wined3d_surface
*surface
)
2095 TRACE("surface %p.\n", surface
);
2097 if (!surface
->resource
.device
->d3d_initialized
)
2099 ERR("D3D not initialized.\n");
2103 wined3d_texture_preload(surface
->container
);
2106 void * CDECL
wined3d_surface_get_parent(const struct wined3d_surface
*surface
)
2108 TRACE("surface %p.\n", surface
);
2110 return surface
->resource
.parent
;
2113 struct wined3d_resource
* CDECL
wined3d_surface_get_resource(struct wined3d_surface
*surface
)
2115 TRACE("surface %p.\n", surface
);
2117 return &surface
->resource
;
2120 HRESULT CDECL
wined3d_surface_get_blt_status(const struct wined3d_surface
*surface
, DWORD flags
)
2122 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2126 case WINEDDGBS_CANBLT
:
2127 case WINEDDGBS_ISBLTDONE
:
2131 return WINED3DERR_INVALIDCALL
;
2135 HRESULT CDECL
wined3d_surface_get_flip_status(const struct wined3d_surface
*surface
, DWORD flags
)
2137 TRACE("surface %p, flags %#x.\n", surface
, flags
);
2139 /* XXX: DDERR_INVALIDSURFACETYPE */
2143 case WINEDDGFS_CANFLIP
:
2144 case WINEDDGFS_ISFLIPDONE
:
2148 return WINED3DERR_INVALIDCALL
;
2152 HRESULT CDECL
wined3d_surface_is_lost(const struct wined3d_surface
*surface
)
2154 TRACE("surface %p.\n", surface
);
2156 /* D3D8 and 9 loose full devices, ddraw only surfaces. */
2157 return surface
->flags
& SFLAG_LOST
? WINED3DERR_DEVICELOST
: WINED3D_OK
;
2160 HRESULT CDECL
wined3d_surface_restore(struct wined3d_surface
*surface
)
2162 TRACE("surface %p.\n", surface
);
2164 surface
->flags
&= ~SFLAG_LOST
;
2168 DWORD CDECL
wined3d_surface_get_pitch(const struct wined3d_surface
*surface
)
2170 unsigned int alignment
;
2173 TRACE("surface %p.\n", surface
);
2176 return surface
->pitch
;
2178 alignment
= surface
->resource
.device
->surface_alignment
;
2179 pitch
= wined3d_format_calculate_pitch(surface
->resource
.format
, surface
->resource
.width
);
2180 pitch
= (pitch
+ alignment
- 1) & ~(alignment
- 1);
2182 TRACE("Returning %u.\n", pitch
);
2187 HRESULT CDECL
wined3d_surface_set_overlay_position(struct wined3d_surface
*surface
, LONG x
, LONG y
)
2191 TRACE("surface %p, x %d, y %d.\n", surface
, x
, y
);
2193 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2195 WARN("Not an overlay surface.\n");
2196 return WINEDDERR_NOTAOVERLAYSURFACE
;
2199 w
= surface
->overlay_destrect
.right
- surface
->overlay_destrect
.left
;
2200 h
= surface
->overlay_destrect
.bottom
- surface
->overlay_destrect
.top
;
2201 surface
->overlay_destrect
.left
= x
;
2202 surface
->overlay_destrect
.top
= y
;
2203 surface
->overlay_destrect
.right
= x
+ w
;
2204 surface
->overlay_destrect
.bottom
= y
+ h
;
2209 HRESULT CDECL
wined3d_surface_get_overlay_position(const struct wined3d_surface
*surface
, LONG
*x
, LONG
*y
)
2211 TRACE("surface %p, x %p, y %p.\n", surface
, x
, y
);
2213 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2215 TRACE("Not an overlay surface.\n");
2216 return WINEDDERR_NOTAOVERLAYSURFACE
;
2219 if (!surface
->overlay_dest
)
2221 TRACE("Overlay not visible.\n");
2224 return WINEDDERR_OVERLAYNOTVISIBLE
;
2227 *x
= surface
->overlay_destrect
.left
;
2228 *y
= surface
->overlay_destrect
.top
;
2230 TRACE("Returning position %d, %d.\n", *x
, *y
);
2235 HRESULT CDECL
wined3d_surface_update_overlay_z_order(struct wined3d_surface
*surface
,
2236 DWORD flags
, struct wined3d_surface
*ref
)
2238 FIXME("surface %p, flags %#x, ref %p stub!\n", surface
, flags
, ref
);
2240 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2242 TRACE("Not an overlay surface.\n");
2243 return WINEDDERR_NOTAOVERLAYSURFACE
;
2249 HRESULT CDECL
wined3d_surface_update_overlay(struct wined3d_surface
*surface
, const RECT
*src_rect
,
2250 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
, DWORD flags
, const WINEDDOVERLAYFX
*fx
)
2252 TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2253 surface
, wine_dbgstr_rect(src_rect
), dst_surface
, wine_dbgstr_rect(dst_rect
), flags
, fx
);
2255 if (!(surface
->resource
.usage
& WINED3DUSAGE_OVERLAY
))
2257 WARN("Not an overlay surface.\n");
2258 return WINEDDERR_NOTAOVERLAYSURFACE
;
2260 else if (!dst_surface
)
2262 WARN("Dest surface is NULL.\n");
2263 return WINED3DERR_INVALIDCALL
;
2268 surface
->overlay_srcrect
= *src_rect
;
2272 surface
->overlay_srcrect
.left
= 0;
2273 surface
->overlay_srcrect
.top
= 0;
2274 surface
->overlay_srcrect
.right
= surface
->resource
.width
;
2275 surface
->overlay_srcrect
.bottom
= surface
->resource
.height
;
2280 surface
->overlay_destrect
= *dst_rect
;
2284 surface
->overlay_destrect
.left
= 0;
2285 surface
->overlay_destrect
.top
= 0;
2286 surface
->overlay_destrect
.right
= dst_surface
? dst_surface
->resource
.width
: 0;
2287 surface
->overlay_destrect
.bottom
= dst_surface
? dst_surface
->resource
.height
: 0;
2290 if (surface
->overlay_dest
&& (surface
->overlay_dest
!= dst_surface
|| flags
& WINEDDOVER_HIDE
))
2292 surface
->overlay_dest
= NULL
;
2293 list_remove(&surface
->overlay_entry
);
2296 if (flags
& WINEDDOVER_SHOW
)
2298 if (surface
->overlay_dest
!= dst_surface
)
2300 surface
->overlay_dest
= dst_surface
;
2301 list_add_tail(&dst_surface
->overlays
, &surface
->overlay_entry
);
2304 else if (flags
& WINEDDOVER_HIDE
)
2306 /* tests show that the rectangles are erased on hide */
2307 surface
->overlay_srcrect
.left
= 0; surface
->overlay_srcrect
.top
= 0;
2308 surface
->overlay_srcrect
.right
= 0; surface
->overlay_srcrect
.bottom
= 0;
2309 surface
->overlay_destrect
.left
= 0; surface
->overlay_destrect
.top
= 0;
2310 surface
->overlay_destrect
.right
= 0; surface
->overlay_destrect
.bottom
= 0;
2311 surface
->overlay_dest
= NULL
;
2317 HRESULT
wined3d_surface_update_desc(struct wined3d_surface
*surface
,
2318 const struct wined3d_gl_info
*gl_info
, void *mem
, unsigned int pitch
)
2320 struct wined3d_resource
*texture_resource
= &surface
->container
->resource
;
2321 unsigned int width
, height
;
2322 BOOL create_dib
= FALSE
;
2323 DWORD valid_location
= 0;
2326 if (surface
->flags
& SFLAG_DIBSECTION
)
2328 DeleteDC(surface
->hDC
);
2329 DeleteObject(surface
->dib
.DIBsection
);
2330 surface
->dib
.bitmap_data
= NULL
;
2331 surface
->flags
&= ~SFLAG_DIBSECTION
;
2335 surface
->locations
= 0;
2336 wined3d_resource_free_sysmem(&surface
->resource
);
2338 width
= texture_resource
->width
;
2339 height
= texture_resource
->height
;
2340 surface
->resource
.width
= width
;
2341 surface
->resource
.height
= height
;
2342 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
2343 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
2345 surface
->pow2Width
= width
;
2346 surface
->pow2Height
= height
;
2350 surface
->pow2Width
= surface
->pow2Height
= 1;
2351 while (surface
->pow2Width
< width
)
2352 surface
->pow2Width
<<= 1;
2353 while (surface
->pow2Height
< height
)
2354 surface
->pow2Height
<<= 1;
2357 if (surface
->pow2Width
!= width
|| surface
->pow2Height
!= height
)
2358 surface
->flags
|= SFLAG_NONPOW2
;
2360 surface
->flags
&= ~SFLAG_NONPOW2
;
2362 if ((surface
->user_memory
= mem
))
2364 surface
->resource
.map_binding
= WINED3D_LOCATION_USER_MEMORY
;
2365 valid_location
= WINED3D_LOCATION_USER_MEMORY
;
2367 surface
->pitch
= pitch
;
2368 surface
->resource
.format
= texture_resource
->format
;
2369 surface
->resource
.multisample_type
= texture_resource
->multisample_type
;
2370 surface
->resource
.multisample_quality
= texture_resource
->multisample_quality
;
2372 surface
->resource
.size
= height
* surface
->pitch
;
2374 surface
->resource
.size
= wined3d_format_calculate_size(texture_resource
->format
,
2375 texture_resource
->device
->surface_alignment
, width
, height
, 1);
2377 /* The format might be changed to a format that needs conversion.
2378 * If the surface didn't use PBOs previously but could now, don't
2379 * change it - whatever made us not use PBOs might come back, e.g.
2381 if (surface
->resource
.map_binding
== WINED3D_LOCATION_BUFFER
&& !surface_use_pbo(surface
))
2382 surface
->resource
.map_binding
= create_dib
? WINED3D_LOCATION_DIB
: WINED3D_LOCATION_SYSMEM
;
2386 if (FAILED(hr
= surface_create_dib_section(surface
)))
2388 ERR("Failed to create dib section, hr %#x.\n", hr
);
2391 if (!valid_location
)
2392 valid_location
= WINED3D_LOCATION_DIB
;
2395 if (!valid_location
)
2397 surface_prepare_system_memory(surface
);
2398 valid_location
= WINED3D_LOCATION_SYSMEM
;
2401 surface_validate_location(surface
, valid_location
);
2406 static void convert_r32_float_r16_float(const BYTE
*src
, BYTE
*dst
,
2407 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2409 unsigned short *dst_s
;
2413 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2415 for (y
= 0; y
< h
; ++y
)
2417 src_f
= (const float *)(src
+ y
* pitch_in
);
2418 dst_s
= (unsigned short *) (dst
+ y
* pitch_out
);
2419 for (x
= 0; x
< w
; ++x
)
2421 dst_s
[x
] = float_32_to_16(src_f
+ x
);
2426 static void convert_r5g6b5_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2427 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2429 static const unsigned char convert_5to8
[] =
2431 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2432 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2433 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2434 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2436 static const unsigned char convert_6to8
[] =
2438 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2439 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2440 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2441 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2442 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2443 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2444 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2445 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2449 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2451 for (y
= 0; y
< h
; ++y
)
2453 const WORD
*src_line
= (const WORD
*)(src
+ y
* pitch_in
);
2454 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2455 for (x
= 0; x
< w
; ++x
)
2457 WORD pixel
= src_line
[x
];
2458 dst_line
[x
] = 0xff000000
2459 | convert_5to8
[(pixel
& 0xf800) >> 11] << 16
2460 | convert_6to8
[(pixel
& 0x07e0) >> 5] << 8
2461 | convert_5to8
[(pixel
& 0x001f)];
2466 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
2467 * in both cases we're just setting the X / Alpha channel to 0xff. */
2468 static void convert_a8r8g8b8_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2469 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2473 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2475 for (y
= 0; y
< h
; ++y
)
2477 const DWORD
*src_line
= (const DWORD
*)(src
+ y
* pitch_in
);
2478 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2480 for (x
= 0; x
< w
; ++x
)
2482 dst_line
[x
] = 0xff000000 | (src_line
[x
] & 0xffffff);
2487 static inline BYTE
cliptobyte(int x
)
2489 return (BYTE
)((x
< 0) ? 0 : ((x
> 255) ? 255 : x
));
2492 static void convert_yuy2_x8r8g8b8(const BYTE
*src
, BYTE
*dst
,
2493 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2495 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2498 TRACE("Converting %ux%u pixels, pitches %u %u.\n", w
, h
, pitch_in
, pitch_out
);
2500 for (y
= 0; y
< h
; ++y
)
2502 const BYTE
*src_line
= src
+ y
* pitch_in
;
2503 DWORD
*dst_line
= (DWORD
*)(dst
+ y
* pitch_out
);
2504 for (x
= 0; x
< w
; ++x
)
2506 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2507 * C = Y - 16; D = U - 128; E = V - 128;
2508 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2509 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2510 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2511 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2512 * U and V are shared between the pixels. */
2513 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2515 d
= (int) src_line
[1] - 128;
2516 e
= (int) src_line
[3] - 128;
2518 g2
= - 100 * d
- 208 * e
+ 128;
2521 c2
= 298 * ((int) src_line
[0] - 16);
2522 dst_line
[x
] = 0xff000000
2523 | cliptobyte((c2
+ r2
) >> 8) << 16 /* red */
2524 | cliptobyte((c2
+ g2
) >> 8) << 8 /* green */
2525 | cliptobyte((c2
+ b2
) >> 8); /* blue */
2526 /* Scale RGB values to 0..255 range,
2527 * then clip them if still not in range (may be negative),
2528 * then shift them within DWORD if necessary. */
2534 static void convert_yuy2_r5g6b5(const BYTE
*src
, BYTE
*dst
,
2535 DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
)
2538 int c2
, d
, e
, r2
= 0, g2
= 0, b2
= 0;
2540 TRACE("Converting %ux%u pixels, pitches %u %u\n", w
, h
, pitch_in
, pitch_out
);
2542 for (y
= 0; y
< h
; ++y
)
2544 const BYTE
*src_line
= src
+ y
* pitch_in
;
2545 WORD
*dst_line
= (WORD
*)(dst
+ y
* pitch_out
);
2546 for (x
= 0; x
< w
; ++x
)
2548 /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2549 * C = Y - 16; D = U - 128; E = V - 128;
2550 * R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2551 * G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2552 * B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2553 * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2554 * U and V are shared between the pixels. */
2555 if (!(x
& 1)) /* For every even pixel, read new U and V. */
2557 d
= (int) src_line
[1] - 128;
2558 e
= (int) src_line
[3] - 128;
2560 g2
= - 100 * d
- 208 * e
+ 128;
2563 c2
= 298 * ((int) src_line
[0] - 16);
2564 dst_line
[x
] = (cliptobyte((c2
+ r2
) >> 8) >> 3) << 11 /* red */
2565 | (cliptobyte((c2
+ g2
) >> 8) >> 2) << 5 /* green */
2566 | (cliptobyte((c2
+ b2
) >> 8) >> 3); /* blue */
2567 /* Scale RGB values to 0..255 range,
2568 * then clip them if still not in range (may be negative),
2569 * then shift them within DWORD if necessary. */
2575 struct d3dfmt_converter_desc
2577 enum wined3d_format_id from
, to
;
2578 void (*convert
)(const BYTE
*src
, BYTE
*dst
, DWORD pitch_in
, DWORD pitch_out
, unsigned int w
, unsigned int h
);
2581 static const struct d3dfmt_converter_desc converters
[] =
2583 {WINED3DFMT_R32_FLOAT
, WINED3DFMT_R16_FLOAT
, convert_r32_float_r16_float
},
2584 {WINED3DFMT_B5G6R5_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_r5g6b5_x8r8g8b8
},
2585 {WINED3DFMT_B8G8R8A8_UNORM
, WINED3DFMT_B8G8R8X8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2586 {WINED3DFMT_B8G8R8X8_UNORM
, WINED3DFMT_B8G8R8A8_UNORM
, convert_a8r8g8b8_x8r8g8b8
},
2587 {WINED3DFMT_YUY2
, WINED3DFMT_B8G8R8X8_UNORM
, convert_yuy2_x8r8g8b8
},
2588 {WINED3DFMT_YUY2
, WINED3DFMT_B5G6R5_UNORM
, convert_yuy2_r5g6b5
},
2591 static inline const struct d3dfmt_converter_desc
*find_converter(enum wined3d_format_id from
,
2592 enum wined3d_format_id to
)
2596 for (i
= 0; i
< (sizeof(converters
) / sizeof(*converters
)); ++i
)
2598 if (converters
[i
].from
== from
&& converters
[i
].to
== to
)
2599 return &converters
[i
];
2605 static struct wined3d_texture
*surface_convert_format(struct wined3d_surface
*source
, enum wined3d_format_id to_fmt
)
2607 struct wined3d_map_desc src_map
, dst_map
;
2608 const struct d3dfmt_converter_desc
*conv
;
2609 struct wined3d_texture
*ret
= NULL
;
2610 struct wined3d_resource_desc desc
;
2611 struct wined3d_surface
*dst
;
2613 conv
= find_converter(source
->resource
.format
->id
, to_fmt
);
2616 FIXME("Cannot find a conversion function from format %s to %s.\n",
2617 debug_d3dformat(source
->resource
.format
->id
), debug_d3dformat(to_fmt
));
2621 /* FIXME: Multisampled conversion? */
2622 wined3d_resource_get_desc(&source
->resource
, &desc
);
2623 desc
.resource_type
= WINED3D_RTYPE_TEXTURE
;
2624 desc
.format
= to_fmt
;
2626 desc
.pool
= WINED3D_POOL_SCRATCH
;
2627 if (FAILED(wined3d_texture_create(source
->resource
.device
, &desc
, 1,
2628 WINED3D_SURFACE_MAPPABLE
| WINED3D_SURFACE_DISCARD
, NULL
, &wined3d_null_parent_ops
, &ret
)))
2630 ERR("Failed to create a destination surface for conversion.\n");
2633 dst
= surface_from_resource(wined3d_texture_get_sub_resource(ret
, 0));
2635 memset(&src_map
, 0, sizeof(src_map
));
2636 memset(&dst_map
, 0, sizeof(dst_map
));
2638 if (FAILED(wined3d_surface_map(source
, &src_map
, NULL
, WINED3D_MAP_READONLY
)))
2640 ERR("Failed to lock the source surface.\n");
2641 wined3d_texture_decref(ret
);
2644 if (FAILED(wined3d_surface_map(dst
, &dst_map
, NULL
, 0)))
2646 ERR("Failed to lock the destination surface.\n");
2647 wined3d_surface_unmap(source
);
2648 wined3d_texture_decref(ret
);
2652 conv
->convert(src_map
.data
, dst_map
.data
, src_map
.row_pitch
, dst_map
.row_pitch
,
2653 source
->resource
.width
, source
->resource
.height
);
2655 wined3d_surface_unmap(dst
);
2656 wined3d_surface_unmap(source
);
2661 static HRESULT
_Blt_ColorFill(BYTE
*buf
, unsigned int width
, unsigned int height
,
2662 unsigned int bpp
, UINT pitch
, DWORD color
)
2669 #define COLORFILL_ROW(type) \
2671 type *d = (type *)buf; \
2672 for (x = 0; x < width; ++x) \
2673 d[x] = (type)color; \
2679 COLORFILL_ROW(BYTE
);
2683 COLORFILL_ROW(WORD
);
2689 for (x
= 0; x
< width
; ++x
, d
+= 3)
2691 d
[0] = (color
) & 0xff;
2692 d
[1] = (color
>> 8) & 0xff;
2693 d
[2] = (color
>> 16) & 0xff;
2698 COLORFILL_ROW(DWORD
);
2702 FIXME("Color fill not implemented for bpp %u!\n", bpp
* 8);
2703 return WINED3DERR_NOTAVAILABLE
;
2706 #undef COLORFILL_ROW
2708 /* Now copy first row. */
2710 for (y
= 1; y
< height
; ++y
)
2713 memcpy(buf
, first
, width
* bpp
);
2719 struct wined3d_surface
* CDECL
wined3d_surface_from_resource(struct wined3d_resource
*resource
)
2721 return surface_from_resource(resource
);
2724 HRESULT CDECL
wined3d_surface_unmap(struct wined3d_surface
*surface
)
2726 TRACE("surface %p.\n", surface
);
2728 if (!surface
->resource
.map_count
)
2730 WARN("Trying to unmap unmapped surface.\n");
2731 return WINEDDERR_NOTLOCKED
;
2733 --surface
->resource
.map_count
;
2735 surface
->surface_ops
->surface_unmap(surface
);
2740 HRESULT CDECL
wined3d_surface_map(struct wined3d_surface
*surface
,
2741 struct wined3d_map_desc
*map_desc
, const RECT
*rect
, DWORD flags
)
2743 const struct wined3d_format
*format
= surface
->resource
.format
;
2744 struct wined3d_device
*device
= surface
->resource
.device
;
2745 struct wined3d_context
*context
;
2746 const struct wined3d_gl_info
*gl_info
;
2749 TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
2750 surface
, map_desc
, wine_dbgstr_rect(rect
), flags
);
2752 if (surface
->resource
.map_count
)
2754 WARN("Surface is already mapped.\n");
2755 return WINED3DERR_INVALIDCALL
;
2758 if ((format
->flags
& WINED3DFMT_FLAG_BLOCKS
) && rect
2759 && !surface_check_block_align(surface
, rect
))
2761 WARN("Map rect %s is misaligned for %ux%u blocks.\n",
2762 wine_dbgstr_rect(rect
), format
->block_width
, format
->block_height
);
2764 if (surface
->resource
.pool
== WINED3D_POOL_DEFAULT
)
2765 return WINED3DERR_INVALIDCALL
;
2768 ++surface
->resource
.map_count
;
2770 if (!(surface
->resource
.access_flags
& WINED3D_RESOURCE_ACCESS_CPU
))
2771 WARN("Trying to lock unlockable surface.\n");
2773 /* Performance optimization: Count how often a surface is mapped, if it is
2774 * mapped regularly do not throw away the system memory copy. This avoids
2775 * the need to download the surface from OpenGL all the time. The surface
2776 * is still downloaded if the OpenGL texture is changed. */
2777 if (!(surface
->flags
& SFLAG_DYNLOCK
) && surface
->resource
.map_binding
== WINED3D_LOCATION_SYSMEM
)
2779 if (++surface
->lockCount
> MAXLOCKCOUNT
)
2781 TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
2782 surface
->flags
|= SFLAG_DYNLOCK
;
2786 surface_prepare_map_memory(surface
);
2787 if (flags
& WINED3D_MAP_DISCARD
)
2789 TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
2790 wined3d_debug_location(surface
->resource
.map_binding
));
2791 surface_validate_location(surface
, surface
->resource
.map_binding
);
2795 if (surface
->resource
.usage
& WINED3DUSAGE_DYNAMIC
)
2796 WARN_(d3d_perf
)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
2798 surface_load_location(surface
, surface
->resource
.map_binding
);
2801 if (!(flags
& (WINED3D_MAP_NO_DIRTY_UPDATE
| WINED3D_MAP_READONLY
)))
2802 surface_invalidate_location(surface
, ~surface
->resource
.map_binding
);
2804 switch (surface
->resource
.map_binding
)
2806 case WINED3D_LOCATION_SYSMEM
:
2807 base_memory
= surface
->resource
.heap_memory
;
2810 case WINED3D_LOCATION_USER_MEMORY
:
2811 base_memory
= surface
->user_memory
;
2814 case WINED3D_LOCATION_DIB
:
2815 base_memory
= surface
->dib
.bitmap_data
;
2818 case WINED3D_LOCATION_BUFFER
:
2819 context
= context_acquire(device
, NULL
);
2820 gl_info
= context
->gl_info
;
2822 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, surface
->pbo
));
2823 base_memory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
2824 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
2825 checkGLcall("map PBO");
2827 context_release(context
);
2831 ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface
->resource
.map_binding
));
2835 if (format
->flags
& WINED3DFMT_FLAG_BROKEN_PITCH
)
2836 map_desc
->row_pitch
= surface
->resource
.width
* format
->byte_count
;
2838 map_desc
->row_pitch
= wined3d_surface_get_pitch(surface
);
2839 map_desc
->slice_pitch
= 0;
2843 map_desc
->data
= base_memory
;
2844 surface
->lockedRect
.left
= 0;
2845 surface
->lockedRect
.top
= 0;
2846 surface
->lockedRect
.right
= surface
->resource
.width
;
2847 surface
->lockedRect
.bottom
= surface
->resource
.height
;
2851 if ((format
->flags
& (WINED3DFMT_FLAG_BLOCKS
| WINED3DFMT_FLAG_BROKEN_PITCH
)) == WINED3DFMT_FLAG_BLOCKS
)
2853 /* Compressed textures are block based, so calculate the offset of
2854 * the block that contains the top-left pixel of the locked rectangle. */
2855 map_desc
->data
= base_memory
2856 + ((rect
->top
/ format
->block_height
) * map_desc
->row_pitch
)
2857 + ((rect
->left
/ format
->block_width
) * format
->block_byte_count
);
2861 map_desc
->data
= base_memory
2862 + (map_desc
->row_pitch
* rect
->top
)
2863 + (rect
->left
* format
->byte_count
);
2865 surface
->lockedRect
.left
= rect
->left
;
2866 surface
->lockedRect
.top
= rect
->top
;
2867 surface
->lockedRect
.right
= rect
->right
;
2868 surface
->lockedRect
.bottom
= rect
->bottom
;
2871 TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface
->lockedRect
));
2872 TRACE("Returning memory %p, pitch %u.\n", map_desc
->data
, map_desc
->row_pitch
);
2877 HRESULT CDECL
wined3d_surface_getdc(struct wined3d_surface
*surface
, HDC
*dc
)
2881 TRACE("surface %p, dc %p.\n", surface
, dc
);
2883 /* Give more detailed info for ddraw. */
2884 if (surface
->flags
& SFLAG_DCINUSE
)
2885 return WINEDDERR_DCALREADYCREATED
;
2887 /* Can't GetDC if the surface is locked. */
2888 if (surface
->resource
.map_count
)
2889 return WINED3DERR_INVALIDCALL
;
2891 /* Create a DIB section if there isn't a dc yet. */
2894 if (surface
->flags
& SFLAG_CLIENT
)
2896 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
2897 surface_release_client_storage(surface
);
2899 hr
= surface_create_dib_section(surface
);
2901 return WINED3DERR_INVALIDCALL
;
2902 if (!(surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
2903 || surface
->flags
& SFLAG_PIN_SYSMEM
2905 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
2908 surface_load_location(surface
, WINED3D_LOCATION_DIB
);
2909 surface_invalidate_location(surface
, ~WINED3D_LOCATION_DIB
);
2911 surface
->flags
|= SFLAG_DCINUSE
;
2912 surface
->resource
.map_count
++;
2915 TRACE("Returning dc %p.\n", *dc
);
2920 HRESULT CDECL
wined3d_surface_releasedc(struct wined3d_surface
*surface
, HDC dc
)
2922 TRACE("surface %p, dc %p.\n", surface
, dc
);
2924 if (!(surface
->flags
& SFLAG_DCINUSE
))
2925 return WINEDDERR_NODC
;
2927 if (surface
->hDC
!= dc
)
2929 WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
2931 return WINEDDERR_NODC
;
2934 surface
->resource
.map_count
--;
2935 surface
->flags
&= ~SFLAG_DCINUSE
;
2937 if (surface
->resource
.map_binding
== WINED3D_LOCATION_USER_MEMORY
|| (surface
->flags
& SFLAG_PIN_SYSMEM
2938 && surface
->resource
.map_binding
!= WINED3D_LOCATION_DIB
))
2940 /* The game Salammbo modifies the surface contents without mapping the surface between
2941 * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
2942 * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
2943 * Do not only copy the DIB to the map location, but also make sure the map location is
2944 * copied back to the DIB in the next getdc call.
2946 * The same consideration applies to user memory surfaces. */
2947 surface_load_location(surface
, surface
->resource
.map_binding
);
2948 surface_invalidate_location(surface
, WINED3D_LOCATION_DIB
);
2954 static void read_from_framebuffer(struct wined3d_surface
*surface
, DWORD dst_location
)
2956 struct wined3d_device
*device
= surface
->resource
.device
;
2957 const struct wined3d_gl_info
*gl_info
;
2958 struct wined3d_context
*context
;
2960 BYTE
*row
, *top
, *bottom
;
2962 BOOL srcIsUpsideDown
;
2963 struct wined3d_bo_address data
;
2965 surface_get_memory(surface
, &data
, dst_location
);
2967 context
= context_acquire(device
, surface
);
2968 context_apply_blit_state(context
, device
);
2969 gl_info
= context
->gl_info
;
2971 /* Select the correct read buffer, and give some debug output.
2972 * There is no need to keep track of the current read buffer or reset it, every part of the code
2973 * that reads sets the read buffer as desired.
2975 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
2977 /* Mapping the primary render target which is not on a swapchain.
2978 * Read from the back buffer. */
2979 TRACE("Mapping offscreen render target.\n");
2980 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
2981 srcIsUpsideDown
= TRUE
;
2985 /* Onscreen surfaces are always part of a swapchain */
2986 GLenum buffer
= surface_get_gl_buffer(surface
);
2987 TRACE("Mapping %#x buffer.\n", buffer
);
2988 gl_info
->gl_ops
.gl
.p_glReadBuffer(buffer
);
2989 checkGLcall("glReadBuffer");
2990 srcIsUpsideDown
= FALSE
;
2993 if (data
.buffer_object
)
2995 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, data
.buffer_object
));
2996 checkGLcall("glBindBufferARB");
2999 /* Setup pixel store pack state -- to glReadPixels into the correct place */
3000 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, surface
->resource
.width
);
3001 checkGLcall("glPixelStorei");
3003 gl_info
->gl_ops
.gl
.p_glReadPixels(0, 0,
3004 surface
->resource
.width
, surface
->resource
.height
,
3005 surface
->resource
.format
->glFormat
,
3006 surface
->resource
.format
->glType
, data
.addr
);
3007 checkGLcall("glReadPixels");
3009 /* Reset previous pixel store pack state */
3010 gl_info
->gl_ops
.gl
.p_glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
3011 checkGLcall("glPixelStorei");
3013 if (!srcIsUpsideDown
)
3015 /* glReadPixels returns the image upside down, and there is no way to prevent this.
3016 * Flip the lines in software. */
3017 UINT pitch
= wined3d_surface_get_pitch(surface
);
3019 if (!(row
= HeapAlloc(GetProcessHeap(), 0, pitch
)))
3022 if (data
.buffer_object
)
3024 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
3025 checkGLcall("glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB)");
3031 bottom
= mem
+ pitch
* (surface
->resource
.height
- 1);
3032 for (i
= 0; i
< surface
->resource
.height
/ 2; i
++)
3034 memcpy(row
, top
, pitch
);
3035 memcpy(top
, bottom
, pitch
);
3036 memcpy(bottom
, row
, pitch
);
3040 HeapFree(GetProcessHeap(), 0, row
);
3042 if (data
.buffer_object
)
3043 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB
));
3047 if (data
.buffer_object
)
3049 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
3050 checkGLcall("glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0)");
3053 context_release(context
);
3056 /* Read the framebuffer contents into a texture. Note that this function
3057 * doesn't do any kind of flipping. Using this on an onscreen surface will
3058 * result in a flipped D3D texture. */
3059 void surface_load_fb_texture(struct wined3d_surface
*surface
, BOOL srgb
)
3061 struct wined3d_device
*device
= surface
->resource
.device
;
3062 const struct wined3d_gl_info
*gl_info
;
3063 struct wined3d_context
*context
;
3065 context
= context_acquire(device
, surface
);
3066 gl_info
= context
->gl_info
;
3067 device_invalidate_state(device
, STATE_FRAMEBUFFER
);
3069 surface_prepare_texture(surface
, context
, srgb
);
3070 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3072 TRACE("Reading back offscreen render target %p.\n", surface
);
3074 if (wined3d_resource_is_offscreen(&surface
->container
->resource
))
3075 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3077 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(surface
));
3078 checkGLcall("glReadBuffer");
3080 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(surface
->texture_target
, surface
->texture_level
,
3081 0, 0, 0, 0, surface
->resource
.width
, surface
->resource
.height
);
3082 checkGLcall("glCopyTexSubImage2D");
3084 context_release(context
);
3087 /* Context activation is done by the caller. */
3088 static void surface_prepare_texture_internal(struct wined3d_surface
*surface
,
3089 struct wined3d_context
*context
, BOOL srgb
)
3091 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
3092 enum wined3d_conversion_type convert
;
3093 struct wined3d_format format
;
3095 if (surface
->flags
& alloc_flag
) return;
3097 d3dfmt_get_conv(surface
->container
, TRUE
, &format
, &convert
);
3098 if (convert
!= WINED3D_CT_NONE
|| format
.convert
)
3099 surface
->flags
|= SFLAG_CONVERTED
;
3100 else surface
->flags
&= ~SFLAG_CONVERTED
;
3102 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
3103 surface_allocate_surface(surface
, context
->gl_info
, &format
, srgb
);
3104 surface
->flags
|= alloc_flag
;
3107 /* Context activation is done by the caller. */
3108 void surface_prepare_texture(struct wined3d_surface
*surface
, struct wined3d_context
*context
, BOOL srgb
)
3110 struct wined3d_texture
*texture
= surface
->container
;
3111 UINT sub_count
= texture
->level_count
* texture
->layer_count
;
3114 TRACE("surface %p is a subresource of texture %p.\n", surface
, texture
);
3116 for (i
= 0; i
< sub_count
; ++i
)
3118 struct wined3d_surface
*s
= surface_from_resource(texture
->sub_resources
[i
]);
3119 surface_prepare_texture_internal(s
, context
, srgb
);
3125 void surface_prepare_rb(struct wined3d_surface
*surface
, const struct wined3d_gl_info
*gl_info
, BOOL multisample
)
3129 if (surface
->rb_multisample
)
3132 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_multisample
);
3133 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_multisample
);
3134 gl_info
->fbo_ops
.glRenderbufferStorageMultisample(GL_RENDERBUFFER
, surface
->resource
.multisample_type
,
3135 surface
->resource
.format
->glInternal
, surface
->pow2Width
, surface
->pow2Height
);
3136 TRACE("Created multisample rb %u.\n", surface
->rb_multisample
);
3140 if (surface
->rb_resolved
)
3143 gl_info
->fbo_ops
.glGenRenderbuffers(1, &surface
->rb_resolved
);
3144 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, surface
->rb_resolved
);
3145 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, surface
->resource
.format
->glInternal
,
3146 surface
->pow2Width
, surface
->pow2Height
);
3147 TRACE("Created resolved rb %u.\n", surface
->rb_resolved
);
3151 static BOOL
color_in_range(const struct wined3d_color_key
*color_key
, DWORD color
)
3153 /* FIXME: Is this really how color keys are supposed to work? I think it
3154 * makes more sense to compare the individual channels. */
3155 return color
>= color_key
->color_space_low_value
3156 && color
<= color_key
->color_space_high_value
;
3159 static void convert_p8_uint_b8g8r8a8_unorm(const BYTE
*src
, unsigned int src_pitch
,
3160 BYTE
*dst
, unsigned int dst_pitch
, unsigned int width
, unsigned int height
,
3161 const struct wined3d_palette
*palette
, const struct wined3d_color_key
*color_key
)
3163 const BYTE
*src_row
;
3169 /* FIXME: This should probably use the system palette. */
3170 FIXME("P8 surface loaded without a palette.\n");
3172 for (y
= 0; y
< height
; ++y
)
3174 memset(&dst
[dst_pitch
* y
], 0, width
* 4);
3180 for (y
= 0; y
< height
; ++y
)
3182 src_row
= &src
[src_pitch
* y
];
3183 dst_row
= (DWORD
*)&dst
[dst_pitch
* y
];
3184 for (x
= 0; x
< width
; ++x
)
3186 BYTE src_color
= src_row
[x
];
3187 dst_row
[x
] = 0xff000000
3188 | (palette
->colors
[src_color
].rgbRed
<< 16)
3189 | (palette
->colors
[src_color
].rgbGreen
<< 8)
3190 | palette
->colors
[src_color
].rgbBlue
;
3195 static void convert_b5g6r5_unorm_b5g5r5a1_unorm_color_key(const BYTE
*src
, unsigned int src_pitch
,
3196 BYTE
*dst
, unsigned int dst_pitch
, unsigned int width
, unsigned int height
,
3197 const struct wined3d_color_key
*color_key
)
3199 const WORD
*src_row
;
3203 for (y
= 0; y
< height
; ++y
)
3205 src_row
= (WORD
*)&src
[src_pitch
* y
];
3206 dst_row
= (WORD
*)&dst
[dst_pitch
* y
];
3207 for (x
= 0; x
< width
; ++x
)
3209 WORD src_color
= src_row
[x
];
3210 if (!color_in_range(color_key
, src_color
))
3211 dst_row
[x
] = 0x8000 | ((src_color
& 0xffc0) >> 1) | (src_color
& 0x1f);
3213 dst_row
[x
] = ((src_color
& 0xffc0) >> 1) | (src_color
& 0x1f);
3218 static void convert_b5g5r5x1_unorm_b5g5r5a1_unorm_color_key(const BYTE
*src
, unsigned int src_pitch
,
3219 BYTE
*dst
, unsigned int dst_pitch
, unsigned int width
, unsigned int height
,
3220 const struct wined3d_color_key
*color_key
)
3222 const WORD
*src_row
;
3226 for (y
= 0; y
< height
; ++y
)
3228 src_row
= (WORD
*)&src
[src_pitch
* y
];
3229 dst_row
= (WORD
*)&dst
[dst_pitch
* y
];
3230 for (x
= 0; x
< width
; ++x
)
3232 WORD src_color
= src_row
[x
];
3233 if (color_in_range(color_key
, src_color
))
3234 dst_row
[x
] = src_color
& ~0x8000;
3236 dst_row
[x
] = src_color
| 0x8000;
3241 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
, UINT height
,
3242 UINT outpitch
, enum wined3d_conversion_type conversion_type
, struct wined3d_surface
*surface
)
3244 struct wined3d_palette
*palette
= NULL
;
3245 struct wined3d_texture
*texture
;
3250 TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
3251 src
, dst
, pitch
, width
, height
, outpitch
, conversion_type
, surface
);
3253 texture
= surface
->container
;
3254 switch (conversion_type
)
3257 if (texture
->swapchain
&& texture
->swapchain
->palette
)
3258 palette
= texture
->swapchain
->palette
;
3259 convert_p8_uint_b8g8r8a8_unorm(src
, pitch
, dst
, outpitch
,
3260 width
, height
, palette
, &texture
->src_blt_color_key
);
3263 case WINED3D_CT_CK_B5G6R5
:
3264 convert_b5g6r5_unorm_b5g5r5a1_unorm_color_key(src
, pitch
, dst
, outpitch
,
3265 width
, height
, &texture
->src_blt_color_key
);
3268 case WINED3D_CT_CK_B5G5R5X1
:
3269 convert_b5g5r5x1_unorm_b5g5r5a1_unorm_color_key(src
, pitch
, dst
, outpitch
,
3270 width
, height
, &texture
->src_blt_color_key
);
3273 case WINED3D_CT_CK_B8G8R8
:
3274 for (y
= 0; y
< height
; ++y
)
3276 source
= src
+ pitch
* y
;
3277 dest
= dst
+ outpitch
* y
;
3278 for (x
= 0; x
< width
; ++x
)
3280 DWORD color
= ((DWORD
)source
[2] << 16) | ((DWORD
)source
[1] << 8) | (DWORD
)source
[0];
3281 if (!color_in_range(&texture
->src_blt_color_key
, color
))
3282 color
|= 0xff000000;
3283 *(DWORD
*)dest
= color
;
3290 case WINED3D_CT_CK_B8G8R8X8
:
3291 for (y
= 0; y
< height
; ++y
)
3293 source
= src
+ pitch
* y
;
3294 dest
= dst
+ outpitch
* y
;
3295 for (x
= 0; x
< width
; ++x
)
3297 DWORD color
= *(const DWORD
*)source
;
3298 if (color_in_range(&texture
->src_blt_color_key
, color
))
3299 *(DWORD
*)dest
= color
& ~0xff000000;
3301 *(DWORD
*)dest
= color
| 0xff000000;
3308 case WINED3D_CT_CK_B8G8R8A8
:
3309 for (y
= 0; y
< height
; ++y
)
3311 source
= src
+ pitch
* y
;
3312 dest
= dst
+ outpitch
* y
;
3313 for (x
= 0; x
< width
; ++x
)
3315 DWORD color
= *(const DWORD
*)source
;
3316 if (color_in_range(&texture
->src_blt_color_key
, color
))
3317 color
&= ~0xff000000;
3318 *(DWORD
*)dest
= color
;
3326 ERR("Unsupported conversion type %#x.\n", conversion_type
);
3331 void flip_surface(struct wined3d_surface
*front
, struct wined3d_surface
*back
)
3333 if (front
->container
->level_count
!= 1 || front
->container
->layer_count
!= 1
3334 || back
->container
->level_count
!= 1 || back
->container
->layer_count
!= 1)
3335 ERR("Flip between surfaces %p and %p not supported.\n", front
, back
);
3337 /* Flip the surface contents */
3342 front
->hDC
= back
->hDC
;
3346 /* Flip the DIBsection */
3348 HBITMAP tmp
= front
->dib
.DIBsection
;
3349 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
3350 back
->dib
.DIBsection
= tmp
;
3353 /* Flip the surface data */
3357 tmp
= front
->dib
.bitmap_data
;
3358 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
3359 back
->dib
.bitmap_data
= tmp
;
3361 tmp
= front
->resource
.heap_memory
;
3362 front
->resource
.heap_memory
= back
->resource
.heap_memory
;
3363 back
->resource
.heap_memory
= tmp
;
3368 GLuint tmp_pbo
= front
->pbo
;
3369 front
->pbo
= back
->pbo
;
3370 back
->pbo
= tmp_pbo
;
3373 /* Flip the opengl texture */
3377 tmp
= back
->container
->texture_rgb
.name
;
3378 back
->container
->texture_rgb
.name
= front
->container
->texture_rgb
.name
;
3379 front
->container
->texture_rgb
.name
= tmp
;
3381 tmp
= back
->container
->texture_srgb
.name
;
3382 back
->container
->texture_srgb
.name
= front
->container
->texture_srgb
.name
;
3383 front
->container
->texture_srgb
.name
= tmp
;
3385 tmp
= back
->rb_multisample
;
3386 back
->rb_multisample
= front
->rb_multisample
;
3387 front
->rb_multisample
= tmp
;
3389 tmp
= back
->rb_resolved
;
3390 back
->rb_resolved
= front
->rb_resolved
;
3391 front
->rb_resolved
= tmp
;
3393 resource_unload(&back
->resource
);
3394 resource_unload(&front
->resource
);
3398 DWORD tmp_flags
= back
->flags
;
3399 back
->flags
= front
->flags
;
3400 front
->flags
= tmp_flags
;
3402 tmp_flags
= back
->locations
;
3403 back
->locations
= front
->locations
;
3404 front
->locations
= tmp_flags
;
3408 /* Does a direct frame buffer -> texture copy. Stretching is done with single
3409 * pixel copy calls. */
3410 static void fb_copy_to_texture_direct(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3411 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3413 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3414 const struct wined3d_gl_info
*gl_info
;
3416 struct wined3d_context
*context
;
3417 BOOL upsidedown
= FALSE
;
3418 RECT dst_rect
= *dst_rect_in
;
3420 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3421 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3423 if(dst_rect
.top
> dst_rect
.bottom
) {
3424 UINT tmp
= dst_rect
.bottom
;
3425 dst_rect
.bottom
= dst_rect
.top
;
3430 context
= context_acquire(device
, src_surface
);
3431 gl_info
= context
->gl_info
;
3432 context_apply_blit_state(context
, device
);
3433 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3435 /* Bind the target texture */
3436 context_bind_texture(context
, dst_surface
->container
->target
, dst_surface
->container
->texture_rgb
.name
);
3437 if (wined3d_resource_is_offscreen(&src_surface
->container
->resource
))
3439 TRACE("Reading from an offscreen target\n");
3440 upsidedown
= !upsidedown
;
3441 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3445 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3447 checkGLcall("glReadBuffer");
3449 xrel
= (float) (src_rect
->right
- src_rect
->left
) / (float) (dst_rect
.right
- dst_rect
.left
);
3450 yrel
= (float) (src_rect
->bottom
- src_rect
->top
) / (float) (dst_rect
.bottom
- dst_rect
.top
);
3452 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3454 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3456 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3457 ERR("Texture filtering not supported in direct blit.\n");
3459 else if ((filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
)
3460 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3462 ERR("Texture filtering not supported in direct blit\n");
3466 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3467 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3469 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
3470 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3471 dst_rect
.left
/*xoffset */, dst_rect
.top
/* y offset */,
3472 src_rect
->left
, src_surface
->resource
.height
- src_rect
->bottom
,
3473 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3478 UINT yoffset
= src_surface
->resource
.height
- src_rect
->top
+ dst_rect
.top
- 1;
3479 /* I have to process this row by row to swap the image,
3480 * otherwise it would be upside down, so stretching in y direction
3481 * doesn't cost extra time
3483 * However, stretching in x direction can be avoided if not necessary
3485 for(row
= dst_rect
.top
; row
< dst_rect
.bottom
; row
++) {
3486 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3488 /* Well, that stuff works, but it's very slow.
3489 * find a better way instead
3493 for (col
= dst_rect
.left
; col
< dst_rect
.right
; ++col
)
3495 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3496 dst_rect
.left
+ col
/* x offset */, row
/* y offset */,
3497 src_rect
->left
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
3502 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(dst_surface
->texture_target
, dst_surface
->texture_level
,
3503 dst_rect
.left
/* x offset */, row
/* y offset */,
3504 src_rect
->left
, yoffset
- (int) (row
* yrel
), dst_rect
.right
- dst_rect
.left
, 1);
3508 checkGLcall("glCopyTexSubImage2D");
3510 context_release(context
);
3512 /* The texture is now most up to date - If the surface is a render target
3513 * and has a drawable, this path is never entered. */
3514 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3515 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3518 /* Uses the hardware to stretch and flip the image */
3519 static void fb_copy_to_texture_hwstretch(struct wined3d_surface
*dst_surface
, struct wined3d_surface
*src_surface
,
3520 const RECT
*src_rect
, const RECT
*dst_rect_in
, enum wined3d_texture_filter_type filter
)
3522 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3523 GLuint src
, backup
= 0;
3524 float left
, right
, top
, bottom
; /* Texture coordinates */
3525 UINT fbwidth
= src_surface
->resource
.width
;
3526 UINT fbheight
= src_surface
->resource
.height
;
3527 const struct wined3d_gl_info
*gl_info
;
3528 struct wined3d_context
*context
;
3529 GLenum drawBuffer
= GL_BACK
;
3530 GLenum texture_target
;
3531 BOOL noBackBufferBackup
;
3533 BOOL upsidedown
= FALSE
;
3534 RECT dst_rect
= *dst_rect_in
;
3536 TRACE("Using hwstretch blit\n");
3537 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3538 context
= context_acquire(device
, src_surface
);
3539 gl_info
= context
->gl_info
;
3540 context_apply_blit_state(context
, device
);
3541 wined3d_texture_load(dst_surface
->container
, context
, FALSE
);
3543 src_offscreen
= wined3d_resource_is_offscreen(&src_surface
->container
->resource
);
3544 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
3545 if (!noBackBufferBackup
&& !src_surface
->container
->texture_rgb
.name
)
3547 /* Get it a description */
3548 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3551 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3552 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3554 if (context
->aux_buffers
>= 2)
3556 /* Got more than one aux buffer? Use the 2nd aux buffer */
3557 drawBuffer
= GL_AUX1
;
3559 else if ((!src_offscreen
|| device
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
3561 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3562 drawBuffer
= GL_AUX0
;
3565 if (noBackBufferBackup
)
3567 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &backup
);
3568 checkGLcall("glGenTextures");
3569 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3570 texture_target
= GL_TEXTURE_2D
;
3574 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3575 * we are reading from the back buffer, the backup can be used as source texture
3577 texture_target
= src_surface
->texture_target
;
3578 context_bind_texture(context
, texture_target
, src_surface
->container
->texture_rgb
.name
);
3579 gl_info
->gl_ops
.gl
.p_glEnable(texture_target
);
3580 checkGLcall("glEnable(texture_target)");
3582 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3583 src_surface
->locations
&= ~WINED3D_LOCATION_TEXTURE_RGB
;
3586 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3587 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3589 if(dst_rect
.top
> dst_rect
.bottom
) {
3590 UINT tmp
= dst_rect
.bottom
;
3591 dst_rect
.bottom
= dst_rect
.top
;
3598 TRACE("Reading from an offscreen target\n");
3599 upsidedown
= !upsidedown
;
3600 gl_info
->gl_ops
.gl
.p_glReadBuffer(device
->offscreenBuffer
);
3604 gl_info
->gl_ops
.gl
.p_glReadBuffer(surface_get_gl_buffer(src_surface
));
3607 /* TODO: Only back up the part that will be overwritten */
3608 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3610 checkGLcall("glCopyTexSubImage2D");
3612 /* No issue with overriding these - the sampler is dirty due to blit usage */
3613 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
3614 wined3d_gl_mag_filter(magLookup
, filter
));
3615 checkGLcall("glTexParameteri");
3616 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
3617 wined3d_gl_min_mip_filter(minMipLookup
, filter
, WINED3D_TEXF_NONE
));
3618 checkGLcall("glTexParameteri");
3620 if (!src_surface
->container
->swapchain
3621 || src_surface
->container
== src_surface
->container
->swapchain
->back_buffers
[0])
3623 src
= backup
? backup
: src_surface
->container
->texture_rgb
.name
;
3627 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_FRONT
);
3628 checkGLcall("glReadBuffer(GL_FRONT)");
3630 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &src
);
3631 checkGLcall("glGenTextures(1, &src)");
3632 context_bind_texture(context
, GL_TEXTURE_2D
, src
);
3634 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3635 * out for power of 2 sizes
3637 gl_info
->gl_ops
.gl
.p_glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, src_surface
->pow2Width
,
3638 src_surface
->pow2Height
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
3639 checkGLcall("glTexImage2D");
3640 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, 0, 0, fbwidth
, fbheight
);
3642 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3643 checkGLcall("glTexParameteri");
3644 gl_info
->gl_ops
.gl
.p_glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3645 checkGLcall("glTexParameteri");
3647 gl_info
->gl_ops
.gl
.p_glReadBuffer(GL_BACK
);
3648 checkGLcall("glReadBuffer(GL_BACK)");
3650 if (texture_target
!= GL_TEXTURE_2D
)
3652 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3653 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3654 texture_target
= GL_TEXTURE_2D
;
3657 checkGLcall("glEnd and previous");
3659 left
= src_rect
->left
;
3660 right
= src_rect
->right
;
3664 top
= src_surface
->resource
.height
- src_rect
->top
;
3665 bottom
= src_surface
->resource
.height
- src_rect
->bottom
;
3669 top
= src_surface
->resource
.height
- src_rect
->bottom
;
3670 bottom
= src_surface
->resource
.height
- src_rect
->top
;
3673 if (src_surface
->flags
& SFLAG_NORMCOORD
)
3675 left
/= src_surface
->pow2Width
;
3676 right
/= src_surface
->pow2Width
;
3677 top
/= src_surface
->pow2Height
;
3678 bottom
/= src_surface
->pow2Height
;
3681 /* draw the source texture stretched and upside down. The correct surface is bound already */
3682 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
3683 gl_info
->gl_ops
.gl
.p_glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
3685 context_set_draw_buffer(context
, drawBuffer
);
3686 gl_info
->gl_ops
.gl
.p_glReadBuffer(drawBuffer
);
3688 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3690 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, bottom
);
3691 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3694 gl_info
->gl_ops
.gl
.p_glTexCoord2f(left
, top
);
3695 gl_info
->gl_ops
.gl
.p_glVertex2i(0, dst_rect
.bottom
- dst_rect
.top
);
3698 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, top
);
3699 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3702 gl_info
->gl_ops
.gl
.p_glTexCoord2f(right
, bottom
);
3703 gl_info
->gl_ops
.gl
.p_glVertex2i(dst_rect
.right
- dst_rect
.left
, 0);
3704 gl_info
->gl_ops
.gl
.p_glEnd();
3705 checkGLcall("glEnd and previous");
3707 if (texture_target
!= dst_surface
->texture_target
)
3709 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3710 gl_info
->gl_ops
.gl
.p_glEnable(dst_surface
->texture_target
);
3711 texture_target
= dst_surface
->texture_target
;
3714 /* Now read the stretched and upside down image into the destination texture */
3715 context_bind_texture(context
, texture_target
, dst_surface
->container
->texture_rgb
.name
);
3716 gl_info
->gl_ops
.gl
.p_glCopyTexSubImage2D(texture_target
,
3718 dst_rect
.left
, dst_rect
.top
, /* xoffset, yoffset */
3719 0, 0, /* We blitted the image to the origin */
3720 dst_rect
.right
- dst_rect
.left
, dst_rect
.bottom
- dst_rect
.top
);
3721 checkGLcall("glCopyTexSubImage2D");
3723 if (drawBuffer
== GL_BACK
)
3725 /* Write the back buffer backup back. */
3728 if (texture_target
!= GL_TEXTURE_2D
)
3730 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3731 gl_info
->gl_ops
.gl
.p_glEnable(GL_TEXTURE_2D
);
3732 texture_target
= GL_TEXTURE_2D
;
3734 context_bind_texture(context
, GL_TEXTURE_2D
, backup
);
3738 if (texture_target
!= src_surface
->texture_target
)
3740 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3741 gl_info
->gl_ops
.gl
.p_glEnable(src_surface
->texture_target
);
3742 texture_target
= src_surface
->texture_target
;
3744 context_bind_texture(context
, src_surface
->texture_target
, src_surface
->container
->texture_rgb
.name
);
3747 gl_info
->gl_ops
.gl
.p_glBegin(GL_QUADS
);
3749 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, 0.0f
);
3750 gl_info
->gl_ops
.gl
.p_glVertex2i(0, fbheight
);
3753 gl_info
->gl_ops
.gl
.p_glTexCoord2f(0.0f
, (float)fbheight
/ (float)src_surface
->pow2Height
);
3754 gl_info
->gl_ops
.gl
.p_glVertex2i(0, 0);
3757 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
,
3758 (float)fbheight
/ (float)src_surface
->pow2Height
);
3759 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, 0);
3762 gl_info
->gl_ops
.gl
.p_glTexCoord2f((float)fbwidth
/ (float)src_surface
->pow2Width
, 0.0f
);
3763 gl_info
->gl_ops
.gl
.p_glVertex2i(fbwidth
, fbheight
);
3764 gl_info
->gl_ops
.gl
.p_glEnd();
3766 gl_info
->gl_ops
.gl
.p_glDisable(texture_target
);
3767 checkGLcall("glDisable(texture_target)");
3770 if (src
!= src_surface
->container
->texture_rgb
.name
&& src
!= backup
)
3772 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &src
);
3773 checkGLcall("glDeleteTextures(1, &src)");
3777 gl_info
->gl_ops
.gl
.p_glDeleteTextures(1, &backup
);
3778 checkGLcall("glDeleteTextures(1, &backup)");
3781 if (wined3d_settings
.strict_draw_ordering
)
3782 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3784 context_release(context
);
3786 /* The texture is now most up to date - If the surface is a render target
3787 * and has a drawable, this path is never entered. */
3788 surface_validate_location(dst_surface
, WINED3D_LOCATION_TEXTURE_RGB
);
3789 surface_invalidate_location(dst_surface
, ~WINED3D_LOCATION_TEXTURE_RGB
);
3792 /* Front buffer coordinates are always full screen coordinates, but our GL
3793 * drawable is limited to the window's client area. The sysmem and texture
3794 * copies do have the full screen size. Note that GL has a bottom-left
3795 * origin, while D3D has a top-left origin. */
3796 void surface_translate_drawable_coords(const struct wined3d_surface
*surface
, HWND window
, RECT
*rect
)
3798 UINT drawable_height
;
3800 if (surface
->container
->swapchain
&& surface
->container
== surface
->container
->swapchain
->front_buffer
)
3802 POINT offset
= {0, 0};
3805 ScreenToClient(window
, &offset
);
3806 OffsetRect(rect
, offset
.x
, offset
.y
);
3808 GetClientRect(window
, &windowsize
);
3809 drawable_height
= windowsize
.bottom
- windowsize
.top
;
3813 drawable_height
= surface
->resource
.height
;
3816 rect
->top
= drawable_height
- rect
->top
;
3817 rect
->bottom
= drawable_height
- rect
->bottom
;
3820 static void surface_blt_to_drawable(const struct wined3d_device
*device
,
3821 enum wined3d_texture_filter_type filter
, BOOL alpha_test
,
3822 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
,
3823 struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
)
3825 const struct wined3d_gl_info
*gl_info
;
3826 struct wined3d_context
*context
;
3827 RECT src_rect
, dst_rect
;
3829 src_rect
= *src_rect_in
;
3830 dst_rect
= *dst_rect_in
;
3832 context
= context_acquire(device
, dst_surface
);
3833 gl_info
= context
->gl_info
;
3835 /* Make sure the surface is up-to-date. This should probably use
3836 * surface_load_location() and worry about the destination surface too,
3837 * unless we're overwriting it completely. */
3838 wined3d_texture_load(src_surface
->container
, context
, FALSE
);
3840 /* Activate the destination context, set it up for blitting */
3841 context_apply_blit_state(context
, device
);
3843 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
3844 surface_translate_drawable_coords(dst_surface
, context
->win_handle
, &dst_rect
);
3846 device
->blitter
->set_shader(device
->blit_priv
, context
, src_surface
);
3850 gl_info
->gl_ops
.gl
.p_glEnable(GL_ALPHA_TEST
);
3851 checkGLcall("glEnable(GL_ALPHA_TEST)");
3853 /* For P8 surfaces, the alpha component contains the palette index.
3854 * Which means that the colorkey is one of the palette entries. In
3855 * other cases pixels that should be masked away have alpha set to 0. */
3856 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3857 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
,
3858 (float)src_surface
->container
->src_blt_color_key
.color_space_low_value
/ 256.0f
);
3860 gl_info
->gl_ops
.gl
.p_glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
3861 checkGLcall("glAlphaFunc");
3865 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3866 checkGLcall("glDisable(GL_ALPHA_TEST)");
3869 draw_textured_quad(src_surface
, context
, &src_rect
, &dst_rect
, filter
);
3873 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
3874 checkGLcall("glDisable(GL_ALPHA_TEST)");
3877 /* Leave the opengl state valid for blitting */
3878 device
->blitter
->unset_shader(context
->gl_info
);
3880 if (wined3d_settings
.strict_draw_ordering
3881 || (dst_surface
->container
->swapchain
3882 && dst_surface
->container
->swapchain
->front_buffer
== dst_surface
->container
))
3883 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
3885 context_release(context
);
3888 HRESULT
surface_color_fill(struct wined3d_surface
*s
, const RECT
*rect
, const struct wined3d_color
*color
)
3890 struct wined3d_device
*device
= s
->resource
.device
;
3891 const struct blit_shader
*blitter
;
3893 blitter
= wined3d_select_blitter(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_FILL
,
3894 NULL
, 0, 0, NULL
, rect
, s
->resource
.usage
, s
->resource
.pool
, s
->resource
.format
);
3897 FIXME("No blitter is capable of performing the requested color fill operation.\n");
3898 return WINED3DERR_INVALIDCALL
;
3901 return blitter
->color_fill(device
, s
, rect
, color
);
3904 static HRESULT
surface_blt_special(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
3905 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
, const WINEDDBLTFX
*DDBltFx
,
3906 enum wined3d_texture_filter_type filter
)
3908 struct wined3d_device
*device
= dst_surface
->resource
.device
;
3909 const struct wined3d_surface
*rt
= wined3d_rendertarget_view_get_surface(device
->fb
.render_targets
[0]);
3910 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
3911 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
3913 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
3914 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
3915 flags
, DDBltFx
, debug_d3dtexturefiltertype(filter
));
3917 /* Get the swapchain. One of the surfaces has to be a primary surface */
3918 if (dst_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3920 WARN("Destination is in sysmem, rejecting gl blt\n");
3921 return WINED3DERR_INVALIDCALL
;
3924 dst_swapchain
= dst_surface
->container
->swapchain
;
3928 if (src_surface
->resource
.pool
== WINED3D_POOL_SYSTEM_MEM
)
3930 WARN("Src is in sysmem, rejecting gl blt\n");
3931 return WINED3DERR_INVALIDCALL
;
3934 src_swapchain
= src_surface
->container
->swapchain
;
3938 src_swapchain
= NULL
;
3941 /* Early sort out of cases where no render target is used */
3942 if (!dst_swapchain
&& !src_swapchain
&& src_surface
!= rt
&& dst_surface
!= rt
)
3944 TRACE("No surface is render target, not using hardware blit.\n");
3945 return WINED3DERR_INVALIDCALL
;
3948 /* No destination color keying supported */
3949 if (flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
))
3951 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3952 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3953 return WINED3DERR_INVALIDCALL
;
3956 if (dst_swapchain
&& dst_swapchain
== src_swapchain
)
3958 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3959 return WINED3DERR_INVALIDCALL
;
3962 if (dst_swapchain
&& src_swapchain
)
3964 FIXME("Implement hardware blit between two different swapchains\n");
3965 return WINED3DERR_INVALIDCALL
;
3970 /* Handled with regular texture -> swapchain blit */
3971 if (src_surface
== rt
)
3972 TRACE("Blit from active render target to a swapchain\n");
3974 else if (src_swapchain
&& dst_surface
== rt
)
3976 FIXME("Implement blit from a swapchain to the active render target\n");
3977 return WINED3DERR_INVALIDCALL
;
3980 if ((src_swapchain
|| src_surface
== rt
) && !dst_swapchain
)
3982 /* Blit from render target to texture */
3985 /* P8 read back is not implemented */
3986 if (src_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
3987 || dst_surface
->resource
.format
->id
== WINED3DFMT_P8_UINT
)
3989 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3990 return WINED3DERR_INVALIDCALL
;
3993 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
3995 TRACE("Color keying not supported by frame buffer to texture blit\n");
3996 return WINED3DERR_INVALIDCALL
;
3997 /* Destination color key is checked above */
4000 if (dst_rect
->right
- dst_rect
->left
!= src_rect
->right
- src_rect
->left
)
4005 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
4006 * flip the image nor scale it.
4008 * -> If the app asks for an unscaled, upside down copy, just perform one glCopyTexSubImage2D call
4009 * -> If the app wants an image width an unscaled width, copy it line per line
4010 * -> If the app wants an image that is scaled on the x axis, and the destination rectangle is smaller
4011 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
4012 * back buffer. This is slower than reading line per line, thus not used for flipping
4013 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
4014 * pixel by pixel. */
4015 if (!stretchx
|| dst_rect
->right
- dst_rect
->left
> src_surface
->resource
.width
4016 || dst_rect
->bottom
- dst_rect
->top
> src_surface
->resource
.height
)
4018 TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
4019 fb_copy_to_texture_direct(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4023 TRACE("Using hardware stretching to flip / stretch the texture.\n");
4024 fb_copy_to_texture_hwstretch(dst_surface
, src_surface
, src_rect
, dst_rect
, filter
);
4027 surface_evict_sysmem(dst_surface
);
4031 else if (src_surface
)
4033 /* Blit from offscreen surface to render target */
4034 struct wined3d_color_key old_blt_key
= src_surface
->container
->src_blt_color_key
;
4035 DWORD old_color_key_flags
= src_surface
->container
->color_key_flags
;
4037 TRACE("Blt from surface %p to rendertarget %p\n", src_surface
, dst_surface
);
4039 if (!device
->blitter
->blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4040 src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
4041 dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
4043 FIXME("Unsupported blit operation falling back to software\n");
4044 return WINED3DERR_INVALIDCALL
;
4047 /* Color keying: Check if we have to do a color keyed blt,
4048 * and if not check if a color key is activated.
4050 * Just modify the color keying parameters in the surface and restore them afterwards
4051 * The surface keeps track of the color key last used to load the opengl surface.
4052 * PreLoad will catch the change to the flags and color key and reload if necessary.
4054 if (flags
& WINEDDBLT_KEYSRC
)
4056 /* Use color key from surface */
4058 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
4060 /* Use color key from DDBltFx */
4061 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
, &DDBltFx
->ddckSrcColorkey
);
4065 /* Do not use color key */
4066 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
, NULL
);
4069 surface_blt_to_drawable(device
, filter
,
4070 flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_ALPHATEST
),
4071 src_surface
, src_rect
, dst_surface
, dst_rect
);
4073 /* Restore the color key parameters */
4074 wined3d_texture_set_color_key(src_surface
->container
, WINEDDSD_CKSRCBLT
,
4075 (old_color_key_flags
& WINEDDSD_CKSRCBLT
) ? &old_blt_key
: NULL
);
4077 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
4078 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
4083 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
4084 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
4085 return WINED3DERR_INVALIDCALL
;
4088 /* Context activation is done by the caller. */
4089 static void surface_depth_blt(const struct wined3d_surface
*surface
, struct wined3d_context
*context
,
4090 GLuint texture
, GLint x
, GLint y
, GLsizei w
, GLsizei h
, GLenum target
)
4092 struct wined3d_device
*device
= surface
->resource
.device
;
4093 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4094 GLint compare_mode
= GL_NONE
;
4095 struct blt_info info
;
4096 GLint old_binding
= 0;
4099 gl_info
->gl_ops
.gl
.p_glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
4101 gl_info
->gl_ops
.gl
.p_glDisable(GL_CULL_FACE
);
4102 gl_info
->gl_ops
.gl
.p_glDisable(GL_BLEND
);
4103 gl_info
->gl_ops
.gl
.p_glDisable(GL_ALPHA_TEST
);
4104 gl_info
->gl_ops
.gl
.p_glDisable(GL_SCISSOR_TEST
);
4105 gl_info
->gl_ops
.gl
.p_glDisable(GL_STENCIL_TEST
);
4106 gl_info
->gl_ops
.gl
.p_glEnable(GL_DEPTH_TEST
);
4107 gl_info
->gl_ops
.gl
.p_glDepthFunc(GL_ALWAYS
);
4108 gl_info
->gl_ops
.gl
.p_glDepthMask(GL_TRUE
);
4109 gl_info
->gl_ops
.gl
.p_glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
4110 gl_info
->gl_ops
.gl
.p_glViewport(x
, y
, w
, h
);
4111 gl_info
->gl_ops
.gl
.p_glDepthRange(0.0, 1.0);
4113 SetRect(&rect
, 0, h
, w
, 0);
4114 surface_get_blt_info(target
, &rect
, surface
->pow2Width
, surface
->pow2Height
, &info
);
4115 context_active_texture(context
, context
->gl_info
, 0);
4116 gl_info
->gl_ops
.gl
.p_glGetIntegerv(info
.binding
, &old_binding
);
4117 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, texture
);
4118 if (gl_info
->supported
[ARB_SHADOW
])
4120 gl_info
->gl_ops
.gl
.p_glGetTexParameteriv(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, &compare_mode
);
4121 if (compare_mode
!= GL_NONE
)
4122 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
4125 device
->shader_backend
->shader_select_depth_blt(device
->shader_priv
,
4126 gl_info
, info
.tex_type
, &surface
->ds_current_size
);
4128 gl_info
->gl_ops
.gl
.p_glBegin(GL_TRIANGLE_STRIP
);
4129 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[0]);
4130 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, -1.0f
);
4131 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[1]);
4132 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, -1.0f
);
4133 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[2]);
4134 gl_info
->gl_ops
.gl
.p_glVertex2f(-1.0f
, 1.0f
);
4135 gl_info
->gl_ops
.gl
.p_glTexCoord3fv(info
.coords
[3]);
4136 gl_info
->gl_ops
.gl
.p_glVertex2f(1.0f
, 1.0f
);
4137 gl_info
->gl_ops
.gl
.p_glEnd();
4139 if (compare_mode
!= GL_NONE
)
4140 gl_info
->gl_ops
.gl
.p_glTexParameteri(info
.bind_target
, GL_TEXTURE_COMPARE_MODE_ARB
, compare_mode
);
4141 gl_info
->gl_ops
.gl
.p_glBindTexture(info
.bind_target
, old_binding
);
4143 gl_info
->gl_ops
.gl
.p_glPopAttrib();
4145 device
->shader_backend
->shader_deselect_depth_blt(device
->shader_priv
, gl_info
);
4148 void surface_modify_ds_location(struct wined3d_surface
*surface
,
4149 DWORD location
, UINT w
, UINT h
)
4151 TRACE("surface %p, new location %#x, w %u, h %u.\n", surface
, location
, w
, h
);
4153 if (((surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && !(location
& WINED3D_LOCATION_TEXTURE_RGB
))
4154 || (!(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
) && (location
& WINED3D_LOCATION_TEXTURE_RGB
)))
4155 wined3d_texture_set_dirty(surface
->container
);
4157 surface
->ds_current_size
.cx
= w
;
4158 surface
->ds_current_size
.cy
= h
;
4159 surface
->locations
= location
;
4162 /* Context activation is done by the caller. */
4163 void surface_load_ds_location(struct wined3d_surface
*surface
, struct wined3d_context
*context
, DWORD location
)
4165 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4166 struct wined3d_device
*device
= surface
->resource
.device
;
4169 TRACE("surface %p, new location %#x.\n", surface
, location
);
4171 /* TODO: Make this work for modes other than FBO */
4172 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
4174 if (!(surface
->locations
& location
))
4176 w
= surface
->ds_current_size
.cx
;
4177 h
= surface
->ds_current_size
.cy
;
4178 surface
->ds_current_size
.cx
= 0;
4179 surface
->ds_current_size
.cy
= 0;
4183 w
= surface
->resource
.width
;
4184 h
= surface
->resource
.height
;
4187 if (surface
->ds_current_size
.cx
== surface
->resource
.width
4188 && surface
->ds_current_size
.cy
== surface
->resource
.height
)
4190 TRACE("Location (%#x) is already up to date.\n", location
);
4194 if (surface
->current_renderbuffer
)
4196 FIXME("Not supported with fixed up depth stencil.\n");
4200 if (surface
->locations
& WINED3D_LOCATION_DISCARDED
)
4202 TRACE("Surface was discarded, no need copy data.\n");
4205 case WINED3D_LOCATION_TEXTURE_RGB
:
4206 surface_prepare_texture(surface
, context
, FALSE
);
4208 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4209 surface_prepare_rb(surface
, gl_info
, TRUE
);
4211 case WINED3D_LOCATION_DRAWABLE
:
4215 FIXME("Unhandled location %#x\n", location
);
4217 surface
->locations
&= ~WINED3D_LOCATION_DISCARDED
;
4218 surface
->locations
|= location
;
4219 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4220 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4224 if (!surface
->locations
)
4226 FIXME("No up to date depth stencil location.\n");
4227 surface
->locations
|= location
;
4228 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4229 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4233 if (location
== WINED3D_LOCATION_TEXTURE_RGB
)
4235 GLint old_binding
= 0;
4238 /* The render target is allowed to be smaller than the depth/stencil
4239 * buffer, so the onscreen depth/stencil buffer is potentially smaller
4240 * than the offscreen surface. Don't overwrite the offscreen surface
4241 * with undefined data. */
4242 w
= min(w
, context
->swapchain
->desc
.backbuffer_width
);
4243 h
= min(h
, context
->swapchain
->desc
.backbuffer_height
);
4245 TRACE("Copying onscreen depth buffer to depth texture.\n");
4247 if (!device
->depth_blt_texture
)
4248 gl_info
->gl_ops
.gl
.p_glGenTextures(1, &device
->depth_blt_texture
);
4250 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4251 * directly on the FBO texture. That's because we need to flip. */
4252 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4253 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
4254 NULL
, WINED3D_LOCATION_DRAWABLE
);
4255 if (surface
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
4257 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
4258 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
4262 gl_info
->gl_ops
.gl
.p_glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
4263 bind_target
= GL_TEXTURE_2D
;
4265 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, device
->depth_blt_texture
);
4266 /* We use GL_DEPTH_COMPONENT instead of the surface's specific
4267 * internal format, because the internal format might include stencil
4268 * data. In principle we should copy stencil data as well, but unless
4269 * the driver supports stencil export it's hard to do, and doesn't
4270 * seem to be needed in practice. If the hardware doesn't support
4271 * writing stencil data, the glCopyTexImage2D() call might trigger
4272 * software fallbacks. */
4273 gl_info
->gl_ops
.gl
.p_glCopyTexImage2D(bind_target
, 0, GL_DEPTH_COMPONENT
, 0, 0, w
, h
, 0);
4274 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
4275 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
4276 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
4277 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
4278 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
4279 gl_info
->gl_ops
.gl
.p_glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
4280 gl_info
->gl_ops
.gl
.p_glBindTexture(bind_target
, old_binding
);
4282 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4283 NULL
, surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4284 context_set_draw_buffer(context
, GL_NONE
);
4286 /* Do the actual blit */
4287 surface_depth_blt(surface
, context
, device
->depth_blt_texture
, 0, 0, w
, h
, bind_target
);
4288 checkGLcall("depth_blt");
4290 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4292 if (wined3d_settings
.strict_draw_ordering
)
4293 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4295 else if (location
== WINED3D_LOCATION_DRAWABLE
)
4297 TRACE("Copying depth texture to onscreen depth buffer.\n");
4299 context_apply_fbo_state_blit(context
, GL_FRAMEBUFFER
,
4300 surface_from_resource(wined3d_texture_get_sub_resource(context
->swapchain
->front_buffer
, 0)),
4301 NULL
, WINED3D_LOCATION_DRAWABLE
);
4302 surface_depth_blt(surface
, context
, surface
->container
->texture_rgb
.name
,
4303 0, surface
->pow2Height
- h
, w
, h
, surface
->texture_target
);
4304 checkGLcall("depth_blt");
4306 context_invalidate_state(context
, STATE_FRAMEBUFFER
);
4308 if (wined3d_settings
.strict_draw_ordering
)
4309 gl_info
->gl_ops
.gl
.p_glFlush(); /* Flush to ensure ordering across contexts. */
4313 ERR("Invalid location (%#x) specified.\n", location
);
4316 surface
->locations
|= location
;
4317 surface
->ds_current_size
.cx
= surface
->resource
.width
;
4318 surface
->ds_current_size
.cy
= surface
->resource
.height
;
4321 void surface_validate_location(struct wined3d_surface
*surface
, DWORD location
)
4323 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4325 surface
->locations
|= location
;
4328 void surface_invalidate_location(struct wined3d_surface
*surface
, DWORD location
)
4330 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4332 if (location
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4333 wined3d_texture_set_dirty(surface
->container
);
4334 surface
->locations
&= ~location
;
4336 if (!surface
->locations
)
4337 ERR("Surface %p does not have any up to date location.\n", surface
);
4340 static DWORD
resource_access_from_location(DWORD location
)
4344 case WINED3D_LOCATION_SYSMEM
:
4345 case WINED3D_LOCATION_USER_MEMORY
:
4346 case WINED3D_LOCATION_DIB
:
4347 case WINED3D_LOCATION_BUFFER
:
4348 return WINED3D_RESOURCE_ACCESS_CPU
;
4350 case WINED3D_LOCATION_DRAWABLE
:
4351 case WINED3D_LOCATION_TEXTURE_SRGB
:
4352 case WINED3D_LOCATION_TEXTURE_RGB
:
4353 case WINED3D_LOCATION_RB_MULTISAMPLE
:
4354 case WINED3D_LOCATION_RB_RESOLVED
:
4355 return WINED3D_RESOURCE_ACCESS_GPU
;
4358 FIXME("Unhandled location %#x.\n", location
);
4363 static void surface_copy_simple_location(struct wined3d_surface
*surface
, DWORD location
)
4365 struct wined3d_device
*device
= surface
->resource
.device
;
4366 struct wined3d_context
*context
;
4367 const struct wined3d_gl_info
*gl_info
;
4368 struct wined3d_bo_address dst
, src
;
4369 UINT size
= surface
->resource
.size
;
4371 surface_get_memory(surface
, &dst
, location
);
4372 surface_get_memory(surface
, &src
, surface
->locations
);
4374 if (dst
.buffer_object
)
4376 context
= context_acquire(device
, NULL
);
4377 gl_info
= context
->gl_info
;
4378 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, dst
.buffer_object
));
4379 GL_EXTCALL(glBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0, size
, src
.addr
));
4380 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
4381 checkGLcall("Upload PBO");
4382 context_release(context
);
4385 if (src
.buffer_object
)
4387 context
= context_acquire(device
, NULL
);
4388 gl_info
= context
->gl_info
;
4389 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, src
.buffer_object
));
4390 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_PACK_BUFFER_ARB
, 0, size
, dst
.addr
));
4391 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
4392 checkGLcall("Download PBO");
4393 context_release(context
);
4396 memcpy(dst
.addr
, src
.addr
, size
);
4399 static void surface_load_sysmem(struct wined3d_surface
*surface
,
4400 const struct wined3d_gl_info
*gl_info
, DWORD dst_location
)
4402 if (surface
->locations
& surface_simple_locations
)
4404 surface_copy_simple_location(surface
, dst_location
);
4408 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
))
4409 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4411 /* Download the surface to system memory. */
4412 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| WINED3D_LOCATION_TEXTURE_SRGB
))
4414 struct wined3d_device
*device
= surface
->resource
.device
;
4415 struct wined3d_context
*context
;
4417 /* TODO: Use already acquired context when possible. */
4418 context
= context_acquire(device
, NULL
);
4420 wined3d_texture_bind_and_dirtify(surface
->container
, context
,
4421 !(surface
->locations
& WINED3D_LOCATION_TEXTURE_RGB
));
4422 surface_download_data(surface
, gl_info
, dst_location
);
4424 context_release(context
);
4429 if (surface
->locations
& WINED3D_LOCATION_DRAWABLE
)
4431 read_from_framebuffer(surface
, dst_location
);
4435 FIXME("Can't load surface %p with location flags %s into sysmem.\n",
4436 surface
, wined3d_debug_location(surface
->locations
));
4439 static HRESULT
surface_load_drawable(struct wined3d_surface
*surface
,
4440 const struct wined3d_gl_info
*gl_info
)
4444 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
4445 && wined3d_resource_is_offscreen(&surface
->container
->resource
))
4447 ERR("Trying to load offscreen surface into WINED3D_LOCATION_DRAWABLE.\n");
4448 return WINED3DERR_INVALIDCALL
;
4451 surface_get_rect(surface
, NULL
, &r
);
4452 surface_load_location(surface
, WINED3D_LOCATION_TEXTURE_RGB
);
4453 surface_blt_to_drawable(surface
->resource
.device
,
4454 WINED3D_TEXF_POINT
, FALSE
, surface
, &r
, surface
, &r
);
4459 static HRESULT
surface_load_texture(struct wined3d_surface
*surface
,
4460 const struct wined3d_gl_info
*gl_info
, BOOL srgb
)
4462 RECT src_rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4463 struct wined3d_device
*device
= surface
->resource
.device
;
4464 enum wined3d_conversion_type convert
;
4465 struct wined3d_context
*context
;
4466 UINT width
, src_pitch
, dst_pitch
;
4467 struct wined3d_bo_address data
;
4468 struct wined3d_format format
;
4469 POINT dst_point
= {0, 0};
4472 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
4473 && wined3d_resource_is_offscreen(&surface
->container
->resource
)
4474 && (surface
->locations
& WINED3D_LOCATION_DRAWABLE
))
4476 surface_load_fb_texture(surface
, srgb
);
4481 if (surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| WINED3D_LOCATION_TEXTURE_RGB
)
4482 && (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
)
4483 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4484 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4485 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4488 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_RGB
,
4489 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
, &src_rect
);
4491 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, WINED3D_LOCATION_TEXTURE_SRGB
,
4492 &src_rect
, surface
, WINED3D_LOCATION_TEXTURE_RGB
, &src_rect
);
4497 if (surface
->locations
& (WINED3D_LOCATION_RB_MULTISAMPLE
| WINED3D_LOCATION_RB_RESOLVED
)
4498 && (!srgb
|| (surface
->resource
.format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB
))
4499 && fbo_blit_supported(gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
4500 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
,
4501 NULL
, surface
->resource
.usage
, surface
->resource
.pool
, surface
->resource
.format
))
4503 DWORD src_location
= surface
->locations
& WINED3D_LOCATION_RB_RESOLVED
?
4504 WINED3D_LOCATION_RB_RESOLVED
: WINED3D_LOCATION_RB_MULTISAMPLE
;
4505 DWORD dst_location
= srgb
? WINED3D_LOCATION_TEXTURE_SRGB
: WINED3D_LOCATION_TEXTURE_RGB
;
4506 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4508 surface_blt_fbo(device
, WINED3D_TEXF_POINT
, surface
, src_location
,
4509 &rect
, surface
, dst_location
, &rect
);
4514 /* Upload from system memory */
4516 d3dfmt_get_conv(surface
->container
, TRUE
/* We need color keying */, &format
, &convert
);
4520 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_RGB
| surface
->resource
.map_binding
))
4521 == WINED3D_LOCATION_TEXTURE_RGB
)
4523 /* Performance warning... */
4524 FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface
);
4525 surface_prepare_map_memory(surface
);
4526 surface_load_location(surface
, surface
->resource
.map_binding
);
4531 if ((surface
->locations
& (WINED3D_LOCATION_TEXTURE_SRGB
| surface
->resource
.map_binding
))
4532 == WINED3D_LOCATION_TEXTURE_SRGB
)
4534 /* Performance warning... */
4535 FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface
);
4536 surface_prepare_map_memory(surface
);
4537 surface_load_location(surface
, surface
->resource
.map_binding
);
4541 if (!(surface
->locations
& surface_simple_locations
))
4543 WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
4544 /* Lets hope we get it from somewhere... */
4545 surface_prepare_system_memory(surface
);
4546 surface_load_location(surface
, WINED3D_LOCATION_SYSMEM
);
4549 /* TODO: Use already acquired context when possible. */
4550 context
= context_acquire(device
, NULL
);
4552 surface_prepare_texture(surface
, context
, srgb
);
4553 wined3d_texture_bind_and_dirtify(surface
->container
, context
, srgb
);
4555 if (surface
->container
->color_key_flags
& WINEDDSD_CKSRCBLT
)
4557 surface
->flags
|= SFLAG_GLCKEY
;
4558 surface
->gl_color_key
= surface
->container
->src_blt_color_key
;
4560 else surface
->flags
&= ~SFLAG_GLCKEY
;
4562 width
= surface
->resource
.width
;
4563 src_pitch
= wined3d_surface_get_pitch(surface
);
4565 /* Don't use PBOs for converted surfaces. During PBO conversion we look at
4566 * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
4568 if ((convert
!= WINED3D_CT_NONE
|| format
.convert
) && surface
->pbo
)
4570 TRACE("Removing the pbo attached to surface %p.\n", surface
);
4572 if (surface
->flags
& SFLAG_DIBSECTION
)
4573 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
4575 surface
->resource
.map_binding
= WINED3D_LOCATION_SYSMEM
;
4577 surface_prepare_map_memory(surface
);
4578 surface_load_location(surface
, surface
->resource
.map_binding
);
4579 surface_remove_pbo(surface
, gl_info
);
4582 surface_get_memory(surface
, &data
, surface
->locations
);
4585 /* This code is entered for texture formats which need a fixup. */
4586 UINT height
= surface
->resource
.height
;
4588 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4589 dst_pitch
= width
* format
.conv_byte_count
;
4590 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4592 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4594 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4595 context_release(context
);
4596 return E_OUTOFMEMORY
;
4598 format
.convert(data
.addr
, mem
, src_pitch
, src_pitch
* height
,
4599 dst_pitch
, dst_pitch
* height
, width
, height
, 1);
4600 format
.byte_count
= format
.conv_byte_count
;
4601 src_pitch
= dst_pitch
;
4604 else if (convert
!= WINED3D_CT_NONE
)
4606 /* This code is only entered for color keying fixups */
4607 UINT height
= surface
->resource
.height
;
4609 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4610 dst_pitch
= width
* format
.conv_byte_count
;
4611 dst_pitch
= (dst_pitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4613 if (!(mem
= HeapAlloc(GetProcessHeap(), 0, dst_pitch
* height
)))
4615 ERR("Out of memory (%u).\n", dst_pitch
* height
);
4616 context_release(context
);
4617 return E_OUTOFMEMORY
;
4619 d3dfmt_convert_surface(data
.addr
, mem
, src_pitch
,
4620 width
, height
, dst_pitch
, convert
, surface
);
4621 format
.byte_count
= format
.conv_byte_count
;
4622 src_pitch
= dst_pitch
;
4626 surface_upload_data(surface
, gl_info
, &format
, &src_rect
, src_pitch
, &dst_point
, srgb
, &data
);
4628 context_release(context
);
4630 HeapFree(GetProcessHeap(), 0, mem
);
4635 static void surface_multisample_resolve(struct wined3d_surface
*surface
)
4637 RECT rect
= {0, 0, surface
->resource
.width
, surface
->resource
.height
};
4639 if (!(surface
->locations
& WINED3D_LOCATION_RB_MULTISAMPLE
))
4640 ERR("Trying to resolve multisampled surface %p, but location WINED3D_LOCATION_RB_MULTISAMPLE not current.\n",
4643 surface_blt_fbo(surface
->resource
.device
, WINED3D_TEXF_POINT
,
4644 surface
, WINED3D_LOCATION_RB_MULTISAMPLE
, &rect
, surface
, WINED3D_LOCATION_RB_RESOLVED
, &rect
);
4647 HRESULT
surface_load_location(struct wined3d_surface
*surface
, DWORD location
)
4649 struct wined3d_device
*device
= surface
->resource
.device
;
4650 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4653 TRACE("surface %p, location %s.\n", surface
, wined3d_debug_location(location
));
4655 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
)
4657 if (location
== WINED3D_LOCATION_TEXTURE_RGB
4658 && surface
->locations
& (WINED3D_LOCATION_DRAWABLE
| WINED3D_LOCATION_DISCARDED
))
4660 struct wined3d_context
*context
= context_acquire(device
, NULL
);
4661 surface_load_ds_location(surface
, context
, location
);
4662 context_release(context
);
4665 else if (location
& surface
->locations
4666 && surface
->container
->resource
.draw_binding
!= WINED3D_LOCATION_DRAWABLE
)
4668 /* Already up to date, nothing to do. */
4673 FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
4674 wined3d_debug_location(surface
->locations
), wined3d_debug_location(location
));
4675 return WINED3DERR_INVALIDCALL
;
4679 if (surface
->locations
& location
)
4681 TRACE("Location already up to date.\n");
4685 if (WARN_ON(d3d_surface
))
4687 DWORD required_access
= resource_access_from_location(location
);
4688 if ((surface
->resource
.access_flags
& required_access
) != required_access
)
4689 WARN("Operation requires %#x access, but surface only has %#x.\n",
4690 required_access
, surface
->resource
.access_flags
);
4693 if (!surface
->locations
)
4695 ERR("Surface %p does not have any up to date location.\n", surface
);
4696 surface
->flags
|= SFLAG_LOST
;
4697 return WINED3DERR_DEVICELOST
;
4702 case WINED3D_LOCATION_DIB
:
4703 case WINED3D_LOCATION_USER_MEMORY
:
4704 case WINED3D_LOCATION_SYSMEM
:
4705 case WINED3D_LOCATION_BUFFER
:
4706 surface_load_sysmem(surface
, gl_info
, location
);
4709 case WINED3D_LOCATION_DRAWABLE
:
4710 if (FAILED(hr
= surface_load_drawable(surface
, gl_info
)))
4714 case WINED3D_LOCATION_RB_RESOLVED
:
4715 surface_multisample_resolve(surface
);
4718 case WINED3D_LOCATION_TEXTURE_RGB
:
4719 case WINED3D_LOCATION_TEXTURE_SRGB
:
4720 if (FAILED(hr
= surface_load_texture(surface
, gl_info
, location
== WINED3D_LOCATION_TEXTURE_SRGB
)))
4725 ERR("Don't know how to handle location %#x.\n", location
);
4729 surface_validate_location(surface
, location
);
4731 if (location
!= WINED3D_LOCATION_SYSMEM
&& (surface
->locations
& WINED3D_LOCATION_SYSMEM
))
4732 surface_evict_sysmem(surface
);
4737 static HRESULT
ffp_blit_alloc(struct wined3d_device
*device
) { return WINED3D_OK
; }
4738 /* Context activation is done by the caller. */
4739 static void ffp_blit_free(struct wined3d_device
*device
) { }
4741 /* Context activation is done by the caller. */
4742 static HRESULT
ffp_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4744 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4746 gl_info
->gl_ops
.gl
.p_glEnable(surface
->container
->target
);
4747 checkGLcall("glEnable(target)");
4752 /* Context activation is done by the caller. */
4753 static void ffp_blit_unset(const struct wined3d_gl_info
*gl_info
)
4755 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_2D
);
4756 checkGLcall("glDisable(GL_TEXTURE_2D)");
4757 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
4759 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
4760 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4762 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
4764 gl_info
->gl_ops
.gl
.p_glDisable(GL_TEXTURE_RECTANGLE_ARB
);
4765 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4769 static BOOL
ffp_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4770 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4771 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4775 case WINED3D_BLIT_OP_COLOR_BLIT
:
4776 if (src_pool
== WINED3D_POOL_SYSTEM_MEM
|| dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4779 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
4781 TRACE("Checking support for fixup:\n");
4782 dump_color_fixup_desc(src_format
->color_fixup
);
4785 /* We only support identity conversions. */
4786 if (!is_identity_fixup(src_format
->color_fixup
)
4787 || !is_identity_fixup(dst_format
->color_fixup
))
4789 TRACE("Fixups are not supported.\n");
4795 case WINED3D_BLIT_OP_COLOR_FILL
:
4796 if (dst_pool
== WINED3D_POOL_SYSTEM_MEM
)
4799 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
4801 if (!((dst_format
->flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
) || (dst_usage
& WINED3DUSAGE_RENDERTARGET
)))
4804 else if (!(dst_usage
& WINED3DUSAGE_RENDERTARGET
))
4806 TRACE("Color fill not supported\n");
4810 /* FIXME: We should reject color fills on formats with fixups,
4811 * but this would break P8 color fills for example. */
4815 case WINED3D_BLIT_OP_DEPTH_FILL
:
4819 TRACE("Unsupported blit_op=%d\n", blit_op
);
4824 static HRESULT
ffp_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4825 const RECT
*dst_rect
, const struct wined3d_color
*color
)
4827 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4828 struct wined3d_rendertarget_view
*view
;
4829 struct wined3d_fb_state fb
= {&view
, NULL
};
4832 if (FAILED(hr
= wined3d_rendertarget_view_create_from_surface(dst_surface
,
4833 NULL
, &wined3d_null_parent_ops
, &view
)))
4835 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
4839 device_clear_render_targets(device
, 1, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
, 0);
4840 wined3d_rendertarget_view_decref(view
);
4845 static HRESULT
ffp_blit_depth_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
4846 const RECT
*dst_rect
, float depth
)
4848 const RECT draw_rect
= {0, 0, dst_surface
->resource
.width
, dst_surface
->resource
.height
};
4849 struct wined3d_fb_state fb
= {NULL
, NULL
};
4852 if (FAILED(hr
= wined3d_rendertarget_view_create_from_surface(dst_surface
,
4853 NULL
, &wined3d_null_parent_ops
, &fb
.depth_stencil
)))
4855 ERR("Failed to create rendertarget view, hr %#x.\n", hr
);
4859 device_clear_render_targets(device
, 0, &fb
, 1, dst_rect
, &draw_rect
, WINED3DCLEAR_ZBUFFER
, 0, depth
, 0);
4860 wined3d_rendertarget_view_decref(fb
.depth_stencil
);
4865 const struct blit_shader ffp_blit
= {
4871 ffp_blit_color_fill
,
4872 ffp_blit_depth_fill
,
4875 static HRESULT
cpu_blit_alloc(struct wined3d_device
*device
)
4880 /* Context activation is done by the caller. */
4881 static void cpu_blit_free(struct wined3d_device
*device
)
4885 /* Context activation is done by the caller. */
4886 static HRESULT
cpu_blit_set(void *blit_priv
, struct wined3d_context
*context
, const struct wined3d_surface
*surface
)
4891 /* Context activation is done by the caller. */
4892 static void cpu_blit_unset(const struct wined3d_gl_info
*gl_info
)
4896 static BOOL
cpu_blit_supported(const struct wined3d_gl_info
*gl_info
, enum wined3d_blit_op blit_op
,
4897 const RECT
*src_rect
, DWORD src_usage
, enum wined3d_pool src_pool
, const struct wined3d_format
*src_format
,
4898 const RECT
*dst_rect
, DWORD dst_usage
, enum wined3d_pool dst_pool
, const struct wined3d_format
*dst_format
)
4900 if (blit_op
== WINED3D_BLIT_OP_COLOR_FILL
)
4908 static HRESULT
surface_cpu_blt_compressed(const BYTE
*src_data
, BYTE
*dst_data
,
4909 UINT src_pitch
, UINT dst_pitch
, UINT update_w
, UINT update_h
,
4910 const struct wined3d_format
*format
, DWORD flags
, const WINEDDBLTFX
*fx
)
4912 UINT row_block_count
;
4913 const BYTE
*src_row
;
4920 row_block_count
= (update_w
+ format
->block_width
- 1) / format
->block_width
;
4924 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4926 memcpy(dst_row
, src_row
, row_block_count
* format
->block_byte_count
);
4927 src_row
+= src_pitch
;
4928 dst_row
+= dst_pitch
;
4934 if (flags
== WINEDDBLT_DDFX
&& fx
->dwDDFX
== WINEDDBLTFX_MIRRORUPDOWN
)
4936 src_row
+= (((update_h
/ format
->block_height
) - 1) * src_pitch
);
4940 case WINED3DFMT_DXT1
:
4941 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4946 BYTE control_row
[4];
4949 const struct block
*s
= (const struct block
*)src_row
;
4950 struct block
*d
= (struct block
*)dst_row
;
4952 for (x
= 0; x
< row_block_count
; ++x
)
4954 d
[x
].color
[0] = s
[x
].color
[0];
4955 d
[x
].color
[1] = s
[x
].color
[1];
4956 d
[x
].control_row
[0] = s
[x
].control_row
[3];
4957 d
[x
].control_row
[1] = s
[x
].control_row
[2];
4958 d
[x
].control_row
[2] = s
[x
].control_row
[1];
4959 d
[x
].control_row
[3] = s
[x
].control_row
[0];
4961 src_row
-= src_pitch
;
4962 dst_row
+= dst_pitch
;
4966 case WINED3DFMT_DXT2
:
4967 case WINED3DFMT_DXT3
:
4968 for (y
= 0; y
< update_h
; y
+= format
->block_height
)
4974 BYTE control_row
[4];
4977 const struct block
*s
= (const struct block
*)src_row
;
4978 struct block
*d
= (struct block
*)dst_row
;
4980 for (x
= 0; x
< row_block_count
; ++x
)
4982 d
[x
].alpha_row
[0] = s
[x
].alpha_row
[3];
4983 d
[x
].alpha_row
[1] = s
[x
].alpha_row
[2];
4984 d
[x
].alpha_row
[2] = s
[x
].alpha_row
[1];
4985 d
[x
].alpha_row
[3] = s
[x
].alpha_row
[0];
4986 d
[x
].color
[0] = s
[x
].color
[0];
4987 d
[x
].color
[1] = s
[x
].color
[1];
4988 d
[x
].control_row
[0] = s
[x
].control_row
[3];
4989 d
[x
].control_row
[1] = s
[x
].control_row
[2];
4990 d
[x
].control_row
[2] = s
[x
].control_row
[1];
4991 d
[x
].control_row
[3] = s
[x
].control_row
[0];
4993 src_row
-= src_pitch
;
4994 dst_row
+= dst_pitch
;
4999 FIXME("Compressed flip not implemented for format %s.\n",
5000 debug_d3dformat(format
->id
));
5005 FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
5006 debug_d3dformat(format
->id
), flags
, flags
& WINEDDBLT_DDFX
? fx
->dwDDFX
: 0);
5011 static HRESULT
surface_cpu_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect
,
5012 struct wined3d_surface
*src_surface
, const RECT
*src_rect
, DWORD flags
,
5013 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5015 int bpp
, srcheight
, srcwidth
, dstheight
, dstwidth
, width
;
5016 const struct wined3d_format
*src_format
, *dst_format
;
5017 struct wined3d_texture
*src_texture
= NULL
;
5018 struct wined3d_map_desc dst_map
, src_map
;
5019 const BYTE
*sbase
= NULL
;
5020 HRESULT hr
= WINED3D_OK
;
5025 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5026 dst_surface
, wine_dbgstr_rect(dst_rect
), src_surface
, wine_dbgstr_rect(src_rect
),
5027 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5029 if (src_surface
== dst_surface
)
5031 wined3d_surface_map(dst_surface
, &dst_map
, NULL
, 0);
5033 src_format
= dst_surface
->resource
.format
;
5034 dst_format
= src_format
;
5038 dst_format
= dst_surface
->resource
.format
;
5041 if (dst_surface
->resource
.format
->id
!= src_surface
->resource
.format
->id
)
5043 if (!(src_texture
= surface_convert_format(src_surface
, dst_format
->id
)))
5045 /* The conv function writes a FIXME */
5046 WARN("Cannot convert source surface format to dest format.\n");
5049 src_surface
= surface_from_resource(wined3d_texture_get_sub_resource(src_texture
, 0));
5051 wined3d_surface_map(src_surface
, &src_map
, NULL
, WINED3D_MAP_READONLY
);
5052 src_format
= src_surface
->resource
.format
;
5056 src_format
= dst_format
;
5059 wined3d_surface_map(dst_surface
, &dst_map
, dst_rect
, 0);
5062 bpp
= dst_surface
->resource
.format
->byte_count
;
5063 srcheight
= src_rect
->bottom
- src_rect
->top
;
5064 srcwidth
= src_rect
->right
- src_rect
->left
;
5065 dstheight
= dst_rect
->bottom
- dst_rect
->top
;
5066 dstwidth
= dst_rect
->right
- dst_rect
->left
;
5067 width
= (dst_rect
->right
- dst_rect
->left
) * bpp
;
5070 sbase
= (BYTE
*)src_map
.data
5071 + ((src_rect
->top
/ src_format
->block_height
) * src_map
.row_pitch
)
5072 + ((src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
);
5073 if (src_surface
!= dst_surface
)
5074 dbuf
= dst_map
.data
;
5076 dbuf
= (BYTE
*)dst_map
.data
5077 + ((dst_rect
->top
/ dst_format
->block_height
) * dst_map
.row_pitch
)
5078 + ((dst_rect
->left
/ dst_format
->block_width
) * dst_format
->block_byte_count
);
5080 if (src_format
->flags
& dst_format
->flags
& WINED3DFMT_FLAG_BLOCKS
)
5082 TRACE("%s -> %s copy.\n", debug_d3dformat(src_format
->id
), debug_d3dformat(dst_format
->id
));
5084 if (src_surface
== dst_surface
)
5086 FIXME("Only plain blits supported on compressed surfaces.\n");
5091 if (srcheight
!= dstheight
|| srcwidth
!= dstwidth
)
5093 WARN("Stretching not supported on compressed surfaces.\n");
5094 hr
= WINED3DERR_INVALIDCALL
;
5098 if (!surface_check_block_align(src_surface
, src_rect
))
5100 WARN("Source rectangle not block-aligned.\n");
5101 hr
= WINED3DERR_INVALIDCALL
;
5105 if (!surface_check_block_align(dst_surface
, dst_rect
))
5107 WARN("Destination rectangle not block-aligned.\n");
5108 hr
= WINED3DERR_INVALIDCALL
;
5112 hr
= surface_cpu_blt_compressed(sbase
, dbuf
,
5113 src_map
.row_pitch
, dst_map
.row_pitch
, dstwidth
, dstheight
,
5114 src_format
, flags
, fx
);
5118 /* First, all the 'source-less' blits */
5119 if (flags
& WINEDDBLT_COLORFILL
)
5121 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, fx
->u5
.dwFillColor
);
5122 flags
&= ~WINEDDBLT_COLORFILL
;
5125 if (flags
& WINEDDBLT_DEPTHFILL
)
5127 FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
5129 if (flags
& WINEDDBLT_ROP
)
5131 /* Catch some degenerate cases here. */
5135 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, 0);
5137 case 0xaa0029: /* No-op */
5140 hr
= _Blt_ColorFill(dbuf
, dstwidth
, dstheight
, bpp
, dst_map
.row_pitch
, ~0U);
5142 case SRCCOPY
: /* Well, we do that below? */
5145 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx
->dwROP
, fx
->u5
.lpDDSPattern
);
5148 flags
&= ~WINEDDBLT_ROP
;
5150 if (flags
& WINEDDBLT_DDROPS
)
5152 FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx
->dwDDROP
, fx
->u5
.lpDDSPattern
);
5154 /* Now the 'with source' blits. */
5157 int sx
, xinc
, sy
, yinc
;
5159 if (!dstwidth
|| !dstheight
) /* Hmm... stupid program? */
5162 if (filter
!= WINED3D_TEXF_NONE
&& filter
!= WINED3D_TEXF_POINT
5163 && (srcwidth
!= dstwidth
|| srcheight
!= dstheight
))
5165 /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
5166 FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter
));
5169 xinc
= (srcwidth
<< 16) / dstwidth
;
5170 yinc
= (srcheight
<< 16) / dstheight
;
5174 /* No effects, we can cheat here. */
5175 if (dstwidth
== srcwidth
)
5177 if (dstheight
== srcheight
)
5179 /* No stretching in either direction. This needs to be as
5180 * fast as possible. */
5183 /* Check for overlapping surfaces. */
5184 if (src_surface
!= dst_surface
|| dst_rect
->top
< src_rect
->top
5185 || dst_rect
->right
<= src_rect
->left
|| src_rect
->right
<= dst_rect
->left
)
5187 /* No overlap, or dst above src, so copy from top downwards. */
5188 for (y
= 0; y
< dstheight
; ++y
)
5190 memcpy(dbuf
, sbuf
, width
);
5191 sbuf
+= src_map
.row_pitch
;
5192 dbuf
+= dst_map
.row_pitch
;
5195 else if (dst_rect
->top
> src_rect
->top
)
5197 /* Copy from bottom upwards. */
5198 sbuf
+= src_map
.row_pitch
* dstheight
;
5199 dbuf
+= dst_map
.row_pitch
* dstheight
;
5200 for (y
= 0; y
< dstheight
; ++y
)
5202 sbuf
-= src_map
.row_pitch
;
5203 dbuf
-= dst_map
.row_pitch
;
5204 memcpy(dbuf
, sbuf
, width
);
5209 /* Src and dst overlapping on the same line, use memmove. */
5210 for (y
= 0; y
< dstheight
; ++y
)
5212 memmove(dbuf
, sbuf
, width
);
5213 sbuf
+= src_map
.row_pitch
;
5214 dbuf
+= dst_map
.row_pitch
;
5220 /* Stretching in y direction only. */
5221 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5223 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5224 memcpy(dbuf
, sbuf
, width
);
5225 dbuf
+= dst_map
.row_pitch
;
5231 /* Stretching in X direction. */
5233 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5235 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5237 if ((sy
>> 16) == (last_sy
>> 16))
5239 /* This source row is the same as last source row -
5240 * Copy the already stretched row. */
5241 memcpy(dbuf
, dbuf
- dst_map
.row_pitch
, width
);
5245 #define STRETCH_ROW(type) \
5247 const type *s = (const type *)sbuf; \
5248 type *d = (type *)dbuf; \
5249 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5250 d[x] = s[sx >> 16]; \
5268 for (x
= sx
= 0; x
< dstwidth
; x
++, sx
+= xinc
)
5272 s
= sbuf
+ 3 * (sx
>> 16);
5273 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5274 d
[0] = (pixel
) & 0xff;
5275 d
[1] = (pixel
>> 8) & 0xff;
5276 d
[2] = (pixel
>> 16) & 0xff;
5282 FIXME("Stretched blit not implemented for bpp %u!\n", bpp
* 8);
5283 hr
= WINED3DERR_NOTAVAILABLE
;
5288 dbuf
+= dst_map
.row_pitch
;
5295 LONG dstyinc
= dst_map
.row_pitch
, dstxinc
= bpp
;
5296 DWORD keylow
= 0xffffffff, keyhigh
= 0, keymask
= 0xffffffff;
5297 DWORD destkeylow
= 0x0, destkeyhigh
= 0xffffffff, destkeymask
= 0xffffffff;
5298 if (flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
))
5300 /* The color keying flags are checked for correctness in ddraw */
5301 if (flags
& WINEDDBLT_KEYSRC
)
5303 keylow
= src_surface
->container
->src_blt_color_key
.color_space_low_value
;
5304 keyhigh
= src_surface
->container
->src_blt_color_key
.color_space_high_value
;
5306 else if (flags
& WINEDDBLT_KEYSRCOVERRIDE
)
5308 keylow
= fx
->ddckSrcColorkey
.color_space_low_value
;
5309 keyhigh
= fx
->ddckSrcColorkey
.color_space_high_value
;
5312 if (flags
& WINEDDBLT_KEYDEST
)
5314 /* Destination color keys are taken from the source surface! */
5315 destkeylow
= src_surface
->container
->dst_blt_color_key
.color_space_low_value
;
5316 destkeyhigh
= src_surface
->container
->dst_blt_color_key
.color_space_high_value
;
5318 else if (flags
& WINEDDBLT_KEYDESTOVERRIDE
)
5320 destkeylow
= fx
->ddckDestColorkey
.color_space_low_value
;
5321 destkeyhigh
= fx
->ddckDestColorkey
.color_space_high_value
;
5331 get_color_masks(src_format
, masks
);
5336 flags
&= ~(WINEDDBLT_KEYSRC
| WINEDDBLT_KEYDEST
| WINEDDBLT_KEYSRCOVERRIDE
| WINEDDBLT_KEYDESTOVERRIDE
);
5339 if (flags
& WINEDDBLT_DDFX
)
5341 BYTE
*dTopLeft
, *dTopRight
, *dBottomLeft
, *dBottomRight
, *tmp
;
5344 dTopRight
= dbuf
+ ((dstwidth
- 1) * bpp
);
5345 dBottomLeft
= dTopLeft
+ ((dstheight
- 1) * dst_map
.row_pitch
);
5346 dBottomRight
= dBottomLeft
+ ((dstwidth
- 1) * bpp
);
5348 if (fx
->dwDDFX
& WINEDDBLTFX_ARITHSTRETCHY
)
5350 /* I don't think we need to do anything about this flag */
5351 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
5353 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORLEFTRIGHT
)
5356 dTopRight
= dTopLeft
;
5359 dBottomRight
= dBottomLeft
;
5361 dstxinc
= dstxinc
* -1;
5363 if (fx
->dwDDFX
& WINEDDBLTFX_MIRRORUPDOWN
)
5366 dTopLeft
= dBottomLeft
;
5369 dTopRight
= dBottomRight
;
5371 dstyinc
= dstyinc
* -1;
5373 if (fx
->dwDDFX
& WINEDDBLTFX_NOTEARING
)
5375 /* I don't think we need to do anything about this flag */
5376 WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
5378 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE180
)
5381 dBottomRight
= dTopLeft
;
5384 dBottomLeft
= dTopRight
;
5386 dstxinc
= dstxinc
* -1;
5387 dstyinc
= dstyinc
* -1;
5389 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE270
)
5392 dTopLeft
= dBottomLeft
;
5393 dBottomLeft
= dBottomRight
;
5394 dBottomRight
= dTopRight
;
5399 dstxinc
= dstxinc
* -1;
5401 if (fx
->dwDDFX
& WINEDDBLTFX_ROTATE90
)
5404 dTopLeft
= dTopRight
;
5405 dTopRight
= dBottomRight
;
5406 dBottomRight
= dBottomLeft
;
5411 dstyinc
= dstyinc
* -1;
5413 if (fx
->dwDDFX
& WINEDDBLTFX_ZBUFFERBASEDEST
)
5415 /* I don't think we need to do anything about this flag */
5416 WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
5419 flags
&= ~(WINEDDBLT_DDFX
);
5422 #define COPY_COLORKEY_FX(type) \
5425 type *d = (type *)dbuf, *dx, tmp; \
5426 for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
5428 s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
5430 for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
5432 tmp = s[sx >> 16]; \
5433 if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
5434 && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
5438 dx = (type *)(((BYTE *)dx) + dstxinc); \
5440 d = (type *)(((BYTE *)d) + dstyinc); \
5447 COPY_COLORKEY_FX(BYTE
);
5450 COPY_COLORKEY_FX(WORD
);
5453 COPY_COLORKEY_FX(DWORD
);
5458 BYTE
*d
= dbuf
, *dx
;
5459 for (y
= sy
= 0; y
< dstheight
; ++y
, sy
+= yinc
)
5461 sbuf
= sbase
+ (sy
>> 16) * src_map
.row_pitch
;
5463 for (x
= sx
= 0; x
< dstwidth
; ++x
, sx
+= xinc
)
5465 DWORD pixel
, dpixel
= 0;
5466 s
= sbuf
+ 3 * (sx
>>16);
5467 pixel
= s
[0] | (s
[1] << 8) | (s
[2] << 16);
5468 dpixel
= dx
[0] | (dx
[1] << 8 ) | (dx
[2] << 16);
5469 if (((pixel
& keymask
) < keylow
|| (pixel
& keymask
) > keyhigh
)
5470 && ((dpixel
& keymask
) >= destkeylow
|| (dpixel
& keymask
) <= keyhigh
))
5472 dx
[0] = (pixel
) & 0xff;
5473 dx
[1] = (pixel
>> 8) & 0xff;
5474 dx
[2] = (pixel
>> 16) & 0xff;
5483 FIXME("%s color-keyed blit not implemented for bpp %u!\n",
5484 (flags
& WINEDDBLT_KEYSRC
) ? "Source" : "Destination", bpp
* 8);
5485 hr
= WINED3DERR_NOTAVAILABLE
;
5487 #undef COPY_COLORKEY_FX
5493 if (flags
&& FIXME_ON(d3d_surface
))
5495 FIXME("\tUnsupported flags: %#x.\n", flags
);
5499 wined3d_surface_unmap(dst_surface
);
5500 if (src_surface
&& src_surface
!= dst_surface
)
5501 wined3d_surface_unmap(src_surface
);
5502 /* Release the converted surface, if any. */
5504 wined3d_texture_decref(src_texture
);
5509 static HRESULT
cpu_blit_color_fill(struct wined3d_device
*device
, struct wined3d_surface
*dst_surface
,
5510 const RECT
*dst_rect
, const struct wined3d_color
*color
)
5512 static const RECT src_rect
;
5515 memset(&BltFx
, 0, sizeof(BltFx
));
5516 BltFx
.dwSize
= sizeof(BltFx
);
5517 BltFx
.u5
.dwFillColor
= wined3d_format_convert_from_float(dst_surface
, color
);
5518 return surface_cpu_blt(dst_surface
, dst_rect
, NULL
, &src_rect
,
5519 WINEDDBLT_COLORFILL
, &BltFx
, WINED3D_TEXF_POINT
);
5522 static HRESULT
cpu_blit_depth_fill(struct wined3d_device
*device
,
5523 struct wined3d_surface
*surface
, const RECT
*rect
, float depth
)
5525 FIXME("Depth filling not implemented by cpu_blit.\n");
5526 return WINED3DERR_INVALIDCALL
;
5529 const struct blit_shader cpu_blit
= {
5535 cpu_blit_color_fill
,
5536 cpu_blit_depth_fill
,
5539 HRESULT CDECL
wined3d_surface_blt(struct wined3d_surface
*dst_surface
, const RECT
*dst_rect_in
,
5540 struct wined3d_surface
*src_surface
, const RECT
*src_rect_in
, DWORD flags
,
5541 const WINEDDBLTFX
*fx
, enum wined3d_texture_filter_type filter
)
5543 struct wined3d_swapchain
*src_swapchain
, *dst_swapchain
;
5544 struct wined3d_device
*device
= dst_surface
->resource
.device
;
5545 DWORD src_ds_flags
, dst_ds_flags
;
5546 RECT src_rect
, dst_rect
;
5547 BOOL scale
, convert
;
5548 enum wined3d_conversion_type dst_convert_type
;
5549 struct wined3d_format dst_conv_fmt
;
5551 static const DWORD simple_blit
= WINEDDBLT_ASYNC
5552 | WINEDDBLT_COLORFILL
5554 | WINEDDBLT_DEPTHFILL
5555 | WINEDDBLT_DONOTWAIT
;
5557 TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
5558 dst_surface
, wine_dbgstr_rect(dst_rect_in
), src_surface
, wine_dbgstr_rect(src_rect_in
),
5559 flags
, fx
, debug_d3dtexturefiltertype(filter
));
5560 TRACE("Usage is %s.\n", debug_d3dusage(dst_surface
->resource
.usage
));
5564 TRACE("dwSize %#x.\n", fx
->dwSize
);
5565 TRACE("dwDDFX %#x.\n", fx
->dwDDFX
);
5566 TRACE("dwROP %#x.\n", fx
->dwROP
);
5567 TRACE("dwDDROP %#x.\n", fx
->dwDDROP
);
5568 TRACE("dwRotationAngle %#x.\n", fx
->dwRotationAngle
);
5569 TRACE("dwZBufferOpCode %#x.\n", fx
->dwZBufferOpCode
);
5570 TRACE("dwZBufferLow %#x.\n", fx
->dwZBufferLow
);
5571 TRACE("dwZBufferHigh %#x.\n", fx
->dwZBufferHigh
);
5572 TRACE("dwZBufferBaseDest %#x.\n", fx
->dwZBufferBaseDest
);
5573 TRACE("dwZDestConstBitDepth %#x.\n", fx
->dwZDestConstBitDepth
);
5574 TRACE("lpDDSZBufferDest %p.\n", fx
->u1
.lpDDSZBufferDest
);
5575 TRACE("dwZSrcConstBitDepth %#x.\n", fx
->dwZSrcConstBitDepth
);
5576 TRACE("lpDDSZBufferSrc %p.\n", fx
->u2
.lpDDSZBufferSrc
);
5577 TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx
->dwAlphaEdgeBlendBitDepth
);
5578 TRACE("dwAlphaEdgeBlend %#x.\n", fx
->dwAlphaEdgeBlend
);
5579 TRACE("dwReserved %#x.\n", fx
->dwReserved
);
5580 TRACE("dwAlphaDestConstBitDepth %#x.\n", fx
->dwAlphaDestConstBitDepth
);
5581 TRACE("lpDDSAlphaDest %p.\n", fx
->u3
.lpDDSAlphaDest
);
5582 TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx
->dwAlphaSrcConstBitDepth
);
5583 TRACE("lpDDSAlphaSrc %p.\n", fx
->u4
.lpDDSAlphaSrc
);
5584 TRACE("lpDDSPattern %p.\n", fx
->u5
.lpDDSPattern
);
5585 TRACE("ddckDestColorkey {%#x, %#x}.\n",
5586 fx
->ddckDestColorkey
.color_space_low_value
,
5587 fx
->ddckDestColorkey
.color_space_high_value
);
5588 TRACE("ddckSrcColorkey {%#x, %#x}.\n",
5589 fx
->ddckSrcColorkey
.color_space_low_value
,
5590 fx
->ddckSrcColorkey
.color_space_high_value
);
5593 if (dst_surface
->resource
.map_count
|| (src_surface
&& src_surface
->resource
.map_count
))
5595 WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
5596 return WINEDDERR_SURFACEBUSY
;
5599 surface_get_rect(dst_surface
, dst_rect_in
, &dst_rect
);
5601 if (dst_rect
.left
>= dst_rect
.right
|| dst_rect
.top
>= dst_rect
.bottom
5602 || dst_rect
.left
> dst_surface
->resource
.width
|| dst_rect
.left
< 0
5603 || dst_rect
.top
> dst_surface
->resource
.height
|| dst_rect
.top
< 0
5604 || dst_rect
.right
> dst_surface
->resource
.width
|| dst_rect
.right
< 0
5605 || dst_rect
.bottom
> dst_surface
->resource
.height
|| dst_rect
.bottom
< 0)
5607 WARN("The application gave us a bad destination rectangle.\n");
5608 return WINEDDERR_INVALIDRECT
;
5613 surface_get_rect(src_surface
, src_rect_in
, &src_rect
);
5615 if (src_rect
.left
>= src_rect
.right
|| src_rect
.top
>= src_rect
.bottom
5616 || src_rect
.left
> src_surface
->resource
.width
|| src_rect
.left
< 0
5617 || src_rect
.top
> src_surface
->resource
.height
|| src_rect
.top
< 0
5618 || src_rect
.right
> src_surface
->resource
.width
|| src_rect
.right
< 0
5619 || src_rect
.bottom
> src_surface
->resource
.height
|| src_rect
.bottom
< 0)
5621 WARN("Application gave us bad source rectangle for Blt.\n");
5622 return WINEDDERR_INVALIDRECT
;
5627 memset(&src_rect
, 0, sizeof(src_rect
));
5630 if (!fx
|| !(fx
->dwDDFX
))
5631 flags
&= ~WINEDDBLT_DDFX
;
5633 if (flags
& WINEDDBLT_WAIT
)
5634 flags
&= ~WINEDDBLT_WAIT
;
5636 if (flags
& WINEDDBLT_ASYNC
)
5638 static unsigned int once
;
5641 FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
5642 flags
&= ~WINEDDBLT_ASYNC
;
5645 /* WINEDDBLT_DONOTWAIT appeared in DX7. */
5646 if (flags
& WINEDDBLT_DONOTWAIT
)
5648 static unsigned int once
;
5651 FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
5652 flags
&= ~WINEDDBLT_DONOTWAIT
;
5655 if (!device
->d3d_initialized
)
5657 WARN("D3D not initialized, using fallback.\n");
5661 /* We want to avoid invalidating the sysmem location for converted
5662 * surfaces, since otherwise we'd have to convert the data back when
5664 d3dfmt_get_conv(dst_surface
->container
, TRUE
, &dst_conv_fmt
, &dst_convert_type
);
5665 if (dst_convert_type
!= WINED3D_CT_NONE
|| dst_conv_fmt
.convert
|| dst_surface
->flags
& SFLAG_CONVERTED
)
5667 WARN_(d3d_perf
)("Converted surface, using CPU blit.\n");
5671 if (flags
& ~simple_blit
)
5673 WARN_(d3d_perf
)("Using fallback for complex blit (%#x).\n", flags
);
5678 src_swapchain
= src_surface
->container
->swapchain
;
5680 src_swapchain
= NULL
;
5682 dst_swapchain
= dst_surface
->container
->swapchain
;
5684 /* This isn't strictly needed. FBO blits for example could deal with
5685 * cross-swapchain blits by first downloading the source to a texture
5686 * before switching to the destination context. We just have this here to
5687 * not have to deal with the issue, since cross-swapchain blits should be
5689 if (src_swapchain
&& dst_swapchain
&& src_swapchain
!= dst_swapchain
)
5691 FIXME("Using fallback for cross-swapchain blit.\n");
5696 && (src_rect
.right
- src_rect
.left
!= dst_rect
.right
- dst_rect
.left
5697 || src_rect
.bottom
- src_rect
.top
!= dst_rect
.bottom
- dst_rect
.top
);
5698 convert
= src_surface
&& src_surface
->resource
.format
->id
!= dst_surface
->resource
.format
->id
;
5700 dst_ds_flags
= dst_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5702 src_ds_flags
= src_surface
->resource
.format
->flags
& (WINED3DFMT_FLAG_DEPTH
| WINED3DFMT_FLAG_STENCIL
);
5706 if (src_ds_flags
|| dst_ds_flags
)
5708 if (flags
& WINEDDBLT_DEPTHFILL
)
5712 TRACE("Depth fill.\n");
5714 if (!surface_convert_depth_to_float(dst_surface
, fx
->u5
.dwFillDepth
, &depth
))
5715 return WINED3DERR_INVALIDCALL
;
5717 if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface
, &dst_rect
, depth
)))
5722 if (src_ds_flags
!= dst_ds_flags
)
5724 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
5725 return WINED3DERR_INVALIDCALL
;
5728 if (SUCCEEDED(wined3d_surface_depth_blt(src_surface
, src_surface
->container
->resource
.draw_binding
,
5729 &src_rect
, dst_surface
, dst_surface
->container
->resource
.draw_binding
, &dst_rect
)))
5735 /* In principle this would apply to depth blits as well, but we don't
5736 * implement those in the CPU blitter at the moment. */
5737 if ((dst_surface
->locations
& dst_surface
->resource
.map_binding
)
5738 && (!src_surface
|| (src_surface
->locations
& src_surface
->resource
.map_binding
)))
5741 TRACE("Not doing sysmem blit because of scaling.\n");
5743 TRACE("Not doing sysmem blit because of format conversion.\n");
5748 if (flags
& WINEDDBLT_COLORFILL
)
5750 struct wined3d_color color
;
5752 TRACE("Color fill.\n");
5754 if (!surface_convert_color_to_float(dst_surface
, fx
->u5
.dwFillColor
, &color
))
5757 if (SUCCEEDED(surface_color_fill(dst_surface
, &dst_rect
, &color
)))
5762 TRACE("Color blit.\n");
5765 if ((src_surface
->locations
& WINED3D_LOCATION_SYSMEM
)
5766 && !(dst_surface
->locations
& WINED3D_LOCATION_SYSMEM
))
5769 TRACE("Not doing upload because of scaling.\n");
5771 TRACE("Not doing upload because of format conversion.\n");
5774 POINT dst_point
= {dst_rect
.left
, dst_rect
.top
};
5776 if (SUCCEEDED(surface_upload_from_surface(dst_surface
, &dst_point
, src_surface
, &src_rect
)))
5778 if (!wined3d_resource_is_offscreen(&dst_surface
->container
->resource
))
5779 surface_load_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5785 /* Use present for back -> front blits. The idea behind this is
5786 * that present is potentially faster than a blit, in particular
5787 * when FBO blits aren't available. Some ddraw applications like
5788 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
5789 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
5790 * applications can't blit directly to the frontbuffer. */
5791 if (dst_swapchain
&& dst_swapchain
->back_buffers
5792 && dst_surface
->container
== dst_swapchain
->front_buffer
5793 && src_surface
->container
== dst_swapchain
->back_buffers
[0])
5795 enum wined3d_swap_effect swap_effect
= dst_swapchain
->desc
.swap_effect
;
5797 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
5799 /* Set the swap effect to COPY, we don't want the backbuffer
5800 * to become undefined. */
5801 dst_swapchain
->desc
.swap_effect
= WINED3D_SWAP_EFFECT_COPY
;
5802 wined3d_swapchain_present(dst_swapchain
, NULL
, NULL
, dst_swapchain
->win_handle
, NULL
, 0);
5803 dst_swapchain
->desc
.swap_effect
= swap_effect
;
5808 if (fbo_blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5809 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5810 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5812 TRACE("Using FBO blit.\n");
5814 surface_blt_fbo(device
, filter
,
5815 src_surface
, src_surface
->container
->resource
.draw_binding
, &src_rect
,
5816 dst_surface
, dst_surface
->container
->resource
.draw_binding
, &dst_rect
);
5817 surface_validate_location(dst_surface
, dst_surface
->container
->resource
.draw_binding
);
5818 surface_invalidate_location(dst_surface
, ~dst_surface
->container
->resource
.draw_binding
);
5823 if (arbfp_blit
.blit_supported(&device
->adapter
->gl_info
, WINED3D_BLIT_OP_COLOR_BLIT
,
5824 &src_rect
, src_surface
->resource
.usage
, src_surface
->resource
.pool
, src_surface
->resource
.format
,
5825 &dst_rect
, dst_surface
->resource
.usage
, dst_surface
->resource
.pool
, dst_surface
->resource
.format
))
5827 TRACE("Using arbfp blit.\n");
5829 if (SUCCEEDED(arbfp_blit_surface(device
, filter
, src_surface
, &src_rect
, dst_surface
, &dst_rect
)))
5836 /* Special cases for render targets. */
5837 if (SUCCEEDED(surface_blt_special(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
)))
5842 /* For the rest call the X11 surface implementation. For render targets
5843 * this should be implemented OpenGL accelerated in surface_blt_special(),
5844 * other blits are rather rare. */
5845 return surface_cpu_blt(dst_surface
, &dst_rect
, src_surface
, &src_rect
, flags
, fx
, filter
);
5848 static HRESULT
surface_init(struct wined3d_surface
*surface
, struct wined3d_texture
*container
,
5849 const struct wined3d_resource_desc
*desc
, GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
)
5851 struct wined3d_device
*device
= container
->resource
.device
;
5852 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5853 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, desc
->format
);
5854 UINT multisample_quality
= desc
->multisample_quality
;
5855 BOOL lockable
= flags
& WINED3D_SURFACE_MAPPABLE
;
5856 unsigned int resource_size
;
5859 if (multisample_quality
> 0)
5861 FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality
);
5862 multisample_quality
= 0;
5865 /* Quick lockable sanity check.
5866 * TODO: remove this after surfaces, usage and lockability have been debugged properly
5867 * this function is too deep to need to care about things like this.
5868 * Levels need to be checked too, since they all affect what can be done. */
5871 case WINED3D_POOL_MANAGED
:
5872 if (desc
->usage
& WINED3DUSAGE_DYNAMIC
)
5873 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
5876 case WINED3D_POOL_DEFAULT
:
5877 if (lockable
&& !(desc
->usage
& (WINED3DUSAGE_DYNAMIC
5878 | WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
5879 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
5882 case WINED3D_POOL_SCRATCH
:
5883 case WINED3D_POOL_SYSTEM_MEM
:
5887 FIXME("Unknown pool %#x.\n", desc
->pool
);
5891 if (desc
->usage
& WINED3DUSAGE_RENDERTARGET
&& desc
->pool
!= WINED3D_POOL_DEFAULT
)
5892 FIXME("Trying to create a render target that isn't in the default pool.\n");
5894 /* FIXME: Check that the format is supported by the device. */
5896 resource_size
= wined3d_format_calculate_size(format
, device
->surface_alignment
, desc
->width
, desc
->height
, 1);
5898 return WINED3DERR_INVALIDCALL
;
5900 if (device
->wined3d
->flags
& WINED3D_NO3D
)
5901 surface
->surface_ops
= &gdi_surface_ops
;
5903 surface
->surface_ops
= &surface_ops
;
5905 if (FAILED(hr
= resource_init(&surface
->resource
, device
, WINED3D_RTYPE_SURFACE
, format
,
5906 desc
->multisample_type
, multisample_quality
, desc
->usage
, desc
->pool
, desc
->width
, desc
->height
, 1,
5907 resource_size
, NULL
, &wined3d_null_parent_ops
, &surface_resource_ops
)))
5909 WARN("Failed to initialize resource, returning %#x.\n", hr
);
5913 surface
->container
= container
;
5914 surface_validate_location(surface
, WINED3D_LOCATION_SYSMEM
);
5915 list_init(&surface
->renderbuffers
);
5916 list_init(&surface
->overlays
);
5919 if (target
!= GL_TEXTURE_RECTANGLE_ARB
)
5920 surface
->flags
|= SFLAG_NORMCOORD
;
5921 if (flags
& WINED3D_SURFACE_DISCARD
)
5922 surface
->flags
|= SFLAG_DISCARD
;
5923 if (flags
& WINED3D_SURFACE_PIN_SYSMEM
)
5924 surface
->flags
|= SFLAG_PIN_SYSMEM
;
5925 if (lockable
|| desc
->format
== WINED3DFMT_D16_LOCKABLE
)
5926 surface
->resource
.access_flags
|= WINED3D_RESOURCE_ACCESS_CPU
;
5928 surface
->texture_target
= target
;
5929 surface
->texture_level
= level
;
5930 surface
->texture_layer
= layer
;
5932 /* Call the private setup routine */
5933 if (FAILED(hr
= surface
->surface_ops
->surface_private_setup(surface
)))
5935 ERR("Private setup failed, hr %#x.\n", hr
);
5936 surface_cleanup(surface
);
5940 /* Similar to lockable rendertargets above, creating the DIB section
5941 * during surface initialization prevents the sysmem pointer from changing
5942 * after a wined3d_surface_getdc() call. */
5943 if ((desc
->usage
& WINED3DUSAGE_OWNDC
) && !surface
->hDC
5944 && SUCCEEDED(surface_create_dib_section(surface
)))
5945 surface
->resource
.map_binding
= WINED3D_LOCATION_DIB
;
5947 if (surface
->resource
.map_binding
== WINED3D_LOCATION_DIB
)
5949 wined3d_resource_free_sysmem(&surface
->resource
);
5950 surface_validate_location(surface
, WINED3D_LOCATION_DIB
);
5951 surface_invalidate_location(surface
, WINED3D_LOCATION_SYSMEM
);
5957 HRESULT
wined3d_surface_create(struct wined3d_texture
*container
, const struct wined3d_resource_desc
*desc
,
5958 GLenum target
, unsigned int level
, unsigned int layer
, DWORD flags
, struct wined3d_surface
**surface
)
5960 struct wined3d_device_parent
*device_parent
= container
->resource
.device
->device_parent
;
5961 const struct wined3d_parent_ops
*parent_ops
;
5962 struct wined3d_surface
*object
;
5966 TRACE("container %p, width %u, height %u, format %s, usage %s (%#x), pool %s, "
5967 "multisample_type %#x, multisample_quality %u, target %#x, level %u, layer %u, flags %#x, surface %p.\n",
5968 container
, desc
->width
, desc
->height
, debug_d3dformat(desc
->format
),
5969 debug_d3dusage(desc
->usage
), desc
->usage
, debug_d3dpool(desc
->pool
),
5970 desc
->multisample_type
, desc
->multisample_quality
, target
, level
, layer
, flags
, surface
);
5972 if (!(object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
))))
5973 return E_OUTOFMEMORY
;
5975 if (FAILED(hr
= surface_init(object
, container
, desc
, target
, level
, layer
, flags
)))
5977 WARN("Failed to initialize surface, returning %#x.\n", hr
);
5978 HeapFree(GetProcessHeap(), 0, object
);
5982 if (FAILED(hr
= device_parent
->ops
->surface_created(device_parent
,
5983 wined3d_texture_get_parent(container
), object
, &parent
, &parent_ops
)))
5985 WARN("Failed to create surface parent, hr %#x.\n", hr
);
5986 wined3d_surface_destroy(object
);
5990 TRACE("Created surface %p, parent %p, parent_ops %p.\n", object
, parent
, parent_ops
);
5992 object
->resource
.parent
= parent
;
5993 object
->resource
.parent_ops
= parent_ops
;