Hi all,
A week or so ago I tried to get a game working in WINE (Titan Quest), however it seems it really needs a proper DIB engine before it'll be playable.
Anyways, in my attempt to get it working I fixed up some issues w/ "IWineD3DDeviceImpl_UpdateSurface.c" in dlls/wined3d, not entirely sure how you guys do things around here so I thought i'd just post my changes to the function in this mailing list and you can do with it what you want. (Note: it actually has a few different methods of doing one thing, enclosed in macro blocks to toggle between them. Technically the first one should work (i think :) once you guys properly implement surface locking/unlocking, and it's 'simplest', but the last one is the only one that actually works properly (using standard OpenGL calls).
You'll probably have to clean up the code to meet your coding standards / etc, maybe remove the custom byte size calculation of compressed images, and some other things - but the functionality is there... i also fixed the existing code that didn't actually do what it was supposed to, heh.
Regards, Mitchell Wheeler
static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; /** TODO: remove casts to IWineD3DSurfaceImpl * NOTE: move code to surface to accomplish this ****************************************/ IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface; IWineD3DSurfaceImpl *pDestSurface = (IWineD3DSurfaceImpl*)pDestinationSurface; int srcWidth, srcHeight; unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight; WINED3DFORMAT destFormat, srcFormat; int srcLeft, srcTop, destLeft, destTop; WINED3DPOOL srcPool, destPool; int offset = 0; int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */ glDescriptor *glDescription = NULL, *glSrcDescription = NULL; GLenum dummy; int bpp; UINT destByteSize = 0, srcByteSize = 0; int destPixelByteSize = 0, srcPixelByteSize = 0; CONVERT_TYPES convert = NO_CONVERSION;
WINED3DSURFACE_DESC winedesc;
TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint); memset(&winedesc, 0, sizeof(winedesc)); winedesc.Width = &srcSurfaceWidth; winedesc.Height = &srcSurfaceHeight; winedesc.Pool = &srcPool; winedesc.Format = &srcFormat; winedesc.Size = &srcByteSize;
IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
winedesc.Width = &destSurfaceWidth; winedesc.Height = &destSurfaceHeight; winedesc.Pool = &destPool; winedesc.Format = &destFormat; winedesc.Size = &destByteSize;
IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){ WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface); return WINED3DERR_INVALIDCALL; }
/* This call loads the opengl surface directly, instead of copying the surface to the * destination's sysmem copy. If surface conversion is needed, use BltFast instead to * copy in sysmem and use regular surface loading. */ d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE); if(convert != NO_CONVERSION) { return IWineD3DSurface_BltFast(pDestinationSurface, pDestPoint ? pDestPoint->x : 0, pDestPoint ? pDestPoint->y : 0, pSourceSurface, (RECT *) pSourceRect, 0); }
if (destFormat == WINED3DFMT_UNKNOWN) { TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This); IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
/* Get the update surface description */ IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc); }
ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
ENTER_GL();
if (GL_SUPPORT(ARB_MULTITEXTURE)) { GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); checkGLcall("glActiveTextureARB"); }
/* Make sure the surface is loaded and up to date */ IWineD3DSurface_PreLoad(pDestinationSurface); IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription); IWineD3DSurface_GetGlDesc(pDestinationSurface, &glSrcDescription);
/* this needs to be done in lines if the sourceRect != the sourceWidth */ srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth; srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight; srcLeft = pSourceRect ? pSourceRect->left : 0; srcTop = pSourceRect ? pSourceRect->top : 0; destLeft = pDestPoint ? pDestPoint->x : 0; destTop = pDestPoint ? pDestPoint->y : 0;
// Calculate the rowOffset / offset values, for copying #define ISDXTFORMAT(format) \ (format == WINED3DFMT_DXT1 || format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 || format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5)
// Calculating this for our selves because I don't have faith in how surface->bytesPerPixel is calculated... destPixelByteSize = destByteSize / (int)(destSurfaceWidth * destSurfaceHeight); srcPixelByteSize = srcByteSize / (int)(srcSurfaceWidth * srcSurfaceHeight);
if(pSourceRect != NULL) { // Irregular surface formats if (destFormat != srcFormat) { FIXME("Can not convert between surface pixel formats...");
// Would require some relatively big code restructuring for rare occurances (that shouldn't even be supported?)
return WINED3DERR_INVALIDCALL; } // Uniform surface formats else { if(srcWidth != srcSurfaceWidth || srcLeft > 0) { rowoffset = srcSurfaceWidth * srcPixelByteSize; offset += (srcLeft * srcPixelByteSize); }
if(srcTop > 0) offset += srcTop * srcSurfaceWidth * srcPixelByteSize; }
}
/* Sanity check */ if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
/* need to lock the surface to get the data */ FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n"); }
/* TODO: Cube and volume support */ if(rowoffset != 0) { // Compressed texture if (ISDXTFORMAT(destFormat)) { if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { #if 0 RECT rect; rect.left = destLeft; rect.top = destTop; rect.right = destLeft + srcWidth; rect.bottom = destTop + srcHeight;
// Lock source/destination regions WINED3DLOCKED_RECT destRect, srcRect;
printf("Locking surfaces...\n"); if( FAILED(IWineD3DSurface_LockRect(pDestinationSurface, &destRect, &rect, 0)) || FAILED(IWineD3DSurface_LockRect(pSourceSurface, &srcRect, pSourceRect, WINED3DLOCK_READONLY))) { // How should we handle this case? Just returning an invalid call for now... return WINED3DERR_INVALIDCALL; }
printf("Surfaces locked, copying contents now... "); if(destFormat == WINED3DFMT_DXT1) { printf("DXT1\n"); //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 2)); //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 2)); memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 8); } else { printf("DXT2-5\n"); //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 4)); memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 16); }
// Unlock source/destination regions IWineD3DSurface_UnlockRect(pSourceSurface); IWineD3DSurface_UnlockRect(pDestinationSurface); printf("Unlocking surfaces...\n"); #elif 0 // Get pointers to the source/destination buffers unsigned char *dest_data = (unsigned char*)IWineD3DSurface_GetData(pDestinationSurface); const unsigned char *src_data = (unsigned char*)IWineD3DSurface_GetData(pSourceSurface);
// Copy subsection of source buffer, in to destination buffer. unsigned char *dest_ptr = dest_data + offset; const unsigned char *src_ptr = src_data + offset;
size_t i; for(i = 0; i < srcHeight; ++i) { memcpy(dest_ptr, src_ptr, srcWidth * srcPixelByteSize);
dest_ptr += rowoffset; src_ptr += rowoffset; }
// Upload destination buffer to server GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
glDescription->glFormatInternal, srcWidth, srcHeight, 0, destByteSize, dest_data));
checkGLcall("glCompressedTexImage2DARB"); #elif 1 int blocksize = 16; if(destFormat == WINED3DFMT_DXT1) blocksize = 8;
#define max(a, b) (a > b? a : b) srcHeight = max(srcHeight, 4); srcWidth = max(srcWidth, 4); #undef max
int data_size = (srcWidth / 4) * (srcHeight / 4) * blocksize; int row_size = data_size / srcHeight; int pixel_size = row_size / srcWidth; int stride = srcSurfaceWidth * pixel_size;
unsigned char *temp_buffer = HeapAlloc(GetProcessHeap(), 0, data_size); unsigned char *temp_ptr = temp_buffer;
// Debug info //printf(" > BytesTotal: %i | BytesPerPixel: %i | RowSize: %i\n", data_size, pixel_size, row_size); //printf(" > Source: %i -> %i, %i -> %i | Dest: %i, %i\n", srcLeft, srcWidth, srcTop, srcHeight, destLeft, destTop); //printf(" > Offset: %i\n", (int)((row_size * srcTop) + srcLeft * pixel_size));
// Get pointers to the source buffer const unsigned char *src_data = (unsigned char*)IWineD3DSurface_GetData(pSourceSurface); src_data += (stride * srcTop) + srcLeft * pixel_size;
size_t i; for(i = 0; i < srcHeight; ++i) { memcpy(temp_ptr, src_data, row_size); temp_ptr += row_size; src_data += stride; }
GL_EXTCALL(glCompressedTexSubImage2DARB( glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormatInternal, data_size, temp_buffer )); //checkGLcall("glCompressedTexSubImage2DARB");
HeapFree(GetProcessHeap(), 0, temp_buffer); #endif } else { FIXME("TODO: Need to update a DXT compressed texture without hardware support\n"); } } // Uncompressed texture else { /* not a whole row so we have to do it a line at a time */ int j;
/* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */ const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
for(j = destTop; j < (srcHeight + destTop); ++j) { glTexSubImage2D(glDescription->target ,glDescription->level ,destLeft ,j ,srcWidth ,1 ,glDescription->glFormat ,glDescription->glType ,data /* could be quicker using */ ); data += rowoffset; } } } else { // Compressed texture if (ISDXTFORMAT(destFormat)) { if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { int blocksize = 16; if(destFormat == WINED3DFMT_DXT1) blocksize = 8;
#define max(a, b) (a > b? a : b) int data_size = (max(srcWidth, 4) / 4) * (max(srcHeight, 4) / 4) * blocksize; #undef max
//printf(" -> S = %i | CompressedTexImage2D(?, %i, %i, %i, %i, 0, %i, ?)\n", destByteSize, glDescription->level, glDescription->glFormatInternal, srcWidth, srcHeight, data_size);
GL_EXTCALL(glCompressedTexSubImage2DARB(glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight,
glDescription->glFormatInternal, data_size,
IWineD3DSurface_GetData(pSourceSurface)));
checkGLcall("glCompressedTexImage2DARB"); } else { FIXME("TODO: Need to update a DXT compressed texture without hardware support\n"); } } // Uncompressed Texture else { glTexSubImage2D( glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, IWineD3DSurface_GetData(pSourceSurface) );
checkGLcall("glTexSubImage2D"); } }
LEAVE_GL();
((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM; ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE; IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
return WINED3D_OK; }
Hi all,
A week or so ago I tried to get a game working in WINE (Titan Quest), however it seems it really needs a proper DIB engine before it'll be playable.
Anyways, in my attempt to get it working I fixed up some issues w/ "IWineD3DDeviceImpl_UpdateSurface.c" in dlls/wined3d, not entirely sure how you guys do things around here so I thought i'd just post my changes to the function in this mailing list and you can do with it what you want. (Note: it actually has a few different methods of doing one thing, enclosed in macro blocks to toggle between them. Technically the first one should work (i think :) once you guys properly implement surface locking/unlocking, and it's 'simplest', but the last one is the only one that actually works properly (using standard OpenGL calls).
You'll probably have to clean up the code to meet your coding standards / etc, maybe remove the custom byte size calculation of compressed images, and some other things - but the functionality is there... i also fixed the existing code that didn't actually do what it was supposed to, heh.
Regards, Mitchell Wheeler
Hi,
Could you submit a patch (the difference between the original file and your changes). That makes it easier to comment on. When it is good you need a patch file anyway as that's what added to wine's git.
Regards, Roderick Colenbrander
I tried this patch, everything works like before, can't find any regression in apps like ET: QW, Oblivion, all nvidia D3D SDK tests, 3DMarks and others. Titan Quest looks beter, but there are still some issues in menu, game is not working because of gdi32.dll functionality. I create patch for actual git.
Mirek
Mitchell Wheeler napsal(a):
Hi all,
A week or so ago I tried to get a game working in WINE (Titan Quest), however it seems it really needs a proper DIB engine before it'll be playable.
Anyways, in my attempt to get it working I fixed up some issues w/ "IWineD3DDeviceImpl_UpdateSurface.c" in dlls/wined3d, not entirely sure how you guys do things around here so I thought i'd just post my changes to the function in this mailing list and you can do with it what you want. (Note: it actually has a few different methods of doing one thing, enclosed in macro blocks to toggle between them. Technically the first one should work (i think :) once you guys properly implement surface locking/unlocking, and it's 'simplest', but the last one is the only one that actually works properly (using standard OpenGL calls).
You'll probably have to clean up the code to meet your coding standards / etc, maybe remove the custom byte size calculation of compressed images, and some other things - but the functionality is there... i also fixed the existing code that didn't actually do what it was supposed to, heh.
Regards, Mitchell Wheeler
static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; /** TODO: remove casts to IWineD3DSurfaceImpl * NOTE: move code to surface to accomplish this ****************************************/ IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface; IWineD3DSurfaceImpl *pDestSurface = (IWineD3DSurfaceImpl*)pDestinationSurface; int srcWidth, srcHeight; unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight; WINED3DFORMAT destFormat, srcFormat; int srcLeft, srcTop, destLeft, destTop; WINED3DPOOL srcPool, destPool; int offset = 0; int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */ glDescriptor *glDescription = NULL, *glSrcDescription = NULL; GLenum dummy; int bpp; UINT destByteSize = 0, srcByteSize = 0; int destPixelByteSize = 0, srcPixelByteSize = 0; CONVERT_TYPES convert = NO_CONVERSION;
WINED3DSURFACE_DESC winedesc; TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n",
This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint); memset(&winedesc, 0, sizeof(winedesc)); winedesc.Width = &srcSurfaceWidth; winedesc.Height = &srcSurfaceHeight; winedesc.Pool = &srcPool; winedesc.Format = &srcFormat; winedesc.Size = &srcByteSize;
IWineD3DSurface_GetDesc(pSourceSurface, &winedesc); winedesc.Width = &destSurfaceWidth; winedesc.Height = &destSurfaceHeight; winedesc.Pool = &destPool; winedesc.Format = &destFormat; winedesc.Size = &destByteSize; IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc); if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool !=
WINED3DPOOL_DEFAULT){ WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface); return WINED3DERR_INVALIDCALL; }
/* This call loads the opengl surface directly, instead of copying
the surface to the * destination's sysmem copy. If surface conversion is needed, use BltFast instead to * copy in sysmem and use regular surface loading. */ d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE); if(convert != NO_CONVERSION) { return IWineD3DSurface_BltFast(pDestinationSurface, pDestPoint ? pDestPoint->x : 0, pDestPoint ? pDestPoint->y : 0, pSourceSurface, (RECT *) pSourceRect, 0); }
if (destFormat == WINED3DFMT_UNKNOWN) { TRACE("(%p) : Converting destination surface from
WINED3DFMT_UNKNOWN to the source format\n", This); IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
/* Get the update surface description */ IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc); } ActivateContext(This, This->lastActiveRenderTarget,
CTXUSAGE_RESOURCELOAD);
ENTER_GL(); if (GL_SUPPORT(ARB_MULTITEXTURE)) { GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); checkGLcall("glActiveTextureARB"); } /* Make sure the surface is loaded and up to date */ IWineD3DSurface_PreLoad(pDestinationSurface); IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription); IWineD3DSurface_GetGlDesc(pDestinationSurface, &glSrcDescription); /* this needs to be done in lines if the sourceRect != the
sourceWidth */ srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth; srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight; srcLeft = pSourceRect ? pSourceRect->left : 0; srcTop = pSourceRect ? pSourceRect->top : 0; destLeft = pDestPoint ? pDestPoint->x : 0; destTop = pDestPoint ? pDestPoint->y : 0;
// Calculate the rowOffset / offset values, for copying #define ISDXTFORMAT(format) \ (format == WINED3DFMT_DXT1 || format == WINED3DFMT_DXT2 ||
format == WINED3DFMT_DXT3 || format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5)
// Calculating this for our selves because I don't have faith in how
surface->bytesPerPixel is calculated... destPixelByteSize = destByteSize / (int)(destSurfaceWidth * destSurfaceHeight); srcPixelByteSize = srcByteSize / (int)(srcSurfaceWidth * srcSurfaceHeight);
if(pSourceRect != NULL) { // Irregular surface formats if (destFormat != srcFormat) { FIXME("Can not convert between surface pixel formats..."); // Would require some relatively big code restructuring for
rare occurances (that shouldn't even be supported?)
return WINED3DERR_INVALIDCALL; } // Uniform surface formats else { if(srcWidth != srcSurfaceWidth || srcLeft > 0) { rowoffset = srcSurfaceWidth * srcPixelByteSize; offset += (srcLeft * srcPixelByteSize); } if(srcTop > 0) offset += srcTop * srcSurfaceWidth * srcPixelByteSize; } } /* Sanity check */ if (IWineD3DSurface_GetData(pSourceSurface) == NULL) { /* need to lock the surface to get the data */ FIXME("Surfaces has no allocated memory, but should be an in
memory only surface\n"); }
/* TODO: Cube and volume support */ if(rowoffset != 0) { // Compressed texture if (ISDXTFORMAT(destFormat)) { if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
#if 0 RECT rect; rect.left = destLeft; rect.top = destTop; rect.right = destLeft + srcWidth; rect.bottom = destTop + srcHeight;
// Lock source/destination regions WINED3DLOCKED_RECT destRect, srcRect; printf("Locking surfaces...\n"); if(
FAILED(IWineD3DSurface_LockRect(pDestinationSurface, &destRect, &rect, 0)) || FAILED(IWineD3DSurface_LockRect(pSourceSurface, &srcRect, pSourceRect, WINED3DLOCK_READONLY))) { // How should we handle this case? Just returning an invalid call for now... return WINED3DERR_INVALIDCALL; }
printf("Surfaces locked, copying contents now... "); if(destFormat == WINED3DFMT_DXT1) { printf("DXT1\n"); //memcpy(destRect.pBits, srcRect.pBits,
srcRect.Pitch * (srcHeight / 2)); //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 2)); memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 8); } else { printf("DXT2-5\n"); //memcpy(destRect.pBits, srcRect.pBits, srcRect.Pitch * (srcHeight / 4)); memcpy(destRect.pBits, srcRect.pBits, ceil(srcWidth/4) * ceil(srcHeight/4) * 16); }
// Unlock source/destination regions IWineD3DSurface_UnlockRect(pSourceSurface); IWineD3DSurface_UnlockRect(pDestinationSurface); printf("Unlocking surfaces...\n");
#elif 0 // Get pointers to the source/destination buffers unsigned char *dest_data = (unsigned char*)IWineD3DSurface_GetData(pDestinationSurface); const unsigned char *src_data = (unsigned char*)IWineD3DSurface_GetData(pSourceSurface);
// Copy subsection of source buffer, in to destination
buffer. unsigned char *dest_ptr = dest_data + offset; const unsigned char *src_ptr = src_data + offset;
size_t i; for(i = 0; i < srcHeight; ++i) { memcpy(dest_ptr, src_ptr, srcWidth * srcPixelByteSize); dest_ptr += rowoffset; src_ptr += rowoffset; } // Upload destination buffer to server GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
glDescription->glFormatInternal, srcWidth, srcHeight, 0, destByteSize, dest_data));
checkGLcall("glCompressedTexImage2DARB");
#elif 1 int blocksize = 16; if(destFormat == WINED3DFMT_DXT1) blocksize = 8;
#define max(a, b) (a > b? a : b) srcHeight = max(srcHeight, 4); srcWidth = max(srcWidth, 4); #undef max int data_size = (srcWidth / 4) * (srcHeight / 4) *
blocksize; int row_size = data_size / srcHeight; int pixel_size = row_size / srcWidth; int stride = srcSurfaceWidth * pixel_size;
unsigned char *temp_buffer = HeapAlloc(GetProcessHeap(),
0, data_size); unsigned char *temp_ptr = temp_buffer;
// Debug info //printf(" > BytesTotal: %i | BytesPerPixel: %i |
RowSize: %i\n", data_size, pixel_size, row_size); //printf(" > Source: %i -> %i, %i -> %i | Dest: %i, %i\n", srcLeft, srcWidth, srcTop, srcHeight, destLeft, destTop); //printf(" > Offset: %i\n", (int)((row_size * srcTop) + srcLeft * pixel_size));
// Get pointers to the source buffer const unsigned char *src_data = (unsigned
char*)IWineD3DSurface_GetData(pSourceSurface); src_data += (stride * srcTop) + srcLeft * pixel_size;
size_t i; for(i = 0; i < srcHeight; ++i) { memcpy(temp_ptr, src_data, row_size); temp_ptr += row_size; src_data += stride; } GL_EXTCALL(glCompressedTexSubImage2DARB( glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormatInternal, data_size, temp_buffer )); //checkGLcall("glCompressedTexSubImage2DARB"); HeapFree(GetProcessHeap(), 0, temp_buffer);
#endif } else { FIXME("TODO: Need to update a DXT compressed texture without hardware support\n"); } } // Uncompressed texture else { /* not a whole row so we have to do it a line at a time */ int j;
/* hopefully using pointer addtion will be quicker than
using a point + j * rowoffset */ const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
for(j = destTop; j < (srcHeight + destTop); ++j) { glTexSubImage2D(glDescription->target ,glDescription->level ,destLeft ,j ,srcWidth ,1 ,glDescription->glFormat ,glDescription->glType ,data /* could be quicker using */ ); data += rowoffset; } } } else { // Compressed texture if (ISDXTFORMAT(destFormat)) { if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { int blocksize = 16; if(destFormat == WINED3DFMT_DXT1) blocksize = 8; #define max(a, b) (a > b? a : b) int data_size = (max(srcWidth, 4) / 4) * (max(srcHeight,
/ 4) * blocksize; #undef max
//printf(" -> S = %i | CompressedTexImage2D(?, %i, %i,
%i, %i, 0, %i, ?)\n", destByteSize, glDescription->level, glDescription->glFormatInternal, srcWidth, srcHeight, data_size);
GL_EXTCALL(glCompressedTexSubImage2DARB(glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight,
glDescription->glFormatInternal, data_size,
IWineD3DSurface_GetData(pSourceSurface)));
checkGLcall("glCompressedTexImage2DARB"); } else { FIXME("TODO: Need to update a DXT compressed texture
without hardware support\n"); } } // Uncompressed Texture else { glTexSubImage2D( glDescription->target, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, IWineD3DSurface_GetData(pSourceSurface) );
checkGLcall("glTexSubImage2D"); } } LEAVE_GL(); ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM; ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE; IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0)); return WINED3D_OK;
}
I tried this patch, everything works like before, can't find any regression in apps like ET: QW, Oblivion, all nvidia D3D SDK tests, 3DMarks and others. Titan Quest looks beter, but there are still some issues in menu, game is not working because of gdi32.dll functionality. I create patch for actual git.
Mirek
There are a couple of things. First something minor use c-style comments and not c++ ones (so /* */ instead of //). Further I'm not sure if the code is correct. It looks to be doing a lot of lowlevel things (directly messing with the memory) and some of the texture upload code is duplicated. Note that in most cases the data is already in opengl, we don't have to reupload it (this is slow). I'm not sure what problems your program is having but I guess it are depth / pitch related problems. For instance the surface is storing the bpp as seen by the windows app which can be different from the real bpp if conversion is needed (that's why d3dfmt_get_conversion exists).
What sort of issues was your gaming having before these changes?
Roderick
Am Samstag, 22. September 2007 13:45:11 schrieb Roderick Colenbrander:
I tried this patch, everything works like before, can't find any regression in apps like ET: QW, Oblivion, all nvidia D3D SDK tests, 3DMarks and others. Titan Quest looks beter, but there are still some issues in menu, game is not working because of gdi32.dll functionality. I create patch for actual git.
Mirek
There are a couple of things. First something minor use c-style comments and not c++ ones (so /* */ instead of //). Further I'm not sure if the code is correct. It looks to be doing a lot of lowlevel things (directly messing with the memory) and some of the texture upload code is duplicated. Note that in most cases the data is already in opengl, we don't have to reupload it (this is slow). I'm not sure what problems your program is having but I guess it are depth / pitch related problems. For instance the surface is storing the bpp as seen by the windows app which can be different from the real bpp if conversion is needed (that's why d3dfmt_get_conversion exists).
What sort of issues was your gaming having before these changes?
I guess it implements source rectangles.
Hello Mitchell,
First of all, thank you for your effort in improving Wine. People who pick their favorite game(s) and fix bugs is exactly what we need these days :-)
You should really get used to git for submitting patches. It requires a tiny bit of learning effort in the beginning, but it pays off very soon because it makes handling patches much easier.
Anyways, in my attempt to get it working I fixed up some issues w/ "IWineD3DDeviceImpl_UpdateSurface.c" in dlls/wined3d, not entirely sure how you guys do things around here so I thought i'd just post my changes to the function in this mailing list and you can do with it what you want. (Note: it actually has a few different methods of doing one thing, enclosed in macro blocks to toggle between them. Technically the first one should work (i think :) once you guys properly implement surface locking/unlocking, and it's 'simplest', but the last one is the only one that actually works properly (using standard OpenGL calls).
I looked at the diff Mirek supplied. You should add an exact description what your modifications do because "i also fixed the existing code that didn't actually do what it was supposed to, heh" does not say much. From reading the code it seems that you implement support for the source rectangle. Your patch is mixed with formatting changes, which is not good. Formatting changes should be separate patches, if really needed.
As for the code, the memcpy codepath should not be in UpdateSurface. If a system memory copy is needed, IWineGDISurface_Blt should be called, and the support for partial rectangles of compressed surfaces added there. Otherwise, gl(Compressed)TexSubImage2D should be used for performance reasons.
As for your memcpy() codepath where you said lockrect is broken: What you are trying here will not work. You have to take the pitch into account when accessing the data returned from lockrect, the data is not in one continuous block.
Stefan Dösinger wrote:
Hello Mitchell,
First of all, thank you for your effort in improving Wine. People who pick their favorite game(s) and fix bugs is exactly what we need these days :-)
You should really get used to git for submitting patches. It requires a tiny bit of learning effort in the beginning, but it pays off very soon because it makes handling patches much easier.
Anyways, in my attempt to get it working I fixed up some issues w/ "IWineD3DDeviceImpl_UpdateSurface.c" in dlls/wined3d, not entirely sure how you guys do things around here so I thought i'd just post my changes to the function in this mailing list and you can do with it what you want. (Note: it actually has a few different methods of doing one thing, enclosed in macro blocks to toggle between them. Technically the first one should work (i think :) once you guys properly implement surface locking/unlocking, and it's 'simplest', but the last one is the only one that actually works properly (using standard OpenGL calls).
I looked at the diff Mirek supplied. You should add an exact description what your modifications do because "i also fixed the existing code that didn't actually do what it was supposed to, heh" does not say much. From reading the code it seems that you implement support for the source rectangle. Your patch is mixed with formatting changes, which is not good. Formatting changes should be separate patches, if really needed.
As for the code, the memcpy codepath should not be in UpdateSurface. If a system memory copy is needed, IWineGDISurface_Blt should be called, and the support for partial rectangles of compressed surfaces added there. Otherwise, gl(Compressed)TexSubImage2D should be used for performance reasons.
As for your memcpy() codepath where you said lockrect is broken: What you are trying here will not work. You have to take the pitch into account when accessing the data returned from lockrect, the data is not in one continuous block.
Thanks for the feedback, I didn't really expect you'd keep the first two codepaths, so all of that is understandable. (Also I could be wrong about this as it was a while ago - but I think when I tried the lock/unlock rect codepath, the destination surface never got re-uploaded to the GPU, though I didn't really understand how it was supposed to work (I've never touched DirectX before, I'm an OpenGL person myself) so could very well be mistaken)
As for the commenting/reformatting, I didn't actually intend to submit this path (it was a last minute "hmm, they could probably do with this functionality" - hence I got a little 'trigger happy' and ended up rewriting half the function despite not having to, and not making a diff, nor going down the git line). I'm very familiar with subversion, and git looks relatively similar to use - so if I do end up contributing to wine again I'll be sure to put in the extra effort.
Thanks again for the feedback, and who knows, you may see more patches from me in the future (when I find another game that doesn't work properly and a free weekend).
Cheers.