Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
e5343404
Commit
e5343404
authored
Feb 12, 2007
by
Stefan Dösinger
Committed by
Alexandre Julliard
Feb 13, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wined3d: Improve render target to texture blits.
parent
f22d37e4
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
276 additions
and
43 deletions
+276
-43
surface.c
dlls/wined3d/surface.c
+276
-43
No files found.
dlls/wined3d/surface.c
View file @
e5343404
...
...
@@ -2191,6 +2191,240 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DS
return
IWineD3DDevice_Present
(
D3D
,
NULL
,
NULL
,
0
,
NULL
);
}
/* Does a direct frame buffer -> texture copy. Stretching is done
* with single pixel copy calls
*/
static
inline
void
fb_copy_to_texture_direct
(
IWineD3DSurfaceImpl
*
This
,
IWineD3DSurface
*
SrcSurface
,
IWineD3DSwapChainImpl
*
swapchain
,
WINED3DRECT
*
srect
,
WINED3DRECT
*
drect
,
BOOL
upsidedown
)
{
IWineD3DDeviceImpl
*
myDevice
=
This
->
resource
.
wineD3DDevice
;
float
xrel
,
yrel
;
UINT
row
;
BOOL
warned
=
FALSE
;
/* deliberately not static */
IWineD3DSurfaceImpl
*
Src
=
(
IWineD3DSurfaceImpl
*
)
SrcSurface
;
ENTER_GL
();
ActivateContext
(
myDevice
,
SrcSurface
,
CTXUSAGE_BLIT
);
/* Bind the target texture */
glBindTexture
(
GL_TEXTURE_2D
,
This
->
glDescription
.
textureName
);
checkGLcall
(
"glBindTexture"
);
if
(
swapchain
->
backBuffer
&&
SrcSurface
==
swapchain
->
backBuffer
[
0
])
{
glReadBuffer
(
GL_BACK
);
}
else
{
glReadBuffer
(
GL_FRONT
);
}
checkGLcall
(
"glReadBuffer"
);
xrel
=
(
float
)
(
srect
->
x2
-
srect
->
x1
)
/
(
float
)
(
drect
->
x2
-
drect
->
x1
);
yrel
=
(
float
)
(
srect
->
y2
-
srect
->
y1
)
/
(
float
)
(
drect
->
y2
-
drect
->
y1
);
if
(
(
xrel
-
1
.
0
<
-
eps
)
||
(
xrel
-
1
.
0
>
eps
))
{
FIXME
(
"Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues
\n
"
);
}
if
(
upsidedown
&&
!
((
xrel
-
1
.
0
<
-
eps
)
||
(
xrel
-
1
.
0
>
eps
))
&&
!
((
yrel
-
1
.
0
<
-
eps
)
||
(
yrel
-
1
.
0
>
eps
)))
{
/* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
glCopyTexSubImage2D
(
This
->
glDescription
.
target
,
This
->
glDescription
.
level
,
drect
->
x1
,
drect
->
y1
,
/* xoffset, yoffset */
srect
->
x1
,
Src
->
currentDesc
.
Height
-
srect
->
y2
,
drect
->
x2
-
drect
->
x1
,
drect
->
y2
-
drect
->
y1
);
}
else
{
UINT
yoffset
=
Src
->
currentDesc
.
Height
-
srect
->
y1
+
drect
->
y1
-
1
;
/* I have to process this row by row to swap the image,
* otherwise it would be upside down, so streching in y direction
* doesn't cost extra time
*
* However, streching in x direction can be avoided if not necessary
*/
for
(
row
=
drect
->
y1
;
row
<
drect
->
y2
;
row
++
)
{
if
(
(
xrel
-
1
.
0
<
-
eps
)
||
(
xrel
-
1
.
0
>
eps
))
{
/* Well, that stuff works, but it's very slow.
* find a better way instead
*/
UINT
col
;
if
(
!
warned
)
{
warned
=
TRUE
;
FIXME
(
"Doing a pixel by pixel render target -> texture copy, expect performance issues
\n
"
);
}
for
(
col
=
drect
->
x1
;
col
<
drect
->
x2
;
col
++
)
{
glCopyTexSubImage2D
(
This
->
glDescription
.
target
,
This
->
glDescription
.
level
,
drect
->
x1
+
col
,
row
,
/* xoffset, yoffset */
srect
->
x1
+
col
*
xrel
,
yoffset
-
(
int
)
(
row
*
yrel
),
1
,
1
);
}
}
else
{
glCopyTexSubImage2D
(
This
->
glDescription
.
target
,
This
->
glDescription
.
level
,
drect
->
x1
,
row
,
/* xoffset, yoffset */
srect
->
x1
,
yoffset
-
(
int
)
(
row
*
yrel
),
drect
->
x2
-
drect
->
x1
,
1
);
}
}
}
vcheckGLcall
(
"glCopyTexSubImage2D"
);
LEAVE_GL
();
}
/* Uses the hardware to stretch and flip the image */
static
inline
void
fb_copy_to_texture_hwstretch
(
IWineD3DSurfaceImpl
*
This
,
IWineD3DSurface
*
SrcSurface
,
IWineD3DSwapChainImpl
*
swapchain
,
WINED3DRECT
*
srect
,
WINED3DRECT
*
drect
,
BOOL
upsidedown
)
{
GLuint
backup
,
src
;
IWineD3DDeviceImpl
*
myDevice
=
This
->
resource
.
wineD3DDevice
;
IWineD3DSurfaceImpl
*
Src
=
(
IWineD3DSurfaceImpl
*
)
SrcSurface
;
float
left
,
right
,
top
,
bottom
;
/* Texture coordinates */
UINT
fbwidth
=
Src
->
currentDesc
.
Width
;
UINT
fbheight
=
Src
->
currentDesc
.
Height
;
TRACE
(
"Using hwstretch blit
\n
"
);
/* Activate the Proper context for reading from the source surface, set it up for blitting */
ENTER_GL
();
ActivateContext
(
myDevice
,
SrcSurface
,
CTXUSAGE_BLIT
);
/* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
* we are reading from the back buffer, the backup can be used as source texture
*/
glGenTextures
(
1
,
&
backup
);
checkGLcall
(
"glGenTextures(1, &backup)"
);
glBindTexture
(
GL_TEXTURE_2D
,
backup
);
checkGLcall
(
"glBindTexture(GL_TEXTURE_2D, backup)"
);
glReadBuffer
(
GL_BACK
);
checkGLcall
(
"glReadBuffer(GL_BACK)"
);
/* TODO: Only back up the part that will be overwritten */
glTexImage2D
(
GL_TEXTURE_2D
,
0
,
GL_RGBA
,
Src
->
pow2Width
,
Src
->
pow2Height
,
0
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
NULL
);
checkGLcall
(
"glTexImage2D"
);
glCopyTexSubImage2D
(
GL_TEXTURE_2D
,
0
,
0
,
0
/* read offsets */
,
0
,
0
,
fbwidth
,
fbheight
);
checkGLcall
(
"glCopyTexSubImage2D"
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
);
checkGLcall
(
"glTexParameteri"
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MIN_FILTER
,
GL_NEAREST
);
checkGLcall
(
"glTexParameteri"
);
if
((
IWineD3DSurface
*
)
This
==
swapchain
->
backBuffer
[
0
]
||
TRUE
)
{
src
=
backup
;
}
else
{
glReadBuffer
(
GL_FRONT
);
checkGLcall
(
"glReadBuffer(GL_FRONT)"
);
glGenTextures
(
1
,
&
src
);
checkGLcall
(
"glGenTextures(1, &src)"
);
glBindTexture
(
GL_TEXTURE_2D
,
src
);
checkGLcall
(
"glBindTexture(GL_TEXTURE_2D, src)"
);
/* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
* out for power of 2 sizes
*/
glTexImage2D
(
GL_TEXTURE_2D
,
0
,
GL_RGBA
,
Src
->
pow2Width
,
Src
->
pow2Height
,
0
,
GL_RGBA
,
GL_UNSIGNED_BYTE
,
NULL
);
checkGLcall
(
"glTexImage2D"
);
glCopyTexSubImage2D
(
GL_TEXTURE_2D
,
0
,
0
,
0
/* read offsets */
,
0
,
0
,
fbwidth
,
fbheight
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
);
checkGLcall
(
"glTexParameteri"
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_MIN_FILTER
,
GL_NEAREST
);
checkGLcall
(
"glTexParameteri"
);
glReadBuffer
(
GL_BACK
);
checkGLcall
(
"glReadBuffer(GL_BACK)"
);
}
checkGLcall
(
"glEnd and previous"
);
left
=
(
float
)
srect
->
x1
/
(
float
)
Src
->
pow2Width
;
right
=
(
float
)
srect
->
x2
/
(
float
)
Src
->
pow2Width
;
if
(
upsidedown
)
{
top
=
(
float
)
(
Src
->
currentDesc
.
Height
-
srect
->
y1
)
/
(
float
)
Src
->
pow2Height
;
bottom
=
(
float
)
(
Src
->
currentDesc
.
Height
-
srect
->
y2
)
/
(
float
)
Src
->
pow2Height
;
}
else
{
top
=
(
float
)
(
Src
->
currentDesc
.
Height
-
srect
->
y2
)
/
(
float
)
Src
->
pow2Height
;
bottom
=
(
float
)
(
Src
->
currentDesc
.
Height
-
srect
->
y1
)
/
(
float
)
Src
->
pow2Height
;
}
/* draw the source texture stretched and upside down. The correct surface is bound already */
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_WRAP_S
,
GL_CLAMP
);
glTexParameteri
(
GL_TEXTURE_2D
,
GL_TEXTURE_WRAP_T
,
GL_CLAMP
);
glBegin
(
GL_QUADS
);
/* bottom left */
glTexCoord2f
(
left
,
bottom
);
glVertex2i
(
0
,
fbheight
);
/* top left */
glTexCoord2f
(
left
,
top
);
glVertex2i
(
0
,
fbheight
-
drect
->
y2
-
drect
->
y1
);
/* top right */
glTexCoord2f
(
right
,
top
);
glVertex2i
(
drect
->
x2
-
drect
->
x1
,
fbheight
-
drect
->
y2
-
drect
->
y1
);
/* bottom right */
glTexCoord2f
(
right
,
bottom
);
glVertex2i
(
drect
->
x2
-
drect
->
x1
,
fbheight
);
glEnd
();
checkGLcall
(
"glEnd and previous"
);
/* Now read the stretched and upside down image into the destination texture */
glBindTexture
(
This
->
glDescription
.
target
,
This
->
glDescription
.
textureName
);
checkGLcall
(
"glBindTexture"
);
glCopyTexSubImage2D
(
This
->
glDescription
.
target
,
0
,
drect
->
x1
,
drect
->
y1
,
/* xoffset, yoffset */
0
,
0
,
/* We blitted the image to the origin */
drect
->
x2
-
drect
->
x1
,
drect
->
y2
-
drect
->
y1
);
checkGLcall
(
"glCopyTexSubImage2D"
);
/* Write the back buffer backup back */
glBindTexture
(
GL_TEXTURE_2D
,
backup
);
checkGLcall
(
"glBindTexture(GL_TEXTURE_2D, backup)"
);
glBegin
(
GL_QUADS
);
/* top left */
glTexCoord2f
(
0
.
0
,
(
float
)
fbheight
/
(
float
)
Src
->
pow2Height
);
glVertex2i
(
0
,
0
);
/* bottom left */
glTexCoord2f
(
0
.
0
,
0
.
0
);
glVertex2i
(
0
,
fbheight
);
/* bottom right */
glTexCoord2f
((
float
)
fbwidth
/
(
float
)
Src
->
pow2Width
,
0
.
0
);
glVertex2i
(
fbwidth
,
Src
->
currentDesc
.
Height
);
/* top right */
glTexCoord2f
((
float
)
fbwidth
/
(
float
)
Src
->
pow2Width
,
(
float
)
fbheight
/
(
float
)
Src
->
pow2Height
);
glVertex2i
(
fbwidth
,
0
);
glEnd
();
/* Cleanup */
if
(
src
!=
backup
)
{
glDeleteTextures
(
1
,
&
src
);
checkGLcall
(
"glDeleteTextures(1, &src)"
);
}
glDeleteTextures
(
1
,
&
backup
);
checkGLcall
(
"glDeleteTextures(1, &backup)"
);
LEAVE_GL
();
}
/* Not called from the VTable */
static
HRESULT
IWineD3DSurfaceImpl_BltOverride
(
IWineD3DSurfaceImpl
*
This
,
RECT
*
DestRect
,
IWineD3DSurface
*
SrcSurface
,
RECT
*
SrcRect
,
DWORD
Flags
,
DDBLTFX
*
DDBltFx
)
{
WINED3DRECT
rect
;
...
...
@@ -2432,73 +2666,72 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *
(
swapchain
->
backBuffer
&&
SrcSurface
==
swapchain
->
backBuffer
[
0
])
)
{
if
(
(
(
IWineD3DSurface
*
)
This
!=
swapchain
->
frontBuffer
)
&&
(
swapchain
->
backBuffer
&&
(
IWineD3DSurface
*
)
This
!=
swapchain
->
backBuffer
[
0
])
)
{
UINT
row
;
WINED3DRECT
srect
;
float
xrel
,
yrel
;
BOOL
upsideDown
,
stretchx
;
TRACE
(
"Blt from rendertarget to texture
\n
"
);
/* Call preload for the surface to make sure it isn't dirty */
IWineD3DSurface_PreLoad
((
IWineD3DSurface
*
)
This
);
/* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
* glCopyTexSubImage is a bit picky about the parameters we pass to it
*/
if
(
SrcRect
)
{
if
(
SrcRect
->
top
<
SrcRect
->
bottom
)
{
srect
.
y1
=
SrcRect
->
top
;
srect
.
y2
=
SrcRect
->
bottom
;
upsideDown
=
FALSE
;
}
else
{
srect
.
y1
=
SrcRect
->
bottom
;
srect
.
y2
=
SrcRect
->
top
;
upsideDown
=
TRUE
;
}
srect
.
x1
=
SrcRect
->
left
;
srect
.
y1
=
SrcRect
->
top
;
srect
.
x2
=
SrcRect
->
right
;
srect
.
y2
=
SrcRect
->
bottom
;
}
else
{
srect
.
x1
=
0
;
srect
.
y1
=
0
;
srect
.
x2
=
Src
->
currentDesc
.
Width
;
srect
.
y2
=
Src
->
currentDesc
.
Height
;
upsideDown
=
FALSE
;
}
if
(
rect
.
x1
>
rect
.
x2
)
{
UINT
tmp
=
rect
.
x2
;
rect
.
x2
=
rect
.
x1
;
rect
.
x1
=
tmp
;
upsideDown
=
!
upsideDown
;
}
ENTER_GL
();
/* Bind the target texture */
glBindTexture
(
GL_TEXTURE_2D
,
This
->
glDescription
.
textureName
);
checkGLcall
(
"glBindTexture"
);
if
(
swapchain
->
backBuffer
&&
SrcSurface
==
swapchain
->
backBuffer
[
0
])
{
glReadBuffer
(
GL_BACK
);
if
(
rect
.
x2
-
rect
.
x1
!=
srect
.
x2
-
srect
.
x1
)
{
stretchx
=
TRUE
;
}
else
{
glReadBuffer
(
GL_FRONT
)
;
stretchx
=
FALSE
;
}
checkGLcall
(
"glReadBuffer"
);
xrel
=
(
float
)
(
srect
.
x2
-
srect
.
x1
)
/
(
float
)
(
rect
.
x2
-
rect
.
x1
);
yrel
=
(
float
)
(
srect
.
y2
-
srect
.
y1
)
/
(
float
)
(
rect
.
y2
-
rect
.
y1
);
/*
I have to process this row by row to swap the image,
*
otherwise it would be upside down, so streching in y direction
*
doesn't cost extra time
/*
Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
*
flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
*
not implemented by now). Otherwise:
*
* However, streching in x direction can be avoided if not necessary
* -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
* -> If the app wants a image width an unscaled width, copy it line per line
* -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
* than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
* back buffer. This is slower than reading line per line, thus not used for flipping
* -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
* pixel by pixel
*/
for
(
row
=
rect
.
y1
;
row
<
rect
.
y2
;
row
++
)
{
if
(
(
xrel
-
1
.
0
<
-
eps
)
||
(
xrel
-
1
.
0
>
eps
))
{
/* Well, that stuff works, but it's very slow.
* find a better way instead
*/
UINT
col
;
for
(
col
=
rect
.
x1
;
col
<
rect
.
x2
;
col
++
)
{
glCopyTexSubImage2D
(
GL_TEXTURE_2D
,
0
,
/* level */
rect
.
x1
+
col
,
This
->
currentDesc
.
Height
-
row
-
1
,
/* xoffset, yoffset */
srect
.
x1
+
col
*
xrel
,
Src
->
currentDesc
.
Height
-
srect
.
y2
+
row
*
yrel
,
1
,
1
);
}
}
else
{
glCopyTexSubImage2D
(
GL_TEXTURE_2D
,
0
,
/* level */
rect
.
x1
,
rect
.
y2
+
rect
.
y1
-
row
-
1
,
/* xoffset, yoffset */
srect
.
x1
,
row
-
rect
.
y1
,
rect
.
x2
-
rect
.
x1
,
1
);
}
if
(
FALSE
/* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */
)
{
TRACE
(
"Using GL_EXT_framebuffer_blit for copying
\n
"
);
}
else
if
((
!
stretchx
)
||
rect
.
x2
-
rect
.
x1
>
Src
->
currentDesc
.
Width
||
rect
.
y2
-
rect
.
y1
>
Src
->
currentDesc
.
Height
)
{
TRACE
(
"No stretching in x direction, using direct framebuffer -> texture copy
\n
"
);
fb_copy_to_texture_direct
(
This
,
SrcSurface
,
swapchain
,
&
srect
,
&
rect
,
upsideDown
);
}
else
{
TRACE
(
"Using hardware stretching to flip / stretch the texture
\n
"
);
fb_copy_to_texture_hwstretch
(
This
,
SrcSurface
,
swapchain
,
&
srect
,
&
rect
,
upsideDown
);
}
vcheckGLcall
(
"glCopyTexSubImage2D"
);
LEAVE_GL
();
if
(
!
(
This
->
Flags
&
SFLAG_DONOTFREE
))
{
HeapFree
(
GetProcessHeap
(),
0
,
This
->
resource
.
allocatedMemory
);
This
->
resource
.
allocatedMemory
=
NULL
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment