mirror of
https://github.com/wine-mirror/wine
synced 2024-07-01 07:14:31 +00:00
Compare commits
55 Commits
a4cdf6709b
...
b8b18a676d
Author | SHA1 | Date | |
---|---|---|---|
|
b8b18a676d | ||
|
1953d1e774 | ||
|
1b702aea3c | ||
|
73f2e64fd4 | ||
|
c4a162a8fe | ||
|
1543fc8d1b | ||
|
640698e432 | ||
|
66ceeed861 | ||
|
fb523ed66f | ||
|
ed819cc973 | ||
|
427e848d0d | ||
|
02ca366b5a | ||
|
af565ce846 | ||
|
bb46d4a621 | ||
|
2ac86fb8c3 | ||
|
0a83c4f287 | ||
|
2e5b4ff32a | ||
|
8934fbcdbd | ||
|
35801043df | ||
|
3ecd3ff853 | ||
|
5b126f7806 | ||
|
6d6fee9dda | ||
|
2e2a3f4539 | ||
|
53f7a59992 | ||
|
9ba05f5e5b | ||
|
4a3365daff | ||
|
1200a80d76 | ||
|
898253af36 | ||
|
d72567c626 | ||
|
e4e5d22145 | ||
|
96d294aa12 | ||
|
2c4db92151 | ||
|
1215ee0241 | ||
|
be746bee64 | ||
|
86a87b0403 | ||
|
8d4024ca7e | ||
|
f89b00c878 | ||
|
fd2861252c | ||
|
acf797f669 | ||
|
52e71f3e07 | ||
|
6cb63e996e | ||
|
299490ed7b | ||
|
a23b754f06 | ||
|
133f14415f | ||
|
f68e91966c | ||
|
9c6fb2b30c | ||
|
2c7f4181bc | ||
|
6ea77ec086 | ||
|
b639319830 | ||
|
6eefb42a41 | ||
|
68e8eaa4b7 | ||
|
43f6ba56d0 | ||
|
aa0ab31571 | ||
|
6b7834d407 | ||
|
5235686be0 |
|
@ -104,9 +104,7 @@ struct d3dx_image
|
||||||
D3DRESOURCETYPE resource_type;
|
D3DRESOURCETYPE resource_type;
|
||||||
D3DFORMAT format;
|
D3DFORMAT format;
|
||||||
|
|
||||||
uint32_t width;
|
struct volume size;
|
||||||
uint32_t height;
|
|
||||||
uint32_t depth;
|
|
||||||
uint32_t mip_levels;
|
uint32_t mip_levels;
|
||||||
|
|
||||||
BYTE *pixels;
|
BYTE *pixels;
|
||||||
|
@ -122,6 +120,12 @@ struct d3dx_image
|
||||||
D3DXIMAGE_FILEFORMAT image_file_format;
|
D3DXIMAGE_FILEFORMAT image_file_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image,
|
||||||
|
uint32_t starting_mip_level, uint32_t flags);
|
||||||
|
void d3dx_image_cleanup(struct d3dx_image *image);
|
||||||
|
HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t mip_level, struct d3dx_pixels *pixels);
|
||||||
|
void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image);
|
||||||
|
|
||||||
struct d3dx_include_from_file
|
struct d3dx_include_from_file
|
||||||
{
|
{
|
||||||
ID3DXInclude ID3DXInclude_iface;
|
ID3DXInclude ID3DXInclude_iface;
|
||||||
|
@ -168,9 +172,6 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic
|
||||||
BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *dst_size,
|
BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *dst_size,
|
||||||
const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette);
|
const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette);
|
||||||
|
|
||||||
HRESULT load_texture_from_dds(IDirect3DTexture9 *texture, const void *src_data, const PALETTEENTRY *palette,
|
|
||||||
DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info, unsigned int skip_levels,
|
|
||||||
unsigned int *loaded_miplevels);
|
|
||||||
HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const void *src_data,
|
HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const void *src_data,
|
||||||
const PALETTEENTRY *palette, DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info);
|
const PALETTEENTRY *palette, DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info);
|
||||||
HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *dst_palette,
|
HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *dst_palette,
|
||||||
|
|
|
@ -437,6 +437,20 @@ static HRESULT d3dformat_to_dds_pixel_format(struct dds_pixel_format *pixel_form
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void d3dx_get_next_mip_level_size(struct volume *size)
|
||||||
|
{
|
||||||
|
size->width = max(size->width / 2, 1);
|
||||||
|
size->height = max(size->height / 2, 1);
|
||||||
|
size->depth = max(size->depth / 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *debug_volume(const struct volume *volume)
|
||||||
|
{
|
||||||
|
if (!volume)
|
||||||
|
return "(null)";
|
||||||
|
return wine_dbg_sprintf("(%ux%ux%u)", volume->width, volume->height, volume->depth);
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT d3dx_calculate_pixels_size(D3DFORMAT format, uint32_t width, uint32_t height,
|
static HRESULT d3dx_calculate_pixels_size(D3DFORMAT format, uint32_t width, uint32_t height,
|
||||||
uint32_t *pitch, uint32_t *size)
|
uint32_t *pitch, uint32_t *size)
|
||||||
{
|
{
|
||||||
|
@ -570,63 +584,6 @@ HRESULT load_volume_from_dds(IDirect3DVolume9 *dst_volume, const PALETTEENTRY *d
|
||||||
row_pitch, slice_pitch, NULL, src_box, filter, color_key);
|
row_pitch, slice_pitch, NULL, src_box, filter, color_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT load_texture_from_dds(IDirect3DTexture9 *texture, const void *src_data, const PALETTEENTRY *palette,
|
|
||||||
DWORD filter, D3DCOLOR color_key, const D3DXIMAGE_INFO *src_info, unsigned int skip_levels,
|
|
||||||
unsigned int *loaded_miplevels)
|
|
||||||
{
|
|
||||||
HRESULT hr;
|
|
||||||
RECT src_rect;
|
|
||||||
UINT src_pitch;
|
|
||||||
UINT mip_level;
|
|
||||||
UINT mip_levels;
|
|
||||||
UINT mip_level_size;
|
|
||||||
UINT width, height;
|
|
||||||
IDirect3DSurface9 *surface;
|
|
||||||
const struct dds_header *header = src_data;
|
|
||||||
const BYTE *pixels = (BYTE *)(header + 1);
|
|
||||||
|
|
||||||
/* Loading a cube texture as a simple texture is also supported
|
|
||||||
* (only first face texture is taken). Same with volume textures. */
|
|
||||||
if ((src_info->ResourceType != D3DRTYPE_TEXTURE)
|
|
||||||
&& (src_info->ResourceType != D3DRTYPE_CUBETEXTURE)
|
|
||||||
&& (src_info->ResourceType != D3DRTYPE_VOLUMETEXTURE))
|
|
||||||
{
|
|
||||||
WARN("Trying to load a %u resource as a 2D texture, returning failure.\n", src_info->ResourceType);
|
|
||||||
return D3DXERR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
width = src_info->Width;
|
|
||||||
height = src_info->Height;
|
|
||||||
mip_levels = min(src_info->MipLevels, IDirect3DTexture9_GetLevelCount(texture));
|
|
||||||
if (src_info->ResourceType == D3DRTYPE_VOLUMETEXTURE)
|
|
||||||
mip_levels = 1;
|
|
||||||
for (mip_level = 0; mip_level < mip_levels + skip_levels; ++mip_level)
|
|
||||||
{
|
|
||||||
hr = d3dx_calculate_pixels_size(src_info->Format, width, height, &src_pitch, &mip_level_size);
|
|
||||||
if (FAILED(hr)) return hr;
|
|
||||||
|
|
||||||
if (mip_level >= skip_levels)
|
|
||||||
{
|
|
||||||
SetRect(&src_rect, 0, 0, width, height);
|
|
||||||
|
|
||||||
IDirect3DTexture9_GetSurfaceLevel(texture, mip_level - skip_levels, &surface);
|
|
||||||
hr = D3DXLoadSurfaceFromMemory(surface, palette, NULL, pixels, src_info->Format, src_pitch,
|
|
||||||
NULL, &src_rect, filter, color_key);
|
|
||||||
IDirect3DSurface9_Release(surface);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixels += mip_level_size;
|
|
||||||
width = max(1, width / 2);
|
|
||||||
height = max(1, height / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
*loaded_miplevels = mip_levels - skip_levels;
|
|
||||||
|
|
||||||
return D3D_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const void *src_data,
|
HRESULT load_cube_texture_from_dds(IDirect3DCubeTexture9 *cube_texture, const void *src_data,
|
||||||
const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info)
|
const PALETTEENTRY *palette, DWORD filter, DWORD color_key, const D3DXIMAGE_INFO *src_info)
|
||||||
{
|
{
|
||||||
|
@ -733,7 +690,7 @@ HRESULT load_volume_texture_from_dds(IDirect3DVolumeTexture9 *volume_texture, co
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src_data_size,
|
static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src_data_size,
|
||||||
struct d3dx_image *image)
|
struct d3dx_image *image, uint32_t starting_mip_level)
|
||||||
{
|
{
|
||||||
const struct dds_header *header = src_data;
|
const struct dds_header *header = src_data;
|
||||||
uint32_t expected_src_data_size;
|
uint32_t expected_src_data_size;
|
||||||
|
@ -743,9 +700,7 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src
|
||||||
return D3DXERR_INVALIDDATA;
|
return D3DXERR_INVALIDDATA;
|
||||||
|
|
||||||
TRACE("File type is DDS.\n");
|
TRACE("File type is DDS.\n");
|
||||||
image->width = header->width;
|
set_volume_struct(&image->size, header->width, header->height, 1);
|
||||||
image->height = header->height;
|
|
||||||
image->depth = 1;
|
|
||||||
image->mip_levels = header->miplevels ? header->miplevels : 1;
|
image->mip_levels = header->miplevels ? header->miplevels : 1;
|
||||||
image->format = dds_pixel_format_to_d3dformat(&header->pixel_format);
|
image->format = dds_pixel_format_to_d3dformat(&header->pixel_format);
|
||||||
|
|
||||||
|
@ -755,7 +710,7 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src
|
||||||
TRACE("Pixel format is %#x.\n", image->format);
|
TRACE("Pixel format is %#x.\n", image->format);
|
||||||
if (header->caps2 & DDS_CAPS2_VOLUME)
|
if (header->caps2 & DDS_CAPS2_VOLUME)
|
||||||
{
|
{
|
||||||
image->depth = header->depth;
|
image->size.depth = header->depth;
|
||||||
image->resource_type = D3DRTYPE_VOLUMETEXTURE;
|
image->resource_type = D3DRTYPE_VOLUMETEXTURE;
|
||||||
}
|
}
|
||||||
else if (header->caps2 & DDS_CAPS2_CUBEMAP)
|
else if (header->caps2 & DDS_CAPS2_CUBEMAP)
|
||||||
|
@ -773,8 +728,8 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src
|
||||||
else
|
else
|
||||||
image->resource_type = D3DRTYPE_TEXTURE;
|
image->resource_type = D3DRTYPE_TEXTURE;
|
||||||
|
|
||||||
expected_src_data_size = calculate_dds_file_size(image->format, image->width, image->height,
|
expected_src_data_size = calculate_dds_file_size(image->format, image->size.width, image->size.height,
|
||||||
image->depth, image->mip_levels, faces);
|
image->size.depth, image->mip_levels, faces);
|
||||||
if (src_data_size < expected_src_data_size)
|
if (src_data_size < expected_src_data_size)
|
||||||
{
|
{
|
||||||
WARN("File is too short %u, expected at least %u bytes.\n", src_data_size, expected_src_data_size);
|
WARN("File is too short %u, expected at least %u bytes.\n", src_data_size, expected_src_data_size);
|
||||||
|
@ -783,6 +738,27 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src
|
||||||
|
|
||||||
image->pixels = ((BYTE *)src_data) + sizeof(*header);
|
image->pixels = ((BYTE *)src_data) + sizeof(*header);
|
||||||
image->image_file_format = D3DXIFF_DDS;
|
image->image_file_format = D3DXIFF_DDS;
|
||||||
|
if (starting_mip_level && (image->mip_levels > 1))
|
||||||
|
{
|
||||||
|
uint32_t i, row_pitch, slice_pitch, initial_mip_levels;
|
||||||
|
const struct volume initial_size = image->size;
|
||||||
|
|
||||||
|
initial_mip_levels = image->mip_levels;
|
||||||
|
for (i = 0; i < starting_mip_level; i++)
|
||||||
|
{
|
||||||
|
d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch);
|
||||||
|
|
||||||
|
image->pixels += slice_pitch * image->size.depth;
|
||||||
|
d3dx_get_next_mip_level_size(&image->size);
|
||||||
|
if (--image->mip_levels == 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("Requested starting mip level %u, actual starting mip level is %u (of %u total in image).\n",
|
||||||
|
starting_mip_level, (initial_mip_levels - image->mip_levels), initial_mip_levels);
|
||||||
|
TRACE("Original dimensions %s, new dimensions %s.\n", debug_volume(&initial_size), debug_volume(&image->size));
|
||||||
|
}
|
||||||
|
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,18 +839,18 @@ static BOOL image_is_argb(IWICBitmapFrameDecode *frame, struct d3dx_image *image
|
||||||
&& image->image_file_format != D3DXIFF_TGA))
|
&& image->image_file_format != D3DXIFF_TGA))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
size = image->width * image->height * 4;
|
size = image->size.width * image->size.height * 4;
|
||||||
if (!(buffer = malloc(size)))
|
if (!(buffer = malloc(size)))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, image->width * 4, size, buffer)))
|
if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, image->size.width * 4, size, buffer)))
|
||||||
{
|
{
|
||||||
ERR("Failed to copy pixels, hr %#lx.\n", hr);
|
ERR("Failed to copy pixels, hr %#lx.\n", hr);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < image->width * image->height; ++i)
|
for (i = 0; i < image->size.width * image->size.height; ++i)
|
||||||
{
|
{
|
||||||
if (buffer[i * 4 + 3])
|
if (buffer[i * 4 + 3])
|
||||||
{
|
{
|
||||||
|
@ -952,7 +928,7 @@ static HRESULT d3dx_image_wic_frame_decode(struct d3dx_image *image,
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
fmt_desc = get_format_info(image->format);
|
fmt_desc = get_format_info(image->format);
|
||||||
hr = d3dx_calculate_pixels_size(image->format, image->width, image->height, &row_pitch, &slice_pitch);
|
hr = d3dx_calculate_pixels_size(image->format, image->size.width, image->size.height, &row_pitch, &slice_pitch);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
|
@ -1088,7 +1064,7 @@ static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &image->width, &image->height);
|
hr = IWICBitmapFrameDecode_GetSize(bitmap_frame, &image->size.width, &image->size.height);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
@ -1113,7 +1089,7 @@ static HRESULT d3dx_initialize_image_from_wic(const void *src_data, uint32_t src
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
image->depth = 1;
|
image->size.depth = 1;
|
||||||
image->mip_levels = 1;
|
image->mip_levels = 1;
|
||||||
image->resource_type = D3DRTYPE_TEXTURE;
|
image->resource_type = D3DRTYPE_TEXTURE;
|
||||||
|
|
||||||
|
@ -1132,48 +1108,66 @@ exit:
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size,
|
HRESULT d3dx_image_init(const void *src_data, uint32_t src_data_size, struct d3dx_image *image,
|
||||||
struct d3dx_image *image, uint32_t flags)
|
uint32_t starting_mip_level, uint32_t flags)
|
||||||
{
|
{
|
||||||
if (!src_data || !src_data_size || !image)
|
if (!src_data || !src_data_size || !image)
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
memset(image, 0, sizeof(*image));
|
memset(image, 0, sizeof(*image));
|
||||||
if ((src_data_size >= 4) && !memcmp(src_data, "DDS ", 4))
|
if ((src_data_size >= 4) && !memcmp(src_data, "DDS ", 4))
|
||||||
return d3dx_initialize_image_from_dds(src_data, src_data_size, image);
|
return d3dx_initialize_image_from_dds(src_data, src_data_size, image, starting_mip_level);
|
||||||
|
|
||||||
return d3dx_initialize_image_from_wic(src_data, src_data_size, image, flags);
|
return d3dx_initialize_image_from_wic(src_data, src_data_size, image, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void d3dx_image_cleanup(struct d3dx_image *image)
|
void d3dx_image_cleanup(struct d3dx_image *image)
|
||||||
{
|
{
|
||||||
free(image->image_buf);
|
free(image->image_buf);
|
||||||
free(image->palette);
|
free(image->palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT d3dx_image_get_pixels(struct d3dx_image *image, struct d3dx_pixels *pixels)
|
HRESULT d3dx_image_get_pixels(struct d3dx_image *image, uint32_t mip_level, struct d3dx_pixels *pixels)
|
||||||
{
|
{
|
||||||
uint32_t row_pitch, slice_pitch;
|
struct volume mip_level_size = image->size;
|
||||||
|
const BYTE *pixels_ptr = image->pixels;
|
||||||
|
uint32_t row_pitch, slice_pitch, i;
|
||||||
RECT unaligned_rect;
|
RECT unaligned_rect;
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
hr = d3dx_calculate_pixels_size(image->format, image->width, image->height, &row_pitch, &slice_pitch);
|
if (mip_level >= image->mip_levels)
|
||||||
if (FAILED(hr))
|
{
|
||||||
return hr;
|
ERR("Tried to retrieve mip level %u, but image only has %u mip levels.\n", mip_level, image->mip_levels);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
SetRect(&unaligned_rect, 0, 0, image->width, image->height);
|
slice_pitch = row_pitch = 0;
|
||||||
set_d3dx_pixels(pixels, image->pixels, row_pitch, slice_pitch, image->palette, image->width, image->height,
|
for (i = 0; i < image->mip_levels; i++)
|
||||||
image->depth, &unaligned_rect);
|
{
|
||||||
|
hr = d3dx_calculate_pixels_size(image->format, mip_level_size.width, mip_level_size.height, &row_pitch, &slice_pitch);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (i == mip_level)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pixels_ptr += slice_pitch * mip_level_size.depth;
|
||||||
|
d3dx_get_next_mip_level_size(&mip_level_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetRect(&unaligned_rect, 0, 0, mip_level_size.width, mip_level_size.height);
|
||||||
|
set_d3dx_pixels(pixels, pixels_ptr, row_pitch, slice_pitch, image->palette, mip_level_size.width,
|
||||||
|
mip_level_size.height, mip_level_size.depth, &unaligned_rect);
|
||||||
|
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image)
|
void d3dximage_info_from_d3dx_image(D3DXIMAGE_INFO *info, struct d3dx_image *image)
|
||||||
{
|
{
|
||||||
info->ImageFileFormat = image->image_file_format;
|
info->ImageFileFormat = image->image_file_format;
|
||||||
info->Width = image->width;
|
info->Width = image->size.width;
|
||||||
info->Height = image->height;
|
info->Height = image->size.height;
|
||||||
info->Depth = image->depth;
|
info->Depth = image->size.depth;
|
||||||
info->MipLevels = image->mip_levels;
|
info->MipLevels = image->mip_levels;
|
||||||
info->Format = image->format;
|
info->Format = image->format;
|
||||||
info->ResourceType = image->resource_type;
|
info->ResourceType = image->resource_type;
|
||||||
|
@ -1213,7 +1207,7 @@ HRESULT WINAPI D3DXGetImageInfoFromFileInMemory(const void *data, UINT datasize,
|
||||||
if (!info)
|
if (!info)
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
|
|
||||||
hr = d3dx_image_init(data, datasize, &image, D3DX_IMAGE_INFO_ONLY);
|
hr = d3dx_image_init(data, datasize, &image, 0, D3DX_IMAGE_INFO_ONLY);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
TRACE("Invalid or unsupported image file\n");
|
TRACE("Invalid or unsupported image file\n");
|
||||||
return D3DXERR_INVALIDDATA;
|
return D3DXERR_INVALIDDATA;
|
||||||
|
@ -1362,7 +1356,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface,
|
||||||
if (!pDestSurface || !pSrcData || !SrcDataSize)
|
if (!pDestSurface || !pSrcData || !SrcDataSize)
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
hr = d3dx_image_init(pSrcData, SrcDataSize, &image, 0);
|
hr = d3dx_image_init(pSrcData, SrcDataSize, &image, 0, 0);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return D3DXERR_INVALIDDATA;
|
return D3DXERR_INVALIDDATA;
|
||||||
|
|
||||||
|
@ -1372,7 +1366,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromFileInMemory(IDirect3DSurface9 *pDestSurface,
|
||||||
else
|
else
|
||||||
SetRect(&src_rect, 0, 0, img_info.Width, img_info.Height);
|
SetRect(&src_rect, 0, 0, img_info.Width, img_info.Height);
|
||||||
|
|
||||||
hr = d3dx_image_get_pixels(&image, &pixels);
|
hr = d3dx_image_get_pixels(&image, 0, &pixels);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "wine/test.h"
|
#include "wine/test.h"
|
||||||
#include "d3dx9tex.h"
|
#include "d3dx9tex.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
static int has_2d_dxt1, has_2d_dxt3, has_2d_dxt5, has_cube_dxt5, has_3d_dxt3;
|
static int has_2d_dxt1, has_2d_dxt3, has_2d_dxt5, has_cube_dxt5, has_3d_dxt3;
|
||||||
|
|
||||||
|
@ -127,6 +128,91 @@ static const unsigned char png_grayscale[] =
|
||||||
0x60, 0x82
|
0x60, 0x82
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4x4x4 24-bit volume dds, 3 mipmaps. Level 0 is red, level 1 is green, level 2 is
|
||||||
|
* blue.
|
||||||
|
*/
|
||||||
|
static const BYTE dds_volume_24bit_4_4_4[] =
|
||||||
|
{
|
||||||
|
0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x0f,0x10,0x82,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
|
||||||
|
0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00,
|
||||||
|
0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4x4x4 DXT3 volume dds. 3 mipmaps. Level 0 is red, level 1 is green, level 2 is
|
||||||
|
* blue.
|
||||||
|
*/
|
||||||
|
static const BYTE dds_volume_dxt3_4_4_4[] =
|
||||||
|
{
|
||||||
|
0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x8a,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x44,0x58,0x54,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00,
|
||||||
|
0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa,
|
||||||
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa,
|
||||||
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa,
|
||||||
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa,
|
||||||
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x07,0xe0,0x07,0xaa,0xaa,0xaa,0xaa,
|
||||||
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x07,0xe0,0x07,0xaa,0xaa,0xaa,0xaa,
|
||||||
|
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x00,0x1f,0x00,0xaa,0xaa,0xaa,0xaa,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 8x8 24-bit dds, 4 mipmaps. Level 0 is red, level 1 is green, level 2 is
|
||||||
|
* blue, and level 3 is black.
|
||||||
|
*/
|
||||||
|
static const BYTE dds_24bit_8_8[] =
|
||||||
|
{
|
||||||
|
0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x07,0x10,0x0a,0x00,0x08,0x00,0x00,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
|
||||||
|
0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x10,0x40,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,
|
||||||
|
0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,
|
||||||
|
0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00
|
||||||
|
};
|
||||||
|
|
||||||
#define ADMITTED_ERROR 0.0001f
|
#define ADMITTED_ERROR 0.0001f
|
||||||
|
|
||||||
static inline float relative_error(float expected, float got)
|
static inline float relative_error(float expected, float got)
|
||||||
|
@ -146,6 +232,92 @@ static inline void expect_vec4_(unsigned int line, const D3DXVECTOR4 *expected,
|
||||||
got->x, got->y, got->z, got->w);
|
got->x, got->y, got->z, got->w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define check_image_info(info, width, height, depth, mip_levels, format, resource_type, image_file_format, wine_todo) \
|
||||||
|
check_image_info_(__LINE__, info, width, height, depth, mip_levels, format, resource_type, image_file_format, \
|
||||||
|
wine_todo)
|
||||||
|
static inline void check_image_info_(uint32_t line, const D3DXIMAGE_INFO *info, uint32_t width, uint32_t height,
|
||||||
|
uint32_t depth, uint32_t mip_levels, D3DFORMAT format, D3DRESOURCETYPE resource_type,
|
||||||
|
D3DXIMAGE_FILEFORMAT image_file_format, BOOL wine_todo)
|
||||||
|
{
|
||||||
|
const D3DXIMAGE_INFO expected_info = { width, height, depth, mip_levels, format, resource_type, image_file_format };
|
||||||
|
BOOL matched;
|
||||||
|
|
||||||
|
matched = !memcmp(&expected_info, info, sizeof(*info));
|
||||||
|
todo_wine_if(wine_todo) ok_(__FILE__, line)(matched, "Got unexpected image info values.\n");
|
||||||
|
if (matched)
|
||||||
|
return;
|
||||||
|
|
||||||
|
todo_wine_if(wine_todo && info->Width != width)
|
||||||
|
ok_(__FILE__, line)(info->Width == width, "Expected width %u, got %u.\n", width, info->Width);
|
||||||
|
todo_wine_if(wine_todo && info->Height != height)
|
||||||
|
ok_(__FILE__, line)(info->Height == height, "Expected height %u, got %u.\n", height, info->Height);
|
||||||
|
todo_wine_if(wine_todo && info->Depth != depth)
|
||||||
|
ok_(__FILE__, line)(info->Depth == depth, "Expected depth %u, got %u.\n", depth, info->Depth);
|
||||||
|
todo_wine_if(wine_todo && info->MipLevels != mip_levels)
|
||||||
|
ok_(__FILE__, line)(info->MipLevels == mip_levels, "Expected mip_levels %u, got %u.\n", mip_levels,
|
||||||
|
info->MipLevels);
|
||||||
|
ok_(__FILE__, line)(info->Format == format, "Expected texture format %d, got %d.\n", format, info->Format);
|
||||||
|
ok_(__FILE__, line)(info->ResourceType == resource_type, "Expected resource_type %d, got %d.\n", resource_type,
|
||||||
|
info->ResourceType);
|
||||||
|
ok_(__FILE__, line)(info->ImageFileFormat == image_file_format, "Expected image_file_format %d, got %d.\n",
|
||||||
|
image_file_format, info->ImageFileFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define check_texture_level_desc(tex, level, format, usage, pool, multi_sample_type, multi_sample_quality, width, \
|
||||||
|
height, wine_todo) \
|
||||||
|
check_texture_level_desc_(__LINE__, tex, level, format, usage, pool, multi_sample_type, multi_sample_quality, \
|
||||||
|
width, height, wine_todo)
|
||||||
|
static inline void check_texture_level_desc_(uint32_t line, IDirect3DTexture9 *tex, uint32_t level, D3DFORMAT format,
|
||||||
|
uint32_t usage, D3DPOOL pool, D3DMULTISAMPLE_TYPE multi_sample_type,
|
||||||
|
uint32_t multi_sample_quality, uint32_t width, uint32_t height, BOOL wine_todo)
|
||||||
|
{
|
||||||
|
const D3DSURFACE_DESC expected_desc = { format, D3DRTYPE_SURFACE, usage, pool, multi_sample_type,
|
||||||
|
multi_sample_quality, width, height };
|
||||||
|
D3DSURFACE_DESC desc;
|
||||||
|
BOOL matched;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = IDirect3DTexture9_GetLevelDesc(tex, level, &desc);
|
||||||
|
todo_wine_if(wine_todo && FAILED(hr))
|
||||||
|
ok_(__FILE__, line)(hr == S_OK, "Failed to get texture level desc with hr %#lx.\n", hr);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
matched = !memcmp(&expected_desc, &desc, sizeof(desc));
|
||||||
|
todo_wine_if(wine_todo) ok_(__FILE__, line)(matched, "Got unexpected surface desc values.\n");
|
||||||
|
if (matched)
|
||||||
|
return;
|
||||||
|
|
||||||
|
todo_wine_if(wine_todo && desc.Format != format)
|
||||||
|
ok_(__FILE__, line)(desc.Format == format, "Expected surface format %d, got %d.\n", format, desc.Format);
|
||||||
|
ok_(__FILE__, line)(desc.Type == D3DRTYPE_SURFACE, "Expected D3DRTYPE_SURFACE, got %d.\n", desc.Type);
|
||||||
|
todo_wine_if(wine_todo && desc.Usage != usage)
|
||||||
|
ok_(__FILE__, line)(desc.Usage == usage, "Expected usage %u, got %lu.\n", usage, desc.Usage);
|
||||||
|
todo_wine_if(wine_todo && desc.Pool != pool)
|
||||||
|
ok_(__FILE__, line)(desc.Pool == pool, "Expected pool %d, got %d.\n", pool, desc.Pool);
|
||||||
|
todo_wine_if(wine_todo && desc.MultiSampleType != multi_sample_type)
|
||||||
|
ok_(__FILE__, line)(desc.MultiSampleType == multi_sample_type, "Expected multi sample type %d, got %d.\n",
|
||||||
|
multi_sample_type, desc.MultiSampleType);
|
||||||
|
todo_wine_if(wine_todo && desc.MultiSampleQuality != multi_sample_quality)
|
||||||
|
ok_(__FILE__, line)(desc.MultiSampleQuality == multi_sample_quality, "Expected multi sample quality %u, got %lu.\n",
|
||||||
|
multi_sample_quality, desc.MultiSampleQuality);
|
||||||
|
todo_wine_if(wine_todo && desc.Width != width)
|
||||||
|
ok_(__FILE__, line)(desc.Width == width, "Expected width %u, got %u.\n", width, desc.Width);
|
||||||
|
todo_wine_if(wine_todo && desc.Height != height)
|
||||||
|
ok_(__FILE__, line)(desc.Height == height, "Expected height %u, got %u.\n", height, desc.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define check_texture_mip_levels(tex, expected_mip_levels, wine_todo) \
|
||||||
|
check_texture_mip_levels_(__LINE__, ((IDirect3DBaseTexture9 *)tex), expected_mip_levels, wine_todo)
|
||||||
|
static inline void check_texture_mip_levels_(uint32_t line, IDirect3DBaseTexture9 *tex, uint32_t expected_mip_levels,
|
||||||
|
BOOL wine_todo)
|
||||||
|
{
|
||||||
|
uint32_t mip_levels = IDirect3DBaseTexture9_GetLevelCount(tex);
|
||||||
|
|
||||||
|
todo_wine_if(wine_todo) ok_(__FILE__, line)(mip_levels == expected_mip_levels, "Got miplevels %u, expected %u.\n",
|
||||||
|
mip_levels, expected_mip_levels);
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff)
|
static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff)
|
||||||
{
|
{
|
||||||
unsigned int diff = x > y ? x - y : y - x;
|
unsigned int diff = x > y ? x - y : y - x;
|
||||||
|
@ -161,6 +333,88 @@ static BOOL compare_color(DWORD c1, DWORD c2, BYTE max_diff)
|
||||||
&& compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff);
|
&& compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct surface_readback
|
||||||
|
{
|
||||||
|
IDirect3DSurface9 *surface;
|
||||||
|
D3DLOCKED_RECT locked_rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t get_readback_color(struct surface_readback *rb, uint32_t x, uint32_t y)
|
||||||
|
{
|
||||||
|
return rb->locked_rect.pBits
|
||||||
|
? ((uint32_t *)rb->locked_rect.pBits)[y * rb->locked_rect.Pitch / sizeof(uint32_t) + x] : 0xdeadbeef;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void release_surface_readback(struct surface_readback *rb)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
if (!rb->surface)
|
||||||
|
return;
|
||||||
|
if (rb->locked_rect.pBits && FAILED(hr = IDirect3DSurface9_UnlockRect(rb->surface)))
|
||||||
|
trace("Can't unlock the readback surface, hr %#lx.\n", hr);
|
||||||
|
IDirect3DSurface9_Release(rb->surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_texture_surface_readback(IDirect3DDevice9 *device, IDirect3DTexture9 *texture, uint32_t mip_level,
|
||||||
|
struct surface_readback *rb)
|
||||||
|
{
|
||||||
|
IDirect3DSurface9 *surface;
|
||||||
|
D3DSURFACE_DESC desc;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
memset(rb, 0, sizeof(*rb));
|
||||||
|
hr = IDirect3DTexture9_GetSurfaceLevel(texture, mip_level, &surface);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
trace("Failed to get surface for mip level %d, hr %#lx.\n", mip_level, hr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IDirect3DSurface9_GetDesc(surface, &desc);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
trace("Failed to get surface description, hr %#lx.\n", hr);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, desc.Width, desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM,
|
||||||
|
&rb->surface, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
trace("Can't create the readback surface, hr %#lx.\n", hr);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = D3DXLoadSurfaceFromSurface(rb->surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_NONE, 0);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
trace("Can't load the readback surface, hr %#lx.\n", hr);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IDirect3DSurface9_LockRect(rb->surface, &rb->locked_rect, NULL, D3DLOCK_READONLY);
|
||||||
|
if (FAILED(hr))
|
||||||
|
trace("Can't lock the readback surface, hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
IDirect3DSurface9_Release(surface);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
if (rb->surface)
|
||||||
|
IDirect3DSurface9_Release(rb->surface);
|
||||||
|
rb->surface = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define check_readback_pixel_4bpp(rb, x, y, color, todo) _check_readback_pixel_4bpp(__LINE__, rb, x, y, color, todo)
|
||||||
|
static inline void _check_readback_pixel_4bpp(uint32_t line, struct surface_readback *rb, uint32_t x,
|
||||||
|
uint32_t y, uint32_t expected_color, BOOL todo)
|
||||||
|
{
|
||||||
|
uint32_t color = get_readback_color(rb, x, y);
|
||||||
|
todo_wine_if(todo) ok_(__FILE__, line)(color == expected_color, "Got color 0x%08x, expected 0x%08x.\n", color, expected_color);
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL is_autogenmipmap_supported(IDirect3DDevice9 *device, D3DRESOURCETYPE resource_type)
|
static BOOL is_autogenmipmap_supported(IDirect3DDevice9 *device, D3DRESOURCETYPE resource_type)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -1676,6 +1930,10 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device)
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
};
|
};
|
||||||
|
static const uint32_t dds_volume_dxt3_4_4_4_expected_uncompressed[] =
|
||||||
|
{
|
||||||
|
0xffff0000, 0xff00ff00, 0xff0000ff,
|
||||||
|
};
|
||||||
IDirect3DSurface9 *surface, *uncompressed_surface;
|
IDirect3DSurface9 *surface, *uncompressed_surface;
|
||||||
IDirect3DTexture9 *texture;
|
IDirect3DTexture9 *texture;
|
||||||
D3DLOCKED_RECT lock_rect;
|
D3DLOCKED_RECT lock_rect;
|
||||||
|
@ -1900,7 +2158,7 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device)
|
||||||
type = IDirect3DTexture9_GetType(texture);
|
type = IDirect3DTexture9_GetType(texture);
|
||||||
ok(type == D3DRTYPE_TEXTURE, "IDirect3DTexture9_GetType returned %u, expected %u.\n", type, D3DRTYPE_TEXTURE);
|
ok(type == D3DRTYPE_TEXTURE, "IDirect3DTexture9_GetType returned %u, expected %u.\n", type, D3DRTYPE_TEXTURE);
|
||||||
level_count = IDirect3DBaseTexture9_GetLevelCount((IDirect3DBaseTexture9 *)texture);
|
level_count = IDirect3DBaseTexture9_GetLevelCount((IDirect3DBaseTexture9 *)texture);
|
||||||
todo_wine ok(level_count == 3, "Texture has %lu mip levels, 3 expected.\n", level_count);
|
ok(level_count == 3, "Texture has %lu mip levels, 3 expected.\n", level_count);
|
||||||
hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
|
hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
|
||||||
ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc returned %#lx, expected %#lx.\n", hr, D3D_OK);
|
ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc returned %#lx, expected %#lx.\n", hr, D3D_OK);
|
||||||
ok(desc.Width == 4, "Width is %u, expected 4.\n", desc.Width);
|
ok(desc.Width == 4, "Width is %u, expected 4.\n", desc.Width);
|
||||||
|
@ -1925,17 +2183,70 @@ static void test_D3DXCreateTextureFromFileInMemory(IDirect3DDevice9 *device)
|
||||||
ok(desc.Format == D3DFMT_A8R8G8B8, "Unexpected texture format %#x.\n", desc.Format);
|
ok(desc.Format == D3DFMT_A8R8G8B8, "Unexpected texture format %#x.\n", desc.Format);
|
||||||
skip("D3DFMT_DXT3 volume textures are not supported, skipping a test.\n");
|
skip("D3DFMT_DXT3 volume textures are not supported, skipping a test.\n");
|
||||||
}
|
}
|
||||||
/* The lower texture levels are apparently generated by filtering the level 0 surface
|
|
||||||
* I.e. following levels from the file are ignored. */
|
IDirect3DTexture9_Release(texture);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All mip levels are pulled from the texture file, even in the case of a
|
||||||
|
* volume texture file.
|
||||||
|
*/
|
||||||
|
hr = D3DXCreateTextureFromFileInMemory(device, dds_volume_dxt3_4_4_4, sizeof(dds_volume_dxt3_4_4_4), &texture);
|
||||||
|
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
check_texture_mip_levels(texture, 3, FALSE);
|
||||||
|
if (has_2d_dxt3)
|
||||||
|
{
|
||||||
|
struct surface_readback surface_rb;
|
||||||
|
uint32_t mip_level;
|
||||||
|
|
||||||
|
check_texture_level_desc(texture, 0, D3DFMT_DXT3, 0, D3DPOOL_MANAGED, 0, 0, 4, 4, FALSE);
|
||||||
|
check_texture_level_desc(texture, 1, D3DFMT_DXT3, 0, D3DPOOL_MANAGED, 0, 0, 2, 2, FALSE);
|
||||||
|
check_texture_level_desc(texture, 2, D3DFMT_DXT3, 0, D3DPOOL_MANAGED, 0, 0, 1, 1, FALSE);
|
||||||
|
for (mip_level = 0; mip_level < ARRAY_SIZE(dds_volume_dxt3_4_4_4_expected_uncompressed); ++mip_level)
|
||||||
|
{
|
||||||
|
const uint32_t expected_color = dds_volume_dxt3_4_4_4_expected_uncompressed[mip_level];
|
||||||
|
uint32_t x, y;
|
||||||
|
|
||||||
|
IDirect3DTexture9_GetLevelDesc(texture, mip_level, &desc);
|
||||||
|
get_texture_surface_readback(device, texture, mip_level, &surface_rb);
|
||||||
|
for (y = 0; y < desc.Height; ++y)
|
||||||
|
{
|
||||||
|
for (x = 0; x < desc.Width; ++x)
|
||||||
|
{
|
||||||
|
check_readback_pixel_4bpp(&surface_rb, x, y, expected_color, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_surface_readback(&surface_rb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
check_texture_level_desc(texture, 0, D3DFMT_A8R8G8B8, 0, D3DPOOL_MANAGED, 0, 0, 4, 4, FALSE);
|
||||||
|
skip("D3DFMT_DXT3 textures are not supported, skipping a test.\n");
|
||||||
|
}
|
||||||
|
|
||||||
IDirect3DTexture9_Release(texture);
|
IDirect3DTexture9_Release(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_D3DXCreateTextureFromFileInMemoryEx(IDirect3DDevice9 *device)
|
static void test_D3DXCreateTextureFromFileInMemoryEx(IDirect3DDevice9 *device)
|
||||||
{
|
{
|
||||||
|
static const uint32_t dds_24bit_8_8_expected[] =
|
||||||
|
{
|
||||||
|
0xffff0000, 0xff00ff00, 0xff0000ff, 0xff000000,
|
||||||
|
};
|
||||||
|
static const uint32_t dds_volume_24bit_4_4_4_expected[] =
|
||||||
|
{
|
||||||
|
0xffff0000, 0xff00ff00, 0xff0000ff,
|
||||||
|
};
|
||||||
|
static const uint32_t dds_volume_dxt3_4_4_4_expected_uncompressed[] =
|
||||||
|
{
|
||||||
|
0xffff0000, 0xff00ff00, 0xff0000ff,
|
||||||
|
};
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
struct surface_readback surface_rb;
|
||||||
|
uint32_t miplevels, mip_level;
|
||||||
IDirect3DTexture9 *texture;
|
IDirect3DTexture9 *texture;
|
||||||
unsigned int miplevels;
|
|
||||||
IDirect3DSurface9 *surface;
|
IDirect3DSurface9 *surface;
|
||||||
|
D3DXIMAGE_INFO img_info;
|
||||||
D3DSURFACE_DESC desc;
|
D3DSURFACE_DESC desc;
|
||||||
|
|
||||||
hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_16bit, sizeof(dds_16bit), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
|
hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_16bit, sizeof(dds_16bit), D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
|
||||||
|
@ -2056,6 +2367,154 @@ static void test_D3DXCreateTextureFromFileInMemoryEx(IDirect3DDevice9 *device)
|
||||||
ok(desc.Format == D3DFMT_L8, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_L8);
|
ok(desc.Format == D3DFMT_L8, "Returned format %u, expected %u.\n", desc.Format, D3DFMT_L8);
|
||||||
IDirect3DSurface9_Release(surface);
|
IDirect3DSurface9_Release(surface);
|
||||||
IDirect3DTexture9_Release(texture);
|
IDirect3DTexture9_Release(texture);
|
||||||
|
|
||||||
|
/* Test values returned in the D3DXIMAGE_INFO structure. */
|
||||||
|
hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_24bit, sizeof(dds_24bit), D3DX_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_SKIP_DDS_MIP_LEVELS(0, D3DX_FILTER_POINT), 0, &img_info, NULL, &texture);
|
||||||
|
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
check_texture_mip_levels(texture, 2, FALSE);
|
||||||
|
check_image_info(&img_info, 2, 2, 1, 2, D3DFMT_R8G8B8, D3DRTYPE_TEXTURE, D3DXIFF_DDS, FALSE);
|
||||||
|
check_texture_level_desc(texture, 0, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 2, 2, FALSE);
|
||||||
|
check_texture_level_desc(texture, 1, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 1, 1, FALSE);
|
||||||
|
|
||||||
|
IDirect3DTexture9_Release(texture);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The values returned in the D3DXIMAGE_INFO structure represent the mip
|
||||||
|
* level the texture data was retrieved from, i.e if we skip the first mip
|
||||||
|
* level, we will get the values of the second mip level.
|
||||||
|
*/
|
||||||
|
hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_24bit, sizeof(dds_24bit), D3DX_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_SKIP_DDS_MIP_LEVELS(1, D3DX_FILTER_POINT), 0, &img_info, NULL, &texture);
|
||||||
|
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
check_texture_mip_levels(texture, 1, FALSE);
|
||||||
|
check_image_info(&img_info, 1, 1, 1, 1, D3DFMT_R8G8B8, D3DRTYPE_TEXTURE, D3DXIFF_DDS, FALSE);
|
||||||
|
check_texture_level_desc(texture, 0, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 1, 1, FALSE);
|
||||||
|
|
||||||
|
IDirect3DTexture9_Release(texture);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request skipping 3 mip levels in a file that only has 2 mip levels. In this
|
||||||
|
* case, it stops at the final mip level.
|
||||||
|
*/
|
||||||
|
hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_24bit, sizeof(dds_24bit), D3DX_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_SKIP_DDS_MIP_LEVELS(3, D3DX_FILTER_POINT), 0, &img_info, NULL, &texture);
|
||||||
|
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
check_texture_mip_levels(texture, 1, FALSE);
|
||||||
|
check_image_info(&img_info, 1, 1, 1, 1, D3DFMT_R8G8B8, D3DRTYPE_TEXTURE, D3DXIFF_DDS, FALSE);
|
||||||
|
check_texture_level_desc(texture, 0, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 1, 1, FALSE);
|
||||||
|
|
||||||
|
IDirect3DTexture9_Release(texture);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load multiple mip levels from a file and check the resulting pixel
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
|
hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_24bit_8_8, sizeof(dds_24bit_8_8),
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, 0, &img_info, NULL, &texture);
|
||||||
|
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
check_texture_mip_levels(texture, 4, FALSE);
|
||||||
|
check_image_info(&img_info, 8, 8, 1, 4, D3DFMT_R8G8B8, D3DRTYPE_TEXTURE, D3DXIFF_DDS, FALSE);
|
||||||
|
check_texture_level_desc(texture, 0, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 8, 8, FALSE);
|
||||||
|
check_texture_level_desc(texture, 1, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 4, 4, FALSE);
|
||||||
|
check_texture_level_desc(texture, 2, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 2, 2, FALSE);
|
||||||
|
check_texture_level_desc(texture, 3, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 1, 1, FALSE);
|
||||||
|
|
||||||
|
for (mip_level = 0; mip_level < ARRAY_SIZE(dds_24bit_8_8_expected); ++mip_level)
|
||||||
|
{
|
||||||
|
const uint32_t expected_color = dds_24bit_8_8_expected[mip_level];
|
||||||
|
uint32_t x, y;
|
||||||
|
|
||||||
|
IDirect3DTexture9_GetLevelDesc(texture, mip_level, &desc);
|
||||||
|
get_texture_surface_readback(device, texture, mip_level, &surface_rb);
|
||||||
|
for (y = 0; y < desc.Height; ++y)
|
||||||
|
{
|
||||||
|
for (x = 0; x < desc.Width; ++x)
|
||||||
|
{
|
||||||
|
check_readback_pixel_4bpp(&surface_rb, x, y, expected_color, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_surface_readback(&surface_rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirect3DTexture9_Release(texture);
|
||||||
|
|
||||||
|
/* Volume DDS with mips into regular texture tests. */
|
||||||
|
hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_volume_24bit_4_4_4, sizeof(dds_volume_24bit_4_4_4),
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, 0, &img_info, NULL, &texture);
|
||||||
|
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
check_texture_mip_levels(texture, 3, FALSE);
|
||||||
|
check_image_info(&img_info, 4, 4, 4, 3, D3DFMT_R8G8B8, D3DRTYPE_VOLUMETEXTURE, D3DXIFF_DDS, FALSE);
|
||||||
|
check_texture_level_desc(texture, 0, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 4, 4, FALSE);
|
||||||
|
check_texture_level_desc(texture, 1, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 2, 2, FALSE);
|
||||||
|
check_texture_level_desc(texture, 2, D3DFMT_X8R8G8B8, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 1, 1, FALSE);
|
||||||
|
|
||||||
|
for (mip_level = 0; mip_level < ARRAY_SIZE(dds_volume_24bit_4_4_4_expected); ++mip_level)
|
||||||
|
{
|
||||||
|
const uint32_t expected_color = dds_volume_24bit_4_4_4_expected[mip_level];
|
||||||
|
uint32_t x, y;
|
||||||
|
|
||||||
|
IDirect3DTexture9_GetLevelDesc(texture, mip_level, &desc);
|
||||||
|
get_texture_surface_readback(device, texture, mip_level, &surface_rb);
|
||||||
|
for (y = 0; y < desc.Height; ++y)
|
||||||
|
{
|
||||||
|
for (x = 0; x < desc.Width; ++x)
|
||||||
|
{
|
||||||
|
check_readback_pixel_4bpp(&surface_rb, x, y, expected_color, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_surface_readback(&surface_rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirect3DTexture9_Release(texture);
|
||||||
|
|
||||||
|
/* DXT3 volume DDS with mips into a regular texture. */
|
||||||
|
if (has_2d_dxt3)
|
||||||
|
{
|
||||||
|
hr = D3DXCreateTextureFromFileInMemoryEx(device, dds_volume_dxt3_4_4_4, sizeof(dds_volume_dxt3_4_4_4),
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
|
||||||
|
D3DX_DEFAULT, D3DX_DEFAULT, 0, &img_info, NULL, &texture);
|
||||||
|
ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
check_texture_mip_levels(texture, 3, FALSE);
|
||||||
|
check_image_info(&img_info, 4, 4, 4, 3, D3DFMT_DXT3, D3DRTYPE_VOLUMETEXTURE, D3DXIFF_DDS, FALSE);
|
||||||
|
check_texture_level_desc(texture, 0, D3DFMT_DXT3, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 4, 4, FALSE);
|
||||||
|
check_texture_level_desc(texture, 1, D3DFMT_DXT3, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 2, 2, FALSE);
|
||||||
|
check_texture_level_desc(texture, 2, D3DFMT_DXT3, D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT, 0, 0, 1, 1, FALSE);
|
||||||
|
|
||||||
|
for (mip_level = 0; mip_level < ARRAY_SIZE(dds_volume_dxt3_4_4_4_expected_uncompressed); ++mip_level)
|
||||||
|
{
|
||||||
|
const uint32_t expected_color = dds_volume_dxt3_4_4_4_expected_uncompressed[mip_level];
|
||||||
|
uint32_t x, y;
|
||||||
|
|
||||||
|
IDirect3DTexture9_GetLevelDesc(texture, mip_level, &desc);
|
||||||
|
get_texture_surface_readback(device, texture, mip_level, &surface_rb);
|
||||||
|
for (y = 0; y < desc.Height; ++y)
|
||||||
|
{
|
||||||
|
for (x = 0; x < desc.Width; ++x)
|
||||||
|
{
|
||||||
|
check_readback_pixel_4bpp(&surface_rb, x, y, expected_color, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_surface_readback(&surface_rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirect3DTexture9_Release(texture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skip("D3DFMT_DXT3 textures are not supported, skipping tests.\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_D3DXCreateCubeTextureFromFileInMemory(IDirect3DDevice9 *device)
|
static void test_D3DXCreateCubeTextureFromFileInMemory(IDirect3DDevice9 *device)
|
||||||
|
|
|
@ -567,11 +567,11 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi
|
||||||
D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
|
D3DPOOL pool, DWORD filter, DWORD mipfilter, D3DCOLOR colorkey, D3DXIMAGE_INFO *srcinfo,
|
||||||
PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
|
PALETTEENTRY *palette, struct IDirect3DTexture9 **texture)
|
||||||
{
|
{
|
||||||
|
const struct pixel_format_desc *src_fmt_desc, *dst_fmt_desc;
|
||||||
BOOL dynamic_texture, format_specified = FALSE;
|
BOOL dynamic_texture, format_specified = FALSE;
|
||||||
unsigned int loaded_miplevels, skip_levels;
|
uint32_t loaded_miplevels, skip_levels, i;
|
||||||
IDirect3DSurface9 *surface;
|
IDirect3DTexture9 *staging_tex, *tex;
|
||||||
IDirect3DTexture9 **texptr;
|
struct d3dx_image image;
|
||||||
IDirect3DTexture9 *buftex;
|
|
||||||
D3DXIMAGE_INFO imginfo;
|
D3DXIMAGE_INFO imginfo;
|
||||||
D3DCAPS9 caps;
|
D3DCAPS9 caps;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -586,160 +586,134 @@ HRESULT WINAPI D3DXCreateTextureFromFileInMemoryEx(struct IDirect3DDevice9 *devi
|
||||||
if (!device || !texture || !srcdata || !srcdatasize)
|
if (!device || !texture || !srcdata || !srcdatasize)
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
hr = D3DXGetImageInfoFromFileInMemory(srcdata, srcdatasize, &imginfo);
|
staging_tex = tex = *texture = NULL;
|
||||||
|
skip_levels = mipfilter != D3DX_DEFAULT ? mipfilter >> D3DX_SKIP_DDS_MIP_LEVELS_SHIFT : 0;
|
||||||
|
hr = d3dx_image_init(srcdata, srcdatasize, &image, skip_levels, 0);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
FIXME("Unrecognized file format, returning failure.\n");
|
FIXME("Unrecognized file format, returning failure.\n");
|
||||||
*texture = NULL;
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d3dximage_info_from_d3dx_image(&imginfo, &image);
|
||||||
|
|
||||||
/* handle default values */
|
/* handle default values */
|
||||||
if (width == 0 || width == D3DX_DEFAULT_NONPOW2)
|
if (!width || width == D3DX_DEFAULT_NONPOW2 || width == D3DX_FROM_FILE || width == D3DX_DEFAULT)
|
||||||
width = imginfo.Width;
|
width = (width == D3DX_DEFAULT) ? make_pow2(imginfo.Width) : imginfo.Width;
|
||||||
|
if (!height || height == D3DX_DEFAULT_NONPOW2 || height == D3DX_FROM_FILE || height == D3DX_DEFAULT)
|
||||||
|
height = (height == D3DX_DEFAULT) ? make_pow2(imginfo.Height) : imginfo.Height;
|
||||||
|
|
||||||
if (height == 0 || height == D3DX_DEFAULT_NONPOW2)
|
format_specified = (format != D3DFMT_UNKNOWN && format != D3DX_DEFAULT);
|
||||||
height = imginfo.Height;
|
if (format == D3DFMT_FROM_FILE || format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
|
||||||
|
|
||||||
if (width == D3DX_DEFAULT)
|
|
||||||
width = make_pow2(imginfo.Width);
|
|
||||||
|
|
||||||
if (height == D3DX_DEFAULT)
|
|
||||||
height = make_pow2(imginfo.Height);
|
|
||||||
|
|
||||||
if (format == D3DFMT_UNKNOWN || format == D3DX_DEFAULT)
|
|
||||||
format = imginfo.Format;
|
format = imginfo.Format;
|
||||||
else
|
miplevels = (miplevels == D3DX_FROM_FILE) ? imginfo.MipLevels : miplevels;
|
||||||
format_specified = TRUE;
|
|
||||||
|
|
||||||
if (width == D3DX_FROM_FILE)
|
|
||||||
{
|
|
||||||
width = imginfo.Width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (height == D3DX_FROM_FILE)
|
|
||||||
{
|
|
||||||
height = imginfo.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (format == D3DFMT_FROM_FILE)
|
|
||||||
{
|
|
||||||
format = imginfo.Format;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (miplevels == D3DX_FROM_FILE)
|
|
||||||
{
|
|
||||||
miplevels = imginfo.MipLevels;
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_levels = mipfilter != D3DX_DEFAULT ? mipfilter >> D3DX_SKIP_DDS_MIP_LEVELS_SHIFT : 0;
|
|
||||||
if (skip_levels && imginfo.MipLevels > skip_levels)
|
|
||||||
{
|
|
||||||
TRACE("Skipping the first %u (of %u) levels of a DDS mipmapped texture.\n",
|
|
||||||
skip_levels, imginfo.MipLevels);
|
|
||||||
TRACE("Texture level 0 dimensions are %ux%u.\n", imginfo.Width, imginfo.Height);
|
|
||||||
width >>= skip_levels;
|
|
||||||
height >>= skip_levels;
|
|
||||||
miplevels -= skip_levels;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
skip_levels = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fix up texture creation parameters. */
|
/* Fix up texture creation parameters. */
|
||||||
hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool);
|
hr = D3DXCheckTextureRequirements(device, &width, &height, &miplevels, usage, &format, pool);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
FIXME("Couldn't find suitable texture parameters.\n");
|
FIXME("Couldn't find suitable texture parameters.\n");
|
||||||
*texture = NULL;
|
goto err;
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (colorkey && !format_specified)
|
if (colorkey && !format_specified)
|
||||||
format = get_alpha_replacement_format(format);
|
format = get_alpha_replacement_format(format);
|
||||||
|
|
||||||
if (imginfo.ResourceType == D3DRTYPE_VOLUMETEXTURE
|
|
||||||
&& D3DFMT_DXT1 <= imginfo.Format && imginfo.Format <= D3DFMT_DXT5 && miplevels > 1)
|
|
||||||
{
|
|
||||||
FIXME("Generation of mipmaps for compressed volume textures is not implemented yet.\n");
|
|
||||||
miplevels = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
|
if (FAILED(IDirect3DDevice9_GetDeviceCaps(device, &caps)))
|
||||||
return D3DERR_INVALIDCALL;
|
{
|
||||||
|
hr = D3DERR_INVALIDCALL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create the to-be-filled texture */
|
/* Create the to-be-filled texture */
|
||||||
dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC);
|
dynamic_texture = (caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) && (usage & D3DUSAGE_DYNAMIC);
|
||||||
if (pool == D3DPOOL_DEFAULT && !dynamic_texture)
|
if (pool == D3DPOOL_DEFAULT && !dynamic_texture)
|
||||||
{
|
{
|
||||||
hr = D3DXCreateTexture(device, width, height, miplevels, 0, format, D3DPOOL_SYSTEMMEM, &buftex);
|
TRACE("Creating staging texture.\n");
|
||||||
texptr = &buftex;
|
hr = D3DXCreateTexture(device, width, height, miplevels, 0, format, D3DPOOL_SYSTEMMEM, &staging_tex);
|
||||||
|
tex = staging_tex;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
|
hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, &tex);
|
||||||
texptr = texture;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
FIXME("Texture creation failed.\n");
|
FIXME("Texture creation failed.\n");
|
||||||
*texture = NULL;
|
goto err;
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("Texture created correctly. Now loading the texture data into it.\n");
|
TRACE("Texture created correctly. Now loading the texture data into it.\n");
|
||||||
if (imginfo.ImageFileFormat != D3DXIFF_DDS)
|
dst_fmt_desc = get_format_info(format);
|
||||||
|
src_fmt_desc = get_format_info(imginfo.Format);
|
||||||
|
loaded_miplevels = min(imginfo.MipLevels, IDirect3DTexture9_GetLevelCount(tex));
|
||||||
|
for (i = 0; i < loaded_miplevels; i++)
|
||||||
{
|
{
|
||||||
IDirect3DTexture9_GetSurfaceLevel(*texptr, 0, &surface);
|
struct d3dx_pixels src_pixels, dst_pixels;
|
||||||
hr = D3DXLoadSurfaceFromFileInMemory(surface, palette, NULL, srcdata, srcdatasize, NULL, filter, colorkey, NULL);
|
D3DSURFACE_DESC dst_surface_desc;
|
||||||
IDirect3DSurface9_Release(surface);
|
D3DLOCKED_RECT dst_locked_rect;
|
||||||
loaded_miplevels = min(IDirect3DTexture9_GetLevelCount(*texptr), imginfo.MipLevels);
|
RECT dst_rect;
|
||||||
}
|
|
||||||
else
|
hr = d3dx_image_get_pixels(&image, i, &src_pixels);
|
||||||
{
|
if (FAILED(hr))
|
||||||
hr = load_texture_from_dds(*texptr, srcdata, palette, filter, colorkey, &imginfo, skip_levels,
|
break;
|
||||||
&loaded_miplevels);
|
|
||||||
|
hr = IDirect3DTexture9_LockRect(tex, i, &dst_locked_rect, NULL, 0);
|
||||||
|
if (FAILED(hr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
IDirect3DTexture9_GetLevelDesc(tex, i, &dst_surface_desc);
|
||||||
|
SetRect(&dst_rect, 0, 0, dst_surface_desc.Width, dst_surface_desc.Height);
|
||||||
|
set_d3dx_pixels(&dst_pixels, dst_locked_rect.pBits, dst_locked_rect.Pitch, 0, palette,
|
||||||
|
dst_surface_desc.Width, dst_surface_desc.Height, 1, &dst_rect);
|
||||||
|
|
||||||
|
hr = d3dx_load_pixels_from_pixels(&dst_pixels, dst_fmt_desc, &src_pixels, src_fmt_desc, filter, colorkey);
|
||||||
|
IDirect3DTexture9_UnlockRect(tex, i);
|
||||||
|
if (FAILED(hr))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
FIXME("Texture loading failed.\n");
|
FIXME("Texture loading failed.\n");
|
||||||
IDirect3DTexture9_Release(*texptr);
|
goto err;
|
||||||
*texture = NULL;
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = D3DXFilterTexture((IDirect3DBaseTexture9*) *texptr, palette, loaded_miplevels - 1, mipfilter);
|
hr = D3DXFilterTexture((IDirect3DBaseTexture9 *)tex, palette, loaded_miplevels - 1, mipfilter);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
FIXME("Texture filtering failed.\n");
|
FIXME("Texture filtering failed.\n");
|
||||||
IDirect3DTexture9_Release(*texptr);
|
goto err;
|
||||||
*texture = NULL;
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move the data to the actual texture if necessary */
|
/* Move the data to the actual texture if necessary */
|
||||||
if (texptr == &buftex)
|
if (staging_tex)
|
||||||
{
|
{
|
||||||
hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
|
hr = D3DXCreateTexture(device, width, height, miplevels, usage, format, pool, texture);
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
goto err;
|
||||||
IDirect3DTexture9_Release(buftex);
|
|
||||||
*texture = NULL;
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9*)buftex, (IDirect3DBaseTexture9*)(*texture));
|
IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)staging_tex, (IDirect3DBaseTexture9 *)(*texture));
|
||||||
IDirect3DTexture9_Release(buftex);
|
IDirect3DTexture9_Release(staging_tex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*texture = tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d3dx_image_cleanup(&image);
|
||||||
if (srcinfo)
|
if (srcinfo)
|
||||||
*srcinfo = imginfo;
|
*srcinfo = imginfo;
|
||||||
|
|
||||||
return D3D_OK;
|
return hr;
|
||||||
|
|
||||||
|
err:
|
||||||
|
d3dx_image_cleanup(&image);
|
||||||
|
if (tex)
|
||||||
|
IDirect3DTexture9_Release(tex);
|
||||||
|
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT WINAPI D3DXCreateTextureFromFileInMemory(struct IDirect3DDevice9 *device,
|
HRESULT WINAPI D3DXCreateTextureFromFileInMemory(struct IDirect3DDevice9 *device,
|
||||||
|
|
|
@ -153,6 +153,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_macho);
|
||||||
|
|
||||||
#define MACHO_CPU_TYPE_X86 0x00000007
|
#define MACHO_CPU_TYPE_X86 0x00000007
|
||||||
#define MACHO_CPU_TYPE_X86_64 0x01000007
|
#define MACHO_CPU_TYPE_X86_64 0x01000007
|
||||||
|
#define MACHO_CPU_TYPE_ARM 0x0000000c
|
||||||
|
#define MACHO_CPU_TYPE_ARM64 0x0100000c
|
||||||
|
|
||||||
#define MACHO_MH_EXECUTE 0x2
|
#define MACHO_MH_EXECUTE 0x2
|
||||||
#define MACHO_MH_DYLIB 0x6
|
#define MACHO_MH_DYLIB 0x6
|
||||||
|
@ -212,6 +214,8 @@ static USHORT macho_cpu_to_machine(unsigned cpu)
|
||||||
{
|
{
|
||||||
case MACHO_CPU_TYPE_X86: return IMAGE_FILE_MACHINE_I386;
|
case MACHO_CPU_TYPE_X86: return IMAGE_FILE_MACHINE_I386;
|
||||||
case MACHO_CPU_TYPE_X86_64: return IMAGE_FILE_MACHINE_AMD64;
|
case MACHO_CPU_TYPE_X86_64: return IMAGE_FILE_MACHINE_AMD64;
|
||||||
|
case MACHO_CPU_TYPE_ARM: return IMAGE_FILE_MACHINE_ARMNT;
|
||||||
|
case MACHO_CPU_TYPE_ARM64: return IMAGE_FILE_MACHINE_ARM64;
|
||||||
default:
|
default:
|
||||||
FIXME("Untranslated Mach-O CPU %x\n", cpu);
|
FIXME("Untranslated Mach-O CPU %x\n", cpu);
|
||||||
return IMAGE_FILE_MACHINE_UNKNOWN;
|
return IMAGE_FILE_MACHINE_UNKNOWN;
|
||||||
|
|
|
@ -9297,6 +9297,9 @@ static DWORD get_sbix_formats(IDWriteFontFace4 *fontface)
|
||||||
case MS_TIFF_TAG:
|
case MS_TIFF_TAG:
|
||||||
ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
|
ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
|
||||||
break;
|
break;
|
||||||
|
case DWRITE_MAKE_OPENTYPE_TAG('f','l','i','p'):
|
||||||
|
/* ignore macOS-specific tag */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ok(0, "unexpected format, %#lx\n", GET_BE_DWORD(format));
|
ok(0, "unexpected format, %#lx\n", GET_BE_DWORD(format));
|
||||||
}
|
}
|
||||||
|
|
|
@ -797,26 +797,21 @@ static LRESULT ICCVID_DecompressQuery( ICCVID_Info *info, LPBITMAPINFO in, LPBIT
|
||||||
if( in->bmiHeader.biWidth != out->bmiHeader.biWidth )
|
if( in->bmiHeader.biWidth != out->bmiHeader.biWidth )
|
||||||
return ICERR_BADFORMAT;
|
return ICERR_BADFORMAT;
|
||||||
|
|
||||||
switch( out->bmiHeader.biBitCount )
|
switch( out->bmiHeader.biCompression )
|
||||||
{
|
{
|
||||||
case 16:
|
case BI_RGB:
|
||||||
if ( out->bmiHeader.biCompression == BI_BITFIELDS )
|
if ( out->bmiHeader.biBitCount == 16 || out->bmiHeader.biBitCount == 24 || out->bmiHeader.biBitCount == 32 )
|
||||||
{
|
return ICERR_OK;
|
||||||
if ( !ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) &&
|
|
||||||
!ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) )
|
|
||||||
{
|
|
||||||
TRACE("unsupported output bit field(s) for 16-bit colors\n");
|
|
||||||
return ICERR_BADFORMAT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 24:
|
case BI_BITFIELDS:
|
||||||
case 32:
|
if ( out->bmiHeader.biBitCount == 16 && ICCVID_CheckMask(out->bmiColors, 0x7C00, 0x03E0, 0x001F) )
|
||||||
|
return ICERR_OK;
|
||||||
|
if ( out->bmiHeader.biBitCount == 16 && ICCVID_CheckMask(out->bmiColors, 0xF800, 0x07E0, 0x001F) )
|
||||||
|
return ICERR_OK;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
TRACE("unsupported output bitcount = %d\n", out->bmiHeader.biBitCount );
|
|
||||||
return ICERR_BADFORMAT;
|
|
||||||
}
|
}
|
||||||
|
TRACE("unsupported output format\n");
|
||||||
|
return ICERR_BADFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ICERR_OK;
|
return ICERR_OK;
|
||||||
|
|
|
@ -2190,8 +2190,10 @@ static void test_debugger(const char *argv0)
|
||||||
{
|
{
|
||||||
next_event(&ctx, WAIT_EVENT_TIMEOUT);
|
next_event(&ctx, WAIT_EVENT_TIMEOUT);
|
||||||
ok (ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT, "got exception\n");
|
ok (ctx.ev.dwDebugEventCode != EXCEPTION_DEBUG_EVENT, "got exception\n");
|
||||||
|
if (ctx.ev.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) break;
|
||||||
}
|
}
|
||||||
while (ctx.ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
|
while (ctx.ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
|
||||||
|
if (ctx.ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) TerminateProcess(pi.hProcess, 0);
|
||||||
|
|
||||||
ret = CloseHandle(event);
|
ret = CloseHandle(event);
|
||||||
ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
|
ok(ret, "CloseHandle failed, last error %ld.\n", GetLastError());
|
||||||
|
|
|
@ -51,6 +51,8 @@ static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID);
|
||||||
static BOOL (WINAPI *pGetProcessDEPPolicy)(HANDLE, LPDWORD, PBOOL);
|
static BOOL (WINAPI *pGetProcessDEPPolicy)(HANDLE, LPDWORD, PBOOL);
|
||||||
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
||||||
static NTSTATUS (WINAPI *pNtProtectVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG *);
|
static NTSTATUS (WINAPI *pNtProtectVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG, ULONG *);
|
||||||
|
static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE,const void *,void *,SIZE_T, SIZE_T *);
|
||||||
|
static NTSTATUS (WINAPI *pNtWriteVirtualMemory)(HANDLE, void *, const void *, SIZE_T, SIZE_T *);
|
||||||
static BOOL (WINAPI *pPrefetchVirtualMemory)(HANDLE, ULONG_PTR, PWIN32_MEMORY_RANGE_ENTRY, ULONG);
|
static BOOL (WINAPI *pPrefetchVirtualMemory)(HANDLE, ULONG_PTR, PWIN32_MEMORY_RANGE_ENTRY, ULONG);
|
||||||
|
|
||||||
/* ############################### */
|
/* ############################### */
|
||||||
|
@ -83,6 +85,7 @@ static void test_VirtualAllocEx(void)
|
||||||
DWORD old_prot;
|
DWORD old_prot;
|
||||||
MEMORY_BASIC_INFORMATION info;
|
MEMORY_BASIC_INFORMATION info;
|
||||||
HANDLE hProcess;
|
HANDLE hProcess;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
/* Same process */
|
/* Same process */
|
||||||
addr1 = VirtualAllocEx(GetCurrentProcess(), NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
addr1 = VirtualAllocEx(GetCurrentProcess(), NULL, alloc_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
|
@ -113,6 +116,16 @@ static void test_VirtualAllocEx(void)
|
||||||
b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read);
|
b = ReadProcessMemory(hProcess, addr1, dst, alloc_size, &bytes_read);
|
||||||
ok(b && (bytes_read == alloc_size), "%Iu bytes read\n", bytes_read);
|
ok(b && (bytes_read == alloc_size), "%Iu bytes read\n", bytes_read);
|
||||||
ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n");
|
ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n");
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written );
|
||||||
|
ok( status == STATUS_SUCCESS, "wrong status %lx\n", status );
|
||||||
|
ok( bytes_written == alloc_size, "%Iu bytes written\n", bytes_written );
|
||||||
|
bytes_read = 0xdeadbeef;
|
||||||
|
memset( dst, 0, alloc_size );
|
||||||
|
status = pNtReadVirtualMemory( hProcess, addr1, dst, alloc_size, &bytes_read );
|
||||||
|
ok( status == STATUS_SUCCESS, "wrong status %lx\n", status );
|
||||||
|
ok( bytes_read == alloc_size, "%Iu bytes read\n", bytes_read );
|
||||||
|
ok(!memcmp(src, dst, alloc_size), "Data from remote process differs\n");
|
||||||
|
|
||||||
/* test 0 length */
|
/* test 0 length */
|
||||||
bytes_written = 0xdeadbeef;
|
bytes_written = 0xdeadbeef;
|
||||||
|
@ -121,43 +134,126 @@ static void test_VirtualAllocEx(void)
|
||||||
bytes_read = 0xdeadbeef;
|
bytes_read = 0xdeadbeef;
|
||||||
b = ReadProcessMemory(hProcess, addr1, src, 0, &bytes_read);
|
b = ReadProcessMemory(hProcess, addr1, src, 0, &bytes_read);
|
||||||
ok(b && !bytes_read, "read failed: %lu\n", GetLastError());
|
ok(b && !bytes_read, "read failed: %lu\n", GetLastError());
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
status = pNtWriteVirtualMemory( hProcess, addr1, src, 0, &bytes_written );
|
||||||
|
ok( status == STATUS_SUCCESS, "wrong status %lx\n", status );
|
||||||
|
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
||||||
|
bytes_read = 0xdeadbeef;
|
||||||
|
status = pNtReadVirtualMemory( hProcess, addr1, src, 0, &bytes_read );
|
||||||
|
ok( status == STATUS_SUCCESS, "wrong status %lx\n", status );
|
||||||
|
ok( !bytes_read, "%Iu bytes read\n", bytes_read );
|
||||||
|
|
||||||
/* test invalid source buffers */
|
/* test invalid source buffers */
|
||||||
|
|
||||||
b = VirtualProtect( src + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot );
|
b = VirtualProtect( src + 0x2000, 0x2000, PAGE_NOACCESS, &old_prot );
|
||||||
ok( b, "VirtualProtect failed error %lu\n", GetLastError() );
|
ok( b, "VirtualProtect failed error %lu\n", GetLastError() );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
|
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
|
||||||
ok( !b, "WriteProcessMemory succeeded\n" );
|
ok( !b, "WriteProcessMemory succeeded\n" );
|
||||||
ok( GetLastError() == ERROR_NOACCESS ||
|
ok( GetLastError() == ERROR_NOACCESS ||
|
||||||
GetLastError() == ERROR_PARTIAL_COPY, /* vista */
|
GetLastError() == ERROR_PARTIAL_COPY, /* vista */
|
||||||
"wrong error %lu\n", GetLastError() );
|
"wrong error %lu\n", GetLastError() );
|
||||||
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
||||||
|
bytes_read = 0xdeadbeef;
|
||||||
b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
|
b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
|
||||||
ok( !b, "ReadProcessMemory succeeded\n" );
|
ok( !b, "ReadProcessMemory succeeded\n" );
|
||||||
ok( GetLastError() == ERROR_NOACCESS ||
|
ok( GetLastError() == ERROR_NOACCESS ||
|
||||||
GetLastError() == ERROR_PARTIAL_COPY, /* win10 v1607+ */
|
GetLastError() == ERROR_PARTIAL_COPY, /* win10 v1607+ */
|
||||||
"wrong error %lu\n", GetLastError() );
|
"wrong error %lu\n", GetLastError() );
|
||||||
if (GetLastError() == ERROR_NOACCESS)
|
if (GetLastError() == ERROR_NOACCESS)
|
||||||
ok( bytes_read == 0, "%Iu bytes written\n", bytes_read );
|
ok( bytes_read == 0, "%Iu bytes read\n", bytes_read );
|
||||||
|
else
|
||||||
|
ok( bytes_read == 0x2000, "%Iu bytes read\n", bytes_read );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written );
|
||||||
|
ok( status == STATUS_PARTIAL_COPY, "wrong status %lx\n", status );
|
||||||
|
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
||||||
|
bytes_read = 0xdeadbeef;
|
||||||
|
status = pNtReadVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_read );
|
||||||
|
ok( status == STATUS_PARTIAL_COPY || status == STATUS_ACCESS_VIOLATION, "wrong status %lx\n", status );
|
||||||
|
ok( bytes_read == (status == STATUS_PARTIAL_COPY ? 0x2000 : 0), "%Iu bytes read\n", bytes_read );
|
||||||
|
|
||||||
b = VirtualProtect( src, 0x2000, PAGE_NOACCESS, &old_prot );
|
b = VirtualProtect( src, 0x2000, PAGE_NOACCESS, &old_prot );
|
||||||
ok( b, "VirtualProtect failed error %lu\n", GetLastError() );
|
ok( b, "VirtualProtect failed error %lu\n", GetLastError() );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
|
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
|
||||||
ok( !b, "WriteProcessMemory succeeded\n" );
|
ok( !b, "WriteProcessMemory succeeded\n" );
|
||||||
ok( GetLastError() == ERROR_NOACCESS ||
|
ok( GetLastError() == ERROR_NOACCESS ||
|
||||||
GetLastError() == ERROR_PARTIAL_COPY, /* vista */
|
GetLastError() == ERROR_PARTIAL_COPY, /* vista */
|
||||||
"wrong error %lu\n", GetLastError() );
|
"wrong error %lu\n", GetLastError() );
|
||||||
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
||||||
|
bytes_read = 0xdeadbeef;
|
||||||
b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
|
b = ReadProcessMemory(hProcess, addr1, src, alloc_size, &bytes_read);
|
||||||
ok( !b, "ReadProcessMemory succeeded\n" );
|
ok( !b, "ReadProcessMemory succeeded\n" );
|
||||||
ok( GetLastError() == ERROR_NOACCESS ||
|
ok( GetLastError() == ERROR_NOACCESS ||
|
||||||
GetLastError() == ERROR_PARTIAL_COPY, /* win10 v1607+ */
|
GetLastError() == ERROR_PARTIAL_COPY, /* win10 v1607+ */
|
||||||
"wrong error %lu\n", GetLastError() );
|
"wrong error %lu\n", GetLastError() );
|
||||||
if (GetLastError() == ERROR_NOACCESS)
|
ok( bytes_read == 0, "%Iu bytes read\n", bytes_read );
|
||||||
ok( bytes_read == 0, "%Iu bytes written\n", bytes_read );
|
bytes_written = 0xdeadbeef;
|
||||||
|
status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written );
|
||||||
|
ok( status == STATUS_PARTIAL_COPY, "wrong status %lx\n", status );
|
||||||
|
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
||||||
|
bytes_read = 0xdeadbeef;
|
||||||
|
status = pNtReadVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_read );
|
||||||
|
ok( status == STATUS_PARTIAL_COPY || status == STATUS_ACCESS_VIOLATION, "wrong status %lx\n", status );
|
||||||
|
ok( bytes_read == 0, "%Iu bytes read\n", bytes_read );
|
||||||
|
b = VirtualProtect( src, alloc_size, PAGE_READWRITE, &old_prot );
|
||||||
|
ok( b, "VirtualProtect failed error %lu\n", GetLastError() );
|
||||||
|
|
||||||
b = VirtualFreeEx(hProcess, addr1, 0, MEM_RELEASE);
|
/* test readonly buffers */
|
||||||
ok(b != 0, "VirtualFreeEx, error %lu\n", GetLastError());
|
|
||||||
|
b = VirtualProtectEx( hProcess, addr1, alloc_size, PAGE_READONLY, &old_prot );
|
||||||
|
ok( b, "VirtualProtectEx, error %lu\n", GetLastError() );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
|
||||||
|
ok( !b, "WriteProcessMemory succeeded\n" );
|
||||||
|
if (!b) ok( GetLastError() == ERROR_NOACCESS, "wrong error %lu\n", GetLastError() );
|
||||||
|
ok( bytes_written == 0xdeadbeef, "%Iu bytes written\n", bytes_written );
|
||||||
|
status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written );
|
||||||
|
todo_wine
|
||||||
|
ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_ACCESS_VIOLATION),
|
||||||
|
"wrong status %lx\n", status );
|
||||||
|
todo_wine
|
||||||
|
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
||||||
|
|
||||||
|
b = VirtualProtectEx( hProcess, addr1, alloc_size, PAGE_EXECUTE_READ, &old_prot );
|
||||||
|
ok( b, "VirtualProtectEx, error %lu\n", GetLastError() );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
|
||||||
|
ok( b, "WriteProcessMemory failed\n" );
|
||||||
|
ok( bytes_written == alloc_size, "%Iu bytes written\n", bytes_written );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written );
|
||||||
|
todo_wine
|
||||||
|
ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_ACCESS_VIOLATION),
|
||||||
|
"wrong status %lx\n", status );
|
||||||
|
todo_wine
|
||||||
|
ok( bytes_written == 0, "%Iu bytes written\n", bytes_written );
|
||||||
|
|
||||||
|
b = VirtualProtectEx( hProcess, addr1, 0x2000, PAGE_EXECUTE_READWRITE, &old_prot );
|
||||||
|
ok( b, "VirtualProtectEx, error %lu\n", GetLastError() );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
|
||||||
|
todo_wine
|
||||||
|
ok( !b || broken(b), /* <= win10 1507 */ "WriteProcessMemory succeeded\n" );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written );
|
||||||
|
todo_wine
|
||||||
|
ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_SUCCESS), /* <= win10 1507 */
|
||||||
|
"wrong status %lx\n", status );
|
||||||
|
ok( bytes_written == (status ? 0x2000 : alloc_size), "%Iu bytes written\n", bytes_written );
|
||||||
|
|
||||||
|
b = VirtualProtectEx( hProcess, (char *)addr1 + 0x2000, alloc_size - 0x2000, PAGE_READONLY, &old_prot );
|
||||||
|
ok( b, "VirtualProtectEx, error %lu\n", GetLastError() );
|
||||||
|
bytes_written = 0xdeadbeef;
|
||||||
|
b = WriteProcessMemory(hProcess, addr1, src, alloc_size, &bytes_written);
|
||||||
|
todo_wine
|
||||||
|
ok( !b || broken(b), /* <= win10 1507 */ "WriteProcessMemory succeeded\n" );
|
||||||
|
status = pNtWriteVirtualMemory( hProcess, addr1, src, alloc_size, &bytes_written );
|
||||||
|
todo_wine
|
||||||
|
ok( status == STATUS_PARTIAL_COPY || broken(status == STATUS_SUCCESS), /* <= win10 1507 */
|
||||||
|
"wrong status %lx\n", status );
|
||||||
|
ok( bytes_written == (status ? 0x2000 : alloc_size), "%Iu bytes written\n", bytes_written );
|
||||||
|
|
||||||
VirtualFree( src, 0, MEM_RELEASE );
|
VirtualFree( src, 0, MEM_RELEASE );
|
||||||
VirtualFree( dst, 0, MEM_RELEASE );
|
VirtualFree( dst, 0, MEM_RELEASE );
|
||||||
|
@ -4324,6 +4420,8 @@ START_TEST(virtual)
|
||||||
pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" );
|
pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlAddVectoredExceptionHandler" );
|
||||||
pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" );
|
pRtlRemoveVectoredExceptionHandler = (void *)GetProcAddress( hntdll, "RtlRemoveVectoredExceptionHandler" );
|
||||||
pNtProtectVirtualMemory = (void *)GetProcAddress( hntdll, "NtProtectVirtualMemory" );
|
pNtProtectVirtualMemory = (void *)GetProcAddress( hntdll, "NtProtectVirtualMemory" );
|
||||||
|
pNtReadVirtualMemory = (void *)GetProcAddress( hntdll, "NtReadVirtualMemory" );
|
||||||
|
pNtWriteVirtualMemory = (void *)GetProcAddress( hntdll, "NtWriteVirtualMemory" );
|
||||||
pPrefetchVirtualMemory = (void *)GetProcAddress( hkernelbase, "PrefetchVirtualMemory" );
|
pPrefetchVirtualMemory = (void *)GetProcAddress( hkernelbase, "PrefetchVirtualMemory" );
|
||||||
|
|
||||||
GetSystemInfo(&si);
|
GetSystemInfo(&si);
|
||||||
|
|
|
@ -42,10 +42,60 @@ WINE_DECLARE_DEBUG_CHANNEL(virtual);
|
||||||
WINE_DECLARE_DEBUG_CHANNEL(globalmem);
|
WINE_DECLARE_DEBUG_CHANNEL(globalmem);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static CROSS_PROCESS_WORK_LIST *open_cross_process_connection( HANDLE process )
|
||||||
|
{
|
||||||
|
#ifdef __aarch64__
|
||||||
|
CROSS_PROCESS_WORK_LIST *list;
|
||||||
|
HANDLE section;
|
||||||
|
|
||||||
|
RtlOpenCrossProcessEmulatorWorkConnection( process, §ion, (void **)&list );
|
||||||
|
if (section) NtClose( section );
|
||||||
|
return list;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void close_cross_process_connection( CROSS_PROCESS_WORK_LIST *list )
|
||||||
|
{
|
||||||
|
if (list) NtUnmapViewOfSection( GetCurrentProcess(), list );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_cross_process_notification( CROSS_PROCESS_WORK_LIST *list, UINT id,
|
||||||
|
const void *addr, SIZE_T size, int nb_args, ... )
|
||||||
|
{
|
||||||
|
#ifdef __aarch64__
|
||||||
|
CROSS_PROCESS_WORK_ENTRY *entry;
|
||||||
|
void *unused;
|
||||||
|
va_list args;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!list) return;
|
||||||
|
if ((entry = RtlWow64PopCrossProcessWorkFromFreeList( &list->free_list )))
|
||||||
|
{
|
||||||
|
entry->id = id;
|
||||||
|
entry->addr = (ULONG_PTR)addr;
|
||||||
|
entry->size = size;
|
||||||
|
if (nb_args)
|
||||||
|
{
|
||||||
|
va_start( args, nb_args );
|
||||||
|
for (i = 0; i < nb_args; i++) entry->args[i] = va_arg( args, int );
|
||||||
|
va_end( args );
|
||||||
|
}
|
||||||
|
RtlWow64PushCrossProcessWorkOntoWorkList( &list->work_list, entry, &unused );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Virtual memory functions
|
* Virtual memory functions
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
|
static const SIZE_T page_mask = 0xfff;
|
||||||
|
#define ROUND_ADDR(addr) ((void *)((UINT_PTR)(addr) & ~page_mask))
|
||||||
|
#define ROUND_SIZE(addr,size) (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* DiscardVirtualMemory (kernelbase.@)
|
* DiscardVirtualMemory (kernelbase.@)
|
||||||
|
@ -72,6 +122,22 @@ BOOL WINAPI DECLSPEC_HOTPATCH FlushViewOfFile( const void *base, SIZE_T size )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* FlushInstructionCache (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI DECLSPEC_HOTPATCH FlushInstructionCache( HANDLE process, LPCVOID addr, SIZE_T size )
|
||||||
|
{
|
||||||
|
CROSS_PROCESS_WORK_LIST *list;
|
||||||
|
|
||||||
|
if ((list = open_cross_process_connection( process )))
|
||||||
|
{
|
||||||
|
send_cross_process_notification( list, CrossProcessFlushCache, addr, size, 0 );
|
||||||
|
close_cross_process_connection( list );
|
||||||
|
}
|
||||||
|
return set_ntstatus( NtFlushInstructionCache( process, addr, size ));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* GetLargePageMinimum (kernelbase.@)
|
* GetLargePageMinimum (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
@ -537,7 +603,69 @@ BOOL WINAPI DECLSPEC_HOTPATCH VirtualUnlock( void *addr, SIZE_T size )
|
||||||
BOOL WINAPI DECLSPEC_HOTPATCH WriteProcessMemory( HANDLE process, void *addr, const void *buffer,
|
BOOL WINAPI DECLSPEC_HOTPATCH WriteProcessMemory( HANDLE process, void *addr, const void *buffer,
|
||||||
SIZE_T size, SIZE_T *bytes_written )
|
SIZE_T size, SIZE_T *bytes_written )
|
||||||
{
|
{
|
||||||
return set_ntstatus( NtWriteVirtualMemory( process, addr, buffer, size, bytes_written ));
|
CROSS_PROCESS_WORK_LIST *list = open_cross_process_connection( process );
|
||||||
|
DWORD old_prot, prot = PAGE_TARGETS_NO_UPDATE | PAGE_ENCLAVE_NO_CHANGE;
|
||||||
|
MEMORY_BASIC_INFORMATION info;
|
||||||
|
void *base_addr;
|
||||||
|
SIZE_T region_size;
|
||||||
|
NTSTATUS status, status2;
|
||||||
|
|
||||||
|
if (!VirtualQueryEx( process, addr, &info, sizeof(info) ))
|
||||||
|
{
|
||||||
|
close_cross_process_connection( list );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (info.Protect)
|
||||||
|
{
|
||||||
|
case PAGE_READWRITE:
|
||||||
|
case PAGE_WRITECOPY:
|
||||||
|
case PAGE_EXECUTE_READWRITE:
|
||||||
|
case PAGE_EXECUTE_WRITECOPY:
|
||||||
|
/* already writable */
|
||||||
|
if ((status = NtWriteVirtualMemory( process, addr, buffer, size, bytes_written ))) break;
|
||||||
|
send_cross_process_notification( list, CrossProcessFlushCache, addr, size, 0 );
|
||||||
|
NtFlushInstructionCache( process, addr, size );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PAGE_EXECUTE:
|
||||||
|
case PAGE_EXECUTE_READ:
|
||||||
|
/* make it writable */
|
||||||
|
base_addr = ROUND_ADDR( addr );
|
||||||
|
region_size = ROUND_SIZE( addr, size );
|
||||||
|
region_size = min( region_size, (char *)info.BaseAddress + info.RegionSize - (char *)base_addr );
|
||||||
|
prot |= (info.Type == MEM_PRIVATE) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_WRITECOPY;
|
||||||
|
|
||||||
|
send_cross_process_notification( list, CrossProcessPreVirtualProtect,
|
||||||
|
base_addr, region_size, 1, prot );
|
||||||
|
status = NtProtectVirtualMemory( process, &base_addr, ®ion_size, prot, &old_prot );
|
||||||
|
send_cross_process_notification( list, CrossProcessPostVirtualProtect,
|
||||||
|
base_addr, region_size, 2, prot, status );
|
||||||
|
if (status) break;
|
||||||
|
|
||||||
|
status = NtWriteVirtualMemory( process, addr, buffer, size, bytes_written );
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
send_cross_process_notification( list, CrossProcessFlushCache, addr, size, 0 );
|
||||||
|
NtFlushInstructionCache( process, addr, size );
|
||||||
|
}
|
||||||
|
|
||||||
|
prot = PAGE_TARGETS_NO_UPDATE | PAGE_ENCLAVE_NO_CHANGE | old_prot;
|
||||||
|
send_cross_process_notification( list, CrossProcessPreVirtualProtect,
|
||||||
|
base_addr, region_size, 1, prot );
|
||||||
|
status2 = NtProtectVirtualMemory( process, &base_addr, ®ion_size, prot, &old_prot );
|
||||||
|
send_cross_process_notification( list, CrossProcessPostVirtualProtect,
|
||||||
|
base_addr, region_size, 2, prot, status2 );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* not writable */
|
||||||
|
status = STATUS_ACCESS_VIOLATION;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
close_cross_process_connection( list );
|
||||||
|
return set_ntstatus( status );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -737,15 +737,6 @@ BOOL WINAPI DECLSPEC_HOTPATCH DuplicateHandle( HANDLE source_process, HANDLE sou
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* FlushInstructionCache (kernelbase.@)
|
|
||||||
*/
|
|
||||||
BOOL WINAPI DECLSPEC_HOTPATCH FlushInstructionCache( HANDLE process, LPCVOID addr, SIZE_T size )
|
|
||||||
{
|
|
||||||
return set_ntstatus( NtFlushInstructionCache( process, addr, size ));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* GetApplicationRestartSettings (kernelbase.@)
|
* GetApplicationRestartSettings (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1274,6 +1274,7 @@ static void session_close(struct media_session *session)
|
||||||
switch (session->state)
|
switch (session->state)
|
||||||
{
|
{
|
||||||
case SESSION_STATE_STOPPED:
|
case SESSION_STATE_STOPPED:
|
||||||
|
case SESSION_STATE_RESTARTING_SOURCES:
|
||||||
hr = session_finalize_sinks(session);
|
hr = session_finalize_sinks(session);
|
||||||
break;
|
break;
|
||||||
case SESSION_STATE_STARTED:
|
case SESSION_STATE_STARTED:
|
||||||
|
@ -3192,8 +3193,15 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION || FAILED(hr))
|
if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION)
|
||||||
session_set_stopped(session, hr);
|
session_set_stopped(session, hr);
|
||||||
|
else if (FAILED(hr))
|
||||||
|
{
|
||||||
|
if (session->presentation.flags & SESSION_FLAG_FINALIZE_SINKS)
|
||||||
|
session_set_closed(session, hr);
|
||||||
|
else
|
||||||
|
session_set_stopped(session, hr);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -6249,6 +6249,8 @@ static void test_media_session_Start(void)
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
hr = IMFMediaSession_Close(session);
|
hr = IMFMediaSession_Close(session);
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
/* Media session is shut down */
|
/* Media session is shut down */
|
||||||
hr = IMFMediaSource_Shutdown(source);
|
hr = IMFMediaSource_Shutdown(source);
|
||||||
|
@ -6331,6 +6333,8 @@ static void test_media_session_Start(void)
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
hr = IMFMediaSession_Close(session);
|
hr = IMFMediaSession_Close(session);
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
hr = IMFMediaSession_Shutdown(session);
|
hr = IMFMediaSession_Shutdown(session);
|
||||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
hr = IMFMediaSource_Shutdown(source);
|
hr = IMFMediaSource_Shutdown(source);
|
||||||
|
@ -6534,6 +6538,88 @@ static void test_MFEnumDeviceSources(void)
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_media_session_Close(void)
|
||||||
|
{
|
||||||
|
media_type_desc video_rgb32_desc =
|
||||||
|
{
|
||||||
|
ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video),
|
||||||
|
ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
|
||||||
|
};
|
||||||
|
struct test_grabber_callback *grabber_callback;
|
||||||
|
IMFPresentationClock *presentation_clock;
|
||||||
|
IMFActivate *sink_activate;
|
||||||
|
IMFAsyncCallback *callback;
|
||||||
|
IMFMediaType *output_type;
|
||||||
|
IMFMediaSession *session;
|
||||||
|
IMFMediaSource *source;
|
||||||
|
IMFTopology *topology;
|
||||||
|
PROPVARIANT propvar;
|
||||||
|
IMFClock *clock;
|
||||||
|
UINT64 duration;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
||||||
|
ok(hr == S_OK, "Failed to start up, hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
if (!(source = create_media_source(L"test.mp4", L"video/mp4")))
|
||||||
|
{
|
||||||
|
todo_wine /* Gitlab CI Debian runner */
|
||||||
|
win_skip("MP4 media source is not supported, skipping tests.\n");
|
||||||
|
MFShutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grabber_callback = impl_from_IMFSampleGrabberSinkCallback(create_test_grabber_callback());
|
||||||
|
hr = MFCreateMediaType(&output_type);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
init_media_type(output_type, video_rgb32_desc, -1);
|
||||||
|
hr = MFCreateSampleGrabberSinkActivate(output_type, &grabber_callback->IMFSampleGrabberSinkCallback_iface, &sink_activate);
|
||||||
|
ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr);
|
||||||
|
IMFMediaType_Release(output_type);
|
||||||
|
|
||||||
|
hr = MFCreateMediaSession(NULL, &session);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
topology = create_test_topology(source, sink_activate, &duration);
|
||||||
|
hr = IMFMediaSession_SetTopology(session, 0, topology);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
IMFTopology_Release(topology);
|
||||||
|
|
||||||
|
hr = IMFMediaSession_GetClock(session, &clock);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&presentation_clock);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
IMFClock_Release(clock);
|
||||||
|
|
||||||
|
propvar.vt = VT_EMPTY;
|
||||||
|
hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
callback = create_test_callback(TRUE);
|
||||||
|
hr = wait_media_event(session, callback, MESessionStarted, 5000, &propvar);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaSession_Close(session);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
hr = IMFMediaSource_Shutdown(source);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
hr = wait_media_event_until_blocking(session, callback, MESessionClosed, 5000, &propvar);
|
||||||
|
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
hr = IMFMediaSession_Shutdown(session);
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
IMFPresentationClock_Release(presentation_clock);
|
||||||
|
IMFAsyncCallback_Release(callback);
|
||||||
|
IMFMediaSession_Release(session);
|
||||||
|
IMFActivate_ShutdownObject(sink_activate);
|
||||||
|
IMFActivate_Release(sink_activate);
|
||||||
|
IMFSampleGrabberSinkCallback_Release(&grabber_callback->IMFSampleGrabberSinkCallback_iface);
|
||||||
|
IMFMediaSource_Release(source);
|
||||||
|
|
||||||
|
hr = MFShutdown();
|
||||||
|
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(mf)
|
START_TEST(mf)
|
||||||
{
|
{
|
||||||
init_functions();
|
init_functions();
|
||||||
|
@ -6568,4 +6654,5 @@ START_TEST(mf)
|
||||||
test_MFCreateSequencerSegmentOffset();
|
test_MFCreateSequencerSegmentOffset();
|
||||||
test_media_session_Start();
|
test_media_session_Start();
|
||||||
test_MFEnumDeviceSources();
|
test_MFEnumDeviceSources();
|
||||||
|
test_media_session_Close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3585,6 +3585,8 @@ static void test_wma_decoder_dmo_output_type(void)
|
||||||
good_output_type = (void *)buffer_good_output;
|
good_output_type = (void *)buffer_good_output;
|
||||||
bad_output_type = (void *)buffer_bad_output;
|
bad_output_type = (void *)buffer_bad_output;
|
||||||
init_dmo_media_type_audio(input_type, input_subtype, channel_count, rate, 16);
|
init_dmo_media_type_audio(input_type, input_subtype, channel_count, rate, 16);
|
||||||
|
((WAVEFORMATEX *)(input_type + 1))->nBlockAlign = 640;
|
||||||
|
((WAVEFORMATEX *)(input_type + 1))->nAvgBytesPerSec = 2000;
|
||||||
init_dmo_media_type_audio(good_output_type, &MEDIASUBTYPE_PCM, channel_count, rate, bits_per_sample);
|
init_dmo_media_type_audio(good_output_type, &MEDIASUBTYPE_PCM, channel_count, rate, bits_per_sample);
|
||||||
memset(bad_output_type, 0, sizeof(buffer_bad_output));
|
memset(bad_output_type, 0, sizeof(buffer_bad_output));
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ static HRESULT load_typelib(void)
|
||||||
if(typelib)
|
if(typelib)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
hres = LoadRegTypeLib(&LIBID_ADODB, 1, 0, LOCALE_SYSTEM_DEFAULT, &tl);
|
hres = LoadRegTypeLib(&LIBID_ADODB, 2, 8, LOCALE_SYSTEM_DEFAULT, &tl);
|
||||||
if(FAILED(hres)) {
|
if(FAILED(hres)) {
|
||||||
ERR("LoadRegTypeLib failed: %08lx\n", hres);
|
ERR("LoadRegTypeLib failed: %08lx\n", hres);
|
||||||
return hres;
|
return hres;
|
||||||
|
|
|
@ -190,6 +190,13 @@ static void test_Locate(void)
|
||||||
if (h) ok(ICClose(h) == ICERR_OK,"ICClose failed\n");
|
if (h) ok(ICClose(h) == ICERR_OK,"ICClose failed\n");
|
||||||
bo.biHeight = - bo.biHeight;
|
bo.biHeight = - bo.biHeight;
|
||||||
|
|
||||||
|
bo.biCompression = mmioFOURCC('U','Y','V','Y');
|
||||||
|
bo.biBitCount = bi.biBitCount = 16;
|
||||||
|
h = ICLocate(ICTYPE_VIDEO, 0, &bi, &bo, ICMODE_DECOMPRESS);
|
||||||
|
ok(h == 0, "cvid->UYVY succeeded\n");
|
||||||
|
if (h) ok(ICClose(h) == ICERR_OK,"ICClose failed\n");
|
||||||
|
bo.biCompression = BI_RGB;
|
||||||
|
|
||||||
bo.biBitCount = bi.biBitCount = 32;
|
bo.biBitCount = bi.biBitCount = 32;
|
||||||
h = ICLocate(ICTYPE_VIDEO, 0, &bi, &bo, ICMODE_DECOMPRESS);
|
h = ICLocate(ICTYPE_VIDEO, 0, &bi, &bo, ICMODE_DECOMPRESS);
|
||||||
ok(h != 0, "cvid->RGB32 failed\n");
|
ok(h != 0, "cvid->RGB32 failed\n");
|
||||||
|
|
|
@ -712,16 +712,6 @@ NTSTATUS WINAPI DbgUiIssueRemoteBreakin( HANDLE process )
|
||||||
|
|
||||||
status = NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, &attr, process,
|
status = NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, &attr, process,
|
||||||
DbgUiRemoteBreakin, NULL, 0, 0, 0, 0, NULL );
|
DbgUiRemoteBreakin, NULL, 0, 0, 0, 0, NULL );
|
||||||
#ifdef _WIN64
|
|
||||||
/* FIXME: hack for debugging 32-bit wow64 process without a 64-bit ntdll */
|
|
||||||
if (status == STATUS_INVALID_PARAMETER)
|
|
||||||
{
|
|
||||||
ULONG_PTR wow;
|
|
||||||
if (!NtQueryInformationProcess( process, ProcessWow64Information, &wow, sizeof(wow), NULL ) && wow)
|
|
||||||
status = NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, &attr, process,
|
|
||||||
(void *)0x7ffe1000, NULL, 0, 0, 0, 0, NULL );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!status) NtClose( handle );
|
if (!status) NtClose( handle );
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,6 +454,7 @@ static CROSS_PROCESS_WORK_ENTRY *expect_cross_work_entry_( CROSS_PROCESS_WORK_LI
|
||||||
|
|
||||||
ok_(__FILE__,line)( entry != NULL, "no more entries in list\n" );
|
ok_(__FILE__,line)( entry != NULL, "no more entries in list\n" );
|
||||||
if (!entry) return NULL;
|
if (!entry) return NULL;
|
||||||
|
ok_(__FILE__,line)( entry->id == id, "wrong type %u / %u\n", entry->id, id );
|
||||||
ok_(__FILE__,line)( entry->addr == (ULONG_PTR)addr, "wrong address %s / %p\n",
|
ok_(__FILE__,line)( entry->addr == (ULONG_PTR)addr, "wrong address %s / %p\n",
|
||||||
wine_dbgstr_longlong(entry->addr), addr );
|
wine_dbgstr_longlong(entry->addr), addr );
|
||||||
ok_(__FILE__,line)( entry->size == size, "wrong size %s / %Ix\n",
|
ok_(__FILE__,line)( entry->size == size, "wrong size %s / %Ix\n",
|
||||||
|
@ -468,19 +469,59 @@ static CROSS_PROCESS_WORK_ENTRY *expect_cross_work_entry_( CROSS_PROCESS_WORK_LI
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_cross_process_notifications( HANDLE process, void *ptr )
|
static void test_cross_process_notifications( HANDLE process, ULONG_PTR section, ULONG_PTR ptr )
|
||||||
{
|
{
|
||||||
CROSS_PROCESS_WORK_ENTRY *entry;
|
CROSS_PROCESS_WORK_ENTRY *entry;
|
||||||
CROSS_PROCESS_WORK_LIST *list = ptr;
|
CROSS_PROCESS_WORK_LIST *list;
|
||||||
UINT pos;
|
UINT pos;
|
||||||
void *addr, *addr2;
|
void *addr = NULL, *addr2;
|
||||||
SIZE_T size;
|
SIZE_T size = 0;
|
||||||
DWORD old_prot;
|
DWORD old_prot;
|
||||||
LARGE_INTEGER offset;
|
LARGE_INTEGER offset;
|
||||||
HANDLE file, mapping;
|
HANDLE file, mapping;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
BOOL ret;
|
||||||
BYTE data[] = { 0xcc, 0xcc, 0xcc };
|
BYTE data[] = { 0xcc, 0xcc, 0xcc };
|
||||||
|
|
||||||
|
ret = DuplicateHandle( process, (HANDLE)section, GetCurrentProcess(), &mapping,
|
||||||
|
0, FALSE, DUPLICATE_SAME_ACCESS );
|
||||||
|
ok( ret, "DuplicateHandle failed %lu\n", GetLastError() );
|
||||||
|
status = NtMapViewOfSection( mapping, GetCurrentProcess(), &addr, 0, 0, NULL,
|
||||||
|
&size, ViewShare, 0, PAGE_READWRITE );
|
||||||
|
ok( !status, "NtMapViewOfSection failed %lx\n", status );
|
||||||
|
ok( size == 0x4000, "unexpected size %Ix\n", size );
|
||||||
|
list = addr;
|
||||||
|
addr2 = malloc( size );
|
||||||
|
ret = ReadProcessMemory( process, (void *)ptr, addr2, size, &size );
|
||||||
|
ok( ret, "ReadProcessMemory failed %lu\n", GetLastError() );
|
||||||
|
ok( !memcmp( addr2, addr, size ), "wrong data\n" );
|
||||||
|
free( addr2 );
|
||||||
|
CloseHandle( mapping );
|
||||||
|
|
||||||
|
if (pRtlOpenCrossProcessEmulatorWorkConnection)
|
||||||
|
{
|
||||||
|
pRtlOpenCrossProcessEmulatorWorkConnection( process, &mapping, &addr2 );
|
||||||
|
ok( mapping != 0, "got 0 handle\n" );
|
||||||
|
ok( addr2 != NULL, "got NULL data\n" );
|
||||||
|
ok( !memcmp( addr2, addr, size ), "wrong data\n" );
|
||||||
|
UnmapViewOfFile( addr2 );
|
||||||
|
addr2 = NULL;
|
||||||
|
size = 0;
|
||||||
|
status = NtMapViewOfSection( mapping, GetCurrentProcess(), &addr2, 0, 0, NULL,
|
||||||
|
&size, ViewShare, 0, PAGE_READWRITE );
|
||||||
|
ok( !status, "NtMapViewOfSection failed %lx\n", status );
|
||||||
|
ok( !memcmp( addr2, addr, size ), "wrong data\n" );
|
||||||
|
ok( CloseHandle( mapping ), "invalid handle\n" );
|
||||||
|
UnmapViewOfFile( addr2 );
|
||||||
|
|
||||||
|
mapping = (HANDLE)0xdead;
|
||||||
|
addr2 = (void *)0xdeadbeef;
|
||||||
|
pRtlOpenCrossProcessEmulatorWorkConnection( GetCurrentProcess(), &mapping, &addr2 );
|
||||||
|
ok( !mapping, "got handle %p\n", mapping );
|
||||||
|
ok( !addr2, "got data %p\n", addr2 );
|
||||||
|
}
|
||||||
|
else skip( "RtlOpenCrossProcessEmulatorWorkConnection not supported\n" );
|
||||||
|
|
||||||
NtSuspendProcess( process );
|
NtSuspendProcess( process );
|
||||||
|
|
||||||
/* set argument values in free list to detect changes */
|
/* set argument values in free list to detect changes */
|
||||||
|
@ -672,7 +713,6 @@ static void test_cross_process_notifications( HANDLE process, void *ptr )
|
||||||
|
|
||||||
FlushInstructionCache( process, addr, 0x1234 );
|
FlushInstructionCache( process, addr, 0x1234 );
|
||||||
entry = pop_from_work_list( &list->work_list );
|
entry = pop_from_work_list( &list->work_list );
|
||||||
todo_wine_if (current_machine == IMAGE_FILE_MACHINE_ARM64)
|
|
||||||
entry = expect_cross_work_entry( list, entry, CrossProcessFlushCache, addr, 0x1234,
|
entry = expect_cross_work_entry( list, entry, CrossProcessFlushCache, addr, 0x1234,
|
||||||
0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc );
|
0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc );
|
||||||
ok( !entry, "not at end of list\n" );
|
ok( !entry, "not at end of list\n" );
|
||||||
|
@ -688,8 +728,6 @@ static void test_cross_process_notifications( HANDLE process, void *ptr )
|
||||||
|
|
||||||
WriteProcessMemory( process, (char *)addr + 0x1ffe, data, sizeof(data), &size );
|
WriteProcessMemory( process, (char *)addr + 0x1ffe, data, sizeof(data), &size );
|
||||||
entry = pop_from_work_list( &list->work_list );
|
entry = pop_from_work_list( &list->work_list );
|
||||||
todo_wine
|
|
||||||
{
|
|
||||||
entry = expect_cross_work_entry( list, entry, CrossProcessPreVirtualProtect,
|
entry = expect_cross_work_entry( list, entry, CrossProcessPreVirtualProtect,
|
||||||
(char *)addr + 0x1000, 0x2000, 0x60000000 | PAGE_EXECUTE_WRITECOPY,
|
(char *)addr + 0x1000, 0x2000, 0x60000000 | PAGE_EXECUTE_WRITECOPY,
|
||||||
(current_machine != IMAGE_FILE_MACHINE_ARM64) ? 0 : 0xcccccccc,
|
(current_machine != IMAGE_FILE_MACHINE_ARM64) ? 0 : 0xcccccccc,
|
||||||
|
@ -707,7 +745,6 @@ static void test_cross_process_notifications( HANDLE process, void *ptr )
|
||||||
entry = expect_cross_work_entry( list, entry, CrossProcessPostVirtualProtect,
|
entry = expect_cross_work_entry( list, entry, CrossProcessPostVirtualProtect,
|
||||||
(char *)addr + 0x1000, 0x2000,
|
(char *)addr + 0x1000, 0x2000,
|
||||||
0x60000000 | PAGE_EXECUTE_READ, 0, 0xcccccccc, 0xcccccccc );
|
0x60000000 | PAGE_EXECUTE_READ, 0, 0xcccccccc, 0xcccccccc );
|
||||||
}
|
|
||||||
ok( !entry, "not at end of list\n" );
|
ok( !entry, "not at end of list\n" );
|
||||||
|
|
||||||
status = NtUnmapViewOfSection( process, addr );
|
status = NtUnmapViewOfSection( process, addr );
|
||||||
|
@ -717,6 +754,99 @@ static void test_cross_process_notifications( HANDLE process, void *ptr )
|
||||||
|
|
||||||
CloseHandle( mapping );
|
CloseHandle( mapping );
|
||||||
CloseHandle( file );
|
CloseHandle( file );
|
||||||
|
UnmapViewOfFile( list );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_wow64_shared_info( HANDLE process )
|
||||||
|
{
|
||||||
|
ULONG i, peb_data[0x200], buffer[16];
|
||||||
|
WOW64INFO *info = (WOW64INFO *)buffer;
|
||||||
|
ULONG_PTR peb_ptr;
|
||||||
|
NTSTATUS status;
|
||||||
|
SIZE_T res;
|
||||||
|
BOOLEAN wow64 = 0xcc;
|
||||||
|
|
||||||
|
NtQueryInformationProcess( process, ProcessWow64Information, &peb_ptr, sizeof(peb_ptr), NULL );
|
||||||
|
memset( buffer, 0xcc, sizeof(buffer) );
|
||||||
|
status = pRtlWow64GetSharedInfoProcess( process, &wow64, info );
|
||||||
|
ok( !status, "RtlWow64GetSharedInfoProcess failed %lx\n", status );
|
||||||
|
ok( wow64 == TRUE, "wrong wow64 %u\n", wow64 );
|
||||||
|
todo_wine_if (!info->NativeSystemPageSize) /* not set in old wow64 */
|
||||||
|
{
|
||||||
|
ok( info->NativeSystemPageSize == 0x1000, "wrong page size %lx\n",
|
||||||
|
info->NativeSystemPageSize );
|
||||||
|
ok( info->CpuFlags == (native_machine == IMAGE_FILE_MACHINE_AMD64 ? WOW64_CPUFLAGS_MSFT64 : WOW64_CPUFLAGS_SOFTWARE),
|
||||||
|
"wrong flags %lx\n", info->CpuFlags );
|
||||||
|
ok( info->NativeMachineType == native_machine, "wrong machine %x / %x\n",
|
||||||
|
info->NativeMachineType, native_machine );
|
||||||
|
ok( info->EmulatedMachineType == IMAGE_FILE_MACHINE_I386, "wrong machine %x\n",
|
||||||
|
info->EmulatedMachineType );
|
||||||
|
}
|
||||||
|
ok( buffer[sizeof(*info) / sizeof(ULONG)] == 0xcccccccc, "buffer set %lx\n",
|
||||||
|
buffer[sizeof(*info) / sizeof(ULONG)] );
|
||||||
|
if (ReadProcessMemory( process, (void *)peb_ptr, peb_data, sizeof(peb_data), &res ))
|
||||||
|
{
|
||||||
|
ULONG limit = (sizeof(peb_data) - sizeof(info)) / sizeof(ULONG);
|
||||||
|
for (i = 0; i < limit; i++)
|
||||||
|
{
|
||||||
|
if (!memcmp( peb_data + i, info, sizeof(*info) ))
|
||||||
|
{
|
||||||
|
trace( "wow64info found at %lx\n", i * 4 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok( i < limit, "wow64info not found in PEB\n" );
|
||||||
|
}
|
||||||
|
if (info->SectionHandle && info->CrossProcessWorkList)
|
||||||
|
test_cross_process_notifications( process, info->SectionHandle, info->CrossProcessWorkList );
|
||||||
|
else
|
||||||
|
trace( "no WOW64INFO section handle\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_amd64_shared_info( HANDLE process )
|
||||||
|
{
|
||||||
|
ULONG i, peb_data[0x200], buffer[16];
|
||||||
|
PROCESS_BASIC_INFORMATION proc_info;
|
||||||
|
NTSTATUS status;
|
||||||
|
SIZE_T res;
|
||||||
|
BOOLEAN wow64 = 0xcc;
|
||||||
|
struct arm64ec_shared_info
|
||||||
|
{
|
||||||
|
ULONG Wow64ExecuteFlags;
|
||||||
|
USHORT NativeMachineType;
|
||||||
|
USHORT EmulatedMachineType;
|
||||||
|
ULONGLONG SectionHandle;
|
||||||
|
ULONGLONG CrossProcessWorkList;
|
||||||
|
ULONGLONG unknown;
|
||||||
|
} *info = NULL;
|
||||||
|
|
||||||
|
NtQueryInformationProcess( process, ProcessBasicInformation, &proc_info, sizeof(proc_info), NULL );
|
||||||
|
|
||||||
|
memset( buffer, 0xcc, sizeof(buffer) );
|
||||||
|
status = pRtlWow64GetSharedInfoProcess( process, &wow64, (WOW64INFO *)buffer );
|
||||||
|
ok( !status, "RtlWow64GetSharedInfoProcess failed %lx\n", status );
|
||||||
|
ok( !wow64, "wrong wow64 %u\n", wow64 );
|
||||||
|
ok( buffer[0] == 0xcccccccc, "buffer initialized %lx\n", buffer[0] );
|
||||||
|
|
||||||
|
if (ReadProcessMemory( process, (void *)proc_info.PebBaseAddress, peb_data, sizeof(peb_data), &res ))
|
||||||
|
{
|
||||||
|
ULONG limit = (sizeof(peb_data) - sizeof(*info)) / sizeof(ULONG);
|
||||||
|
for (i = 0; i < limit; i++)
|
||||||
|
{
|
||||||
|
info = (struct arm64ec_shared_info *)(peb_data + i);
|
||||||
|
if (info->NativeMachineType == IMAGE_FILE_MACHINE_ARM64 &&
|
||||||
|
info->EmulatedMachineType == IMAGE_FILE_MACHINE_AMD64)
|
||||||
|
{
|
||||||
|
trace( "shared info found at %lx\n", i * 4 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok( i < limit, "shared info not found in PEB\n" );
|
||||||
|
}
|
||||||
|
if (info && info->SectionHandle && info->CrossProcessWorkList)
|
||||||
|
test_cross_process_notifications( process, info->SectionHandle, info->CrossProcessWorkList );
|
||||||
|
else
|
||||||
|
trace( "no shared info section handle\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_peb_teb(void)
|
static void test_peb_teb(void)
|
||||||
|
@ -834,91 +964,7 @@ static void test_peb_teb(void)
|
||||||
ResumeThread( pi.hThread );
|
ResumeThread( pi.hThread );
|
||||||
WaitForInputIdle( pi.hProcess, 1000 );
|
WaitForInputIdle( pi.hProcess, 1000 );
|
||||||
|
|
||||||
if (pRtlWow64GetSharedInfoProcess)
|
if (pRtlWow64GetSharedInfoProcess) test_wow64_shared_info( pi.hProcess );
|
||||||
{
|
|
||||||
ULONG i, peb_data[0x200];
|
|
||||||
|
|
||||||
wow64 = 0xcc;
|
|
||||||
memset( buffer, 0xcc, sizeof(buffer) );
|
|
||||||
status = pRtlWow64GetSharedInfoProcess( pi.hProcess, &wow64, wow64info );
|
|
||||||
ok( !status, "RtlWow64GetSharedInfoProcess failed %lx\n", status );
|
|
||||||
ok( wow64 == TRUE, "wrong wow64 %u\n", wow64 );
|
|
||||||
todo_wine_if (!wow64info->NativeSystemPageSize) /* not set in old wow64 */
|
|
||||||
{
|
|
||||||
ok( wow64info->NativeSystemPageSize == 0x1000, "wrong page size %lx\n",
|
|
||||||
wow64info->NativeSystemPageSize );
|
|
||||||
ok( wow64info->CpuFlags == (native_machine == IMAGE_FILE_MACHINE_AMD64 ? WOW64_CPUFLAGS_MSFT64 : WOW64_CPUFLAGS_SOFTWARE),
|
|
||||||
"wrong flags %lx\n", wow64info->CpuFlags );
|
|
||||||
ok( wow64info->NativeMachineType == native_machine, "wrong machine %x / %x\n",
|
|
||||||
wow64info->NativeMachineType, native_machine );
|
|
||||||
ok( wow64info->EmulatedMachineType == IMAGE_FILE_MACHINE_I386, "wrong machine %x\n",
|
|
||||||
wow64info->EmulatedMachineType );
|
|
||||||
}
|
|
||||||
ok( buffer[sizeof(*wow64info) / sizeof(ULONG)] == 0xcccccccc, "buffer set %lx\n",
|
|
||||||
buffer[sizeof(*wow64info) / sizeof(ULONG)] );
|
|
||||||
if (ReadProcessMemory( pi.hProcess, (void *)peb_ptr, peb_data, sizeof(peb_data), &res ))
|
|
||||||
{
|
|
||||||
ULONG limit = (sizeof(peb_data) - sizeof(wow64info)) / sizeof(ULONG);
|
|
||||||
for (i = 0; i < limit; i++)
|
|
||||||
{
|
|
||||||
if (!memcmp( peb_data + i, wow64info, sizeof(*wow64info) ))
|
|
||||||
{
|
|
||||||
trace( "wow64info found at %lx\n", i * 4 );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ok( i < limit, "wow64info not found in PEB\n" );
|
|
||||||
}
|
|
||||||
if (wow64info->SectionHandle && wow64info->CrossProcessWorkList)
|
|
||||||
{
|
|
||||||
HANDLE handle;
|
|
||||||
void *data, *addr = NULL;
|
|
||||||
SIZE_T size = 0;
|
|
||||||
|
|
||||||
ret = DuplicateHandle( pi.hProcess, (HANDLE)(ULONG_PTR)wow64info->SectionHandle,
|
|
||||||
GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS );
|
|
||||||
ok( ret, "DuplicateHandle failed %lu\n", GetLastError() );
|
|
||||||
status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, NULL,
|
|
||||||
&size, ViewShare, 0, PAGE_READWRITE );
|
|
||||||
ok( !status, "NtMapViewOfSection failed %lx\n", status );
|
|
||||||
ok( size == 0x4000, "unexpected size %Ix\n", size );
|
|
||||||
data = malloc( size );
|
|
||||||
ret = ReadProcessMemory( pi.hProcess, (void *)(ULONG_PTR)wow64info->CrossProcessWorkList,
|
|
||||||
data, size, &size );
|
|
||||||
ok( ret, "ReadProcessMemory failed %lu\n", GetLastError() );
|
|
||||||
ok( !memcmp( data, addr, size ), "wrong data\n" );
|
|
||||||
free( data );
|
|
||||||
CloseHandle( handle );
|
|
||||||
|
|
||||||
if (pRtlOpenCrossProcessEmulatorWorkConnection)
|
|
||||||
{
|
|
||||||
pRtlOpenCrossProcessEmulatorWorkConnection( pi.hProcess, &handle, &data );
|
|
||||||
ok( handle != 0, "got 0 handle\n" );
|
|
||||||
ok( data != NULL, "got NULL data\n" );
|
|
||||||
ok( !memcmp( data, addr, size ), "wrong data\n" );
|
|
||||||
UnmapViewOfFile( data );
|
|
||||||
data = NULL;
|
|
||||||
size = 0;
|
|
||||||
status = NtMapViewOfSection( handle, GetCurrentProcess(), &data, 0, 0, NULL,
|
|
||||||
&size, ViewShare, 0, PAGE_READWRITE );
|
|
||||||
ok( !status, "NtMapViewOfSection failed %lx\n", status );
|
|
||||||
ok( !memcmp( data, addr, size ), "wrong data\n" );
|
|
||||||
ok( CloseHandle( handle ), "invalid handle\n" );
|
|
||||||
UnmapViewOfFile( data );
|
|
||||||
|
|
||||||
handle = (HANDLE)0xdead;
|
|
||||||
data = (void *)0xdeadbeef;
|
|
||||||
pRtlOpenCrossProcessEmulatorWorkConnection( GetCurrentProcess(), &handle, &data );
|
|
||||||
ok( !handle, "got handle %p\n", handle );
|
|
||||||
ok( !data, "got data %p\n", data );
|
|
||||||
}
|
|
||||||
else skip( "RtlOpenCrossProcessEmulatorWorkConnection not supported\n" );
|
|
||||||
|
|
||||||
test_cross_process_notifications( pi.hProcess, addr );
|
|
||||||
UnmapViewOfFile( addr );
|
|
||||||
}
|
|
||||||
else trace( "no WOW64INFO section handle\n" );
|
|
||||||
}
|
|
||||||
else win_skip( "RtlWow64GetSharedInfoProcess not supported\n" );
|
else win_skip( "RtlWow64GetSharedInfoProcess not supported\n" );
|
||||||
|
|
||||||
ret = DebugActiveProcess( pi.dwProcessId );
|
ret = DebugActiveProcess( pi.dwProcessId );
|
||||||
|
@ -938,6 +984,44 @@ static void test_peb_teb(void)
|
||||||
CloseHandle( pi.hThread );
|
CloseHandle( pi.hThread );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_win64 && native_machine == IMAGE_FILE_MACHINE_ARM64 &&
|
||||||
|
create_process_machine( (char *)"C:\\windows\\system32\\regsvr32.exe /?", CREATE_SUSPENDED,
|
||||||
|
IMAGE_FILE_MACHINE_AMD64, &pi ))
|
||||||
|
{
|
||||||
|
memset( &info, 0xcc, sizeof(info) );
|
||||||
|
status = NtQueryInformationThread( pi.hThread, ThreadBasicInformation, &info, sizeof(info), NULL );
|
||||||
|
ok( !status, "ThreadBasicInformation failed %lx\n", status );
|
||||||
|
if (!ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &teb, sizeof(teb), &res )) res = 0;
|
||||||
|
ok( res == sizeof(teb), "wrong len %Ix\n", res );
|
||||||
|
ok( teb.Tib.Self == info.TebBaseAddress, "wrong teb %p / %p\n", teb.Tib.Self, info.TebBaseAddress );
|
||||||
|
ok( !teb.GdiBatchCount, "GdiBatchCount set\n" );
|
||||||
|
ok( !teb.WowTebOffset, "wrong teb offset %ld\n", teb.WowTebOffset );
|
||||||
|
ok( !teb.Tib.ExceptionList, "wrong Tib.ExceptionList %p\n", (char *)teb.Tib.ExceptionList );
|
||||||
|
|
||||||
|
status = NtQueryInformationProcess( pi.hProcess, ProcessBasicInformation,
|
||||||
|
&proc_info, sizeof(proc_info), NULL );
|
||||||
|
ok( !status, "ProcessBasicInformation failed %lx\n", status );
|
||||||
|
ok( proc_info.PebBaseAddress == teb.Peb, "wrong peb %p / %p\n", proc_info.PebBaseAddress, teb.Peb );
|
||||||
|
|
||||||
|
status = NtQueryInformationProcess( pi.hProcess, ProcessWow64Information,
|
||||||
|
&peb_ptr, sizeof(peb_ptr), NULL );
|
||||||
|
ok( !status, "ProcessWow64Information failed %lx\n", status );
|
||||||
|
ok( !peb_ptr, "wrong peb %p\n", (void *)peb_ptr );
|
||||||
|
|
||||||
|
if (!ReadProcessMemory( pi.hProcess, proc_info.PebBaseAddress, &peb, sizeof(peb), &res )) res = 0;
|
||||||
|
ok( res == sizeof(peb), "wrong len %Ix\n", res );
|
||||||
|
ok( !peb.BeingDebugged, "BeingDebugged is %u\n", peb.BeingDebugged );
|
||||||
|
|
||||||
|
ResumeThread( pi.hThread );
|
||||||
|
WaitForInputIdle( pi.hProcess, 1000 );
|
||||||
|
|
||||||
|
test_amd64_shared_info( pi.hProcess );
|
||||||
|
|
||||||
|
TerminateProcess( pi.hProcess, 0 );
|
||||||
|
CloseHandle( pi.hProcess );
|
||||||
|
CloseHandle( pi.hThread );
|
||||||
|
}
|
||||||
|
|
||||||
if (CreateProcessA( "C:\\windows\\system32\\msinfo32.exe", NULL, NULL, NULL,
|
if (CreateProcessA( "C:\\windows\\system32\\msinfo32.exe", NULL, NULL, NULL,
|
||||||
FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
|
FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
|
||||||
{
|
{
|
||||||
|
@ -2041,14 +2125,31 @@ static void test_init_block(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static DWORD WINAPI iosb_delayed_write_thread(void *arg)
|
||||||
|
{
|
||||||
|
HANDLE client = arg;
|
||||||
|
DWORD size;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
Sleep(100);
|
||||||
|
|
||||||
|
ret = WriteFile( client, "data", sizeof("data"), &size, NULL );
|
||||||
|
ok( ret == TRUE, "got error %lu\n", GetLastError() );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void test_iosb(void)
|
static void test_iosb(void)
|
||||||
{
|
{
|
||||||
static const char pipe_name[] = "\\\\.\\pipe\\wow64iosbnamedpipe";
|
static const char pipe_name[] = "\\\\.\\pipe\\wow64iosbnamedpipe";
|
||||||
HANDLE client, server;
|
HANDLE client, server, thread;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
ULONG64 func;
|
ULONG64 read_func, flush_func;
|
||||||
DWORD id;
|
|
||||||
IO_STATUS_BLOCK iosb32;
|
IO_STATUS_BLOCK iosb32;
|
||||||
|
char buffer[6];
|
||||||
|
DWORD size;
|
||||||
|
BOOL ret;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
|
@ -2058,66 +2159,89 @@ static void test_iosb(void)
|
||||||
};
|
};
|
||||||
ULONG64 Information;
|
ULONG64 Information;
|
||||||
} iosb64;
|
} iosb64;
|
||||||
ULONG64 args[] = { 0, 0, 0, 0, (ULONG_PTR)&iosb64, FSCTL_PIPE_LISTEN, 0, 0, 0, 0 };
|
ULONG64 args[] = { 0, 0, 0, 0, (ULONG_PTR)&iosb64, (ULONG_PTR)buffer, sizeof(buffer), 0, 0 };
|
||||||
|
ULONG64 flush_args[] = { 0, (ULONG_PTR)&iosb64 };
|
||||||
|
|
||||||
if (!is_wow64) return;
|
if (!is_wow64) return;
|
||||||
if (!code_mem) return;
|
if (!code_mem) return;
|
||||||
if (!ntdll_module) return;
|
if (!ntdll_module) return;
|
||||||
func = get_proc_address64( ntdll_module, "NtFsControlFile" );
|
read_func = get_proc_address64( ntdll_module, "NtReadFile" );
|
||||||
|
flush_func = get_proc_address64( ntdll_module, "NtFlushBuffersFile" );
|
||||||
|
|
||||||
/* async calls set iosb32 but not iosb64 */
|
/* async calls set iosb32 but not iosb64 */
|
||||||
|
|
||||||
server = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
|
server = CreateNamedPipeA( pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
||||||
4, 1024, 1024, 1000, NULL );
|
4, 1024, 1024, 1000, NULL );
|
||||||
ok( server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError() );
|
ok( server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError() );
|
||||||
|
|
||||||
|
client = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
||||||
|
FILE_FLAG_NO_BUFFERING, NULL );
|
||||||
|
ok( client != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError() );
|
||||||
|
|
||||||
|
memset( buffer, 0xcc, sizeof(buffer) );
|
||||||
memset( &iosb32, 0x55, sizeof(iosb32) );
|
memset( &iosb32, 0x55, sizeof(iosb32) );
|
||||||
iosb64.Pointer = PtrToUlong( &iosb32 );
|
iosb64.Pointer = PtrToUlong( &iosb32 );
|
||||||
iosb64.Information = 0xdeadbeef;
|
iosb64.Information = 0xdeadbeef;
|
||||||
|
|
||||||
args[0] = (LONG_PTR)server;
|
args[0] = (LONG_PTR)server;
|
||||||
status = call_func64( func, ARRAY_SIZE(args), args );
|
status = call_func64( read_func, ARRAY_SIZE(args), args );
|
||||||
ok( status == STATUS_PENDING, "NtFsControlFile returned %lx\n", status );
|
ok( status == STATUS_PENDING, "NtReadFile returned %lx\n", status );
|
||||||
ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status );
|
ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status );
|
||||||
ok( iosb64.Pointer == PtrToUlong(&iosb32), "status changed to %lx\n", iosb64.Status );
|
ok( iosb64.Pointer == PtrToUlong(&iosb32), "pointer changed to %I64x\n", iosb64.Pointer );
|
||||||
ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
||||||
|
|
||||||
client = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
|
ret = WriteFile( client, "data", sizeof("data"), &size, NULL );
|
||||||
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
|
ok( ret == TRUE, "got error %lu\n", GetLastError() );
|
||||||
ok( client != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError() );
|
|
||||||
|
|
||||||
ok( iosb32.Status == 0, "Wrong iostatus %lx\n", iosb32.Status );
|
ok( iosb32.Status == 0, "Wrong iostatus %lx\n", iosb32.Status );
|
||||||
ok( iosb64.Pointer == PtrToUlong(&iosb32), "status changed to %lx\n", iosb64.Status );
|
ok( iosb32.Information == sizeof("data"), "Wrong information %Ix\n", iosb32.Information );
|
||||||
|
ok( iosb64.Pointer == PtrToUlong(&iosb32), "pointer changed to %I64x\n", iosb64.Pointer );
|
||||||
ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
||||||
|
ok( !memcmp( buffer, "data", iosb32.Information ),
|
||||||
|
"got wrong data %s\n", debugstr_an(buffer, iosb32.Information) );
|
||||||
|
|
||||||
|
memset( buffer, 0xcc, sizeof(buffer) );
|
||||||
|
memset( &iosb32, 0x55, sizeof(iosb32) );
|
||||||
|
iosb64.Pointer = PtrToUlong( &iosb32 );
|
||||||
|
iosb64.Information = 0xdeadbeef;
|
||||||
|
|
||||||
|
ret = WriteFile( client, "data", sizeof("data"), &size, NULL );
|
||||||
|
ok( ret == TRUE, "got error %lu\n", GetLastError() );
|
||||||
|
|
||||||
|
status = call_func64( read_func, ARRAY_SIZE(args), args );
|
||||||
|
ok( status == STATUS_SUCCESS, "NtReadFile returned %lx\n", status );
|
||||||
|
todo_wine
|
||||||
|
{
|
||||||
|
ok( iosb32.Status == STATUS_SUCCESS, "status changed to %lx\n", iosb32.Status );
|
||||||
|
ok( iosb32.Information == sizeof("data"), "info changed to %lx\n", iosb32.Information );
|
||||||
|
ok( iosb64.Pointer == PtrToUlong(&iosb32), "pointer changed to %I64x\n", iosb64.Pointer );
|
||||||
|
ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
||||||
|
if (iosb32.Information == sizeof("data"))
|
||||||
|
ok( !memcmp( buffer, "data", iosb32.Information ),
|
||||||
|
"got wrong data %s\n", debugstr_an(buffer, iosb32.Information) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* syscalls which are always synchronous set iosb64 but not iosb32 */
|
||||||
|
|
||||||
memset( &iosb32, 0x55, sizeof(iosb32) );
|
memset( &iosb32, 0x55, sizeof(iosb32) );
|
||||||
iosb64.Pointer = PtrToUlong( &iosb32 );
|
iosb64.Pointer = PtrToUlong( &iosb32 );
|
||||||
iosb64.Information = 0xdeadbeef;
|
iosb64.Information = 0xdeadbeef;
|
||||||
id = 0xdeadbeef;
|
|
||||||
|
|
||||||
args[5] = FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE;
|
flush_args[0] = (LONG_PTR)server;
|
||||||
args[6] = (ULONG_PTR)"ClientProcessId";
|
status = call_func64( flush_func, ARRAY_SIZE(flush_args), flush_args );
|
||||||
args[7] = sizeof("ClientProcessId");
|
ok( status == STATUS_SUCCESS, "NtFlushBuffersFile returned %lx\n", status );
|
||||||
args[8] = (ULONG_PTR)&id;
|
ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status );
|
||||||
args[9] = sizeof(id);
|
ok( iosb32.Information == 0x55555555, "info changed to %lx\n", iosb32.Information );
|
||||||
|
ok( iosb64.Pointer == STATUS_SUCCESS, "pointer changed to %I64x\n", iosb64.Pointer );
|
||||||
|
ok( iosb64.Information == 0, "info changed to %lx\n", (ULONG_PTR)iosb64.Information );
|
||||||
|
|
||||||
status = call_func64( func, ARRAY_SIZE(args), args );
|
|
||||||
ok( status == STATUS_PENDING || status == STATUS_SUCCESS, "NtFsControlFile returned %lx\n", status );
|
|
||||||
todo_wine
|
|
||||||
{
|
|
||||||
ok( iosb32.Status == STATUS_SUCCESS, "status changed to %lx\n", iosb32.Status );
|
|
||||||
ok( iosb32.Information == sizeof(id), "info changed to %Ix\n", iosb32.Information );
|
|
||||||
ok( iosb64.Pointer == PtrToUlong(&iosb32), "status changed to %lx\n", iosb64.Status );
|
|
||||||
ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
|
||||||
}
|
|
||||||
ok( id == GetCurrentProcessId(), "wrong id %lx / %lx\n", id, GetCurrentProcessId() );
|
|
||||||
CloseHandle( client );
|
CloseHandle( client );
|
||||||
CloseHandle( server );
|
CloseHandle( server );
|
||||||
|
|
||||||
/* synchronous calls set iosb64 but not iosb32 */
|
/* synchronous calls set iosb64 but not iosb32 */
|
||||||
|
|
||||||
server = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND,
|
server = CreateNamedPipeA( pipe_name, PIPE_ACCESS_DUPLEX,
|
||||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
||||||
4, 1024, 1024, 1000, NULL );
|
4, 1024, 1024, 1000, NULL );
|
||||||
ok( server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError() );
|
ok( server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError() );
|
||||||
|
@ -2126,19 +2250,60 @@ static void test_iosb(void)
|
||||||
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
|
FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
|
||||||
ok( client != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError() );
|
ok( client != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError() );
|
||||||
|
|
||||||
|
ret = WriteFile( client, "data", sizeof("data"), &size, NULL );
|
||||||
|
ok( ret == TRUE, "got error %lu\n", GetLastError() );
|
||||||
|
|
||||||
|
memset( buffer, 0xcc, sizeof(buffer) );
|
||||||
memset( &iosb32, 0x55, sizeof(iosb32) );
|
memset( &iosb32, 0x55, sizeof(iosb32) );
|
||||||
iosb64.Pointer = PtrToUlong( &iosb32 );
|
iosb64.Pointer = PtrToUlong( &iosb32 );
|
||||||
iosb64.Information = 0xdeadbeef;
|
iosb64.Information = 0xdeadbeef;
|
||||||
id = 0xdeadbeef;
|
|
||||||
|
|
||||||
args[0] = (LONG_PTR)server;
|
args[0] = (LONG_PTR)server;
|
||||||
status = call_func64( func, ARRAY_SIZE(args), args );
|
status = call_func64( read_func, ARRAY_SIZE(args), args );
|
||||||
ok( status == STATUS_SUCCESS, "NtFsControlFile returned %lx\n", status );
|
ok( status == STATUS_SUCCESS, "NtReadFile returned %lx\n", status );
|
||||||
ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status );
|
ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status );
|
||||||
ok( iosb32.Information == 0x55555555, "info changed to %Ix\n", iosb32.Information );
|
ok( iosb32.Information == 0x55555555, "info changed to %lx\n", iosb32.Information );
|
||||||
ok( iosb64.Pointer == STATUS_SUCCESS, "status changed to %lx\n", iosb64.Status );
|
ok( iosb64.Pointer == STATUS_SUCCESS, "pointer changed to %I64x\n", iosb64.Pointer );
|
||||||
ok( iosb64.Information == sizeof(id), "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
ok( iosb64.Information == sizeof("data"), "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
||||||
ok( id == GetCurrentProcessId(), "wrong id %lx / %lx\n", id, GetCurrentProcessId() );
|
ok( !memcmp( buffer, "data", iosb64.Information ),
|
||||||
|
"got wrong data %s\n", debugstr_an(buffer, iosb64.Information) );
|
||||||
|
|
||||||
|
thread = CreateThread( NULL, 0, iosb_delayed_write_thread, client, 0, NULL );
|
||||||
|
|
||||||
|
memset( buffer, 0xcc, sizeof(buffer) );
|
||||||
|
memset( &iosb32, 0x55, sizeof(iosb32) );
|
||||||
|
iosb64.Pointer = PtrToUlong( &iosb32 );
|
||||||
|
iosb64.Information = 0xdeadbeef;
|
||||||
|
|
||||||
|
args[0] = (LONG_PTR)server;
|
||||||
|
status = call_func64( read_func, ARRAY_SIZE(args), args );
|
||||||
|
ok( status == STATUS_SUCCESS, "NtReadFile returned %lx\n", status );
|
||||||
|
todo_wine
|
||||||
|
{
|
||||||
|
ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status );
|
||||||
|
ok( iosb32.Information == 0x55555555, "info changed to %lx\n", iosb32.Information );
|
||||||
|
ok( iosb64.Pointer == STATUS_SUCCESS, "pointer changed to %I64x\n", iosb64.Pointer );
|
||||||
|
ok( iosb64.Information == sizeof("data"), "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
|
||||||
|
ok( !memcmp( buffer, "data", iosb64.Information ),
|
||||||
|
"got wrong data %s\n", debugstr_an(buffer, iosb64.Information) );
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = WaitForSingleObject( thread, 1000 );
|
||||||
|
ok(!ret, "got %d\n", ret );
|
||||||
|
CloseHandle( thread );
|
||||||
|
|
||||||
|
memset( &iosb32, 0x55, sizeof(iosb32) );
|
||||||
|
iosb64.Pointer = PtrToUlong( &iosb32 );
|
||||||
|
iosb64.Information = 0xdeadbeef;
|
||||||
|
|
||||||
|
flush_args[0] = (LONG_PTR)server;
|
||||||
|
status = call_func64( flush_func, ARRAY_SIZE(flush_args), flush_args );
|
||||||
|
ok( status == STATUS_SUCCESS, "NtFlushBuffersFile returned %lx\n", status );
|
||||||
|
ok( iosb32.Status == 0x55555555, "status changed to %lx\n", iosb32.Status );
|
||||||
|
ok( iosb32.Information == 0x55555555, "info changed to %lx\n", iosb32.Information );
|
||||||
|
ok( iosb64.Pointer == STATUS_SUCCESS, "pointer changed to %I64x\n", iosb64.Pointer );
|
||||||
|
ok( iosb64.Information == 0, "info changed to %lx\n", (ULONG_PTR)iosb64.Information );
|
||||||
|
|
||||||
CloseHandle( client );
|
CloseHandle( client );
|
||||||
CloseHandle( server );
|
CloseHandle( server );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1583,7 +1583,7 @@ static void load_ntdll_wow64_functions( HMODULE module )
|
||||||
GET_FUNC( RtlpFreezeTimeBias );
|
GET_FUNC( RtlpFreezeTimeBias );
|
||||||
GET_FUNC( RtlpQueryProcessDebugInformationRemote );
|
GET_FUNC( RtlpQueryProcessDebugInformationRemote );
|
||||||
#undef GET_FUNC
|
#undef GET_FUNC
|
||||||
|
pDbgUiRemoteBreakin = (void *)find_named_export( module, exports, "DbgUiRemoteBreakin" );
|
||||||
p__wine_ctrl_routine = (void *)find_named_export( module, exports, "__wine_ctrl_routine" );
|
p__wine_ctrl_routine = (void *)find_named_export( module, exports, "__wine_ctrl_routine" );
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
|
|
|
@ -452,21 +452,7 @@ static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_waiting( HANDLE handle )
|
static NTSTATUS get_wait_mask( HANDLE hDevice, UINT *mask, BOOL *pending_write )
|
||||||
{
|
|
||||||
unsigned int status;
|
|
||||||
|
|
||||||
SERVER_START_REQ( set_serial_info )
|
|
||||||
{
|
|
||||||
req->handle = wine_server_obj_handle( handle );
|
|
||||||
req->flags = SERIALINFO_PENDING_WAIT;
|
|
||||||
if ((status = wine_server_call( req )))
|
|
||||||
ERR("failed to clear waiting state: %#x\n", status);
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS get_wait_mask(HANDLE hDevice, UINT *mask, UINT *cookie, BOOL *pending_write, BOOL start_wait)
|
|
||||||
{
|
{
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
|
|
||||||
|
@ -474,11 +460,9 @@ static NTSTATUS get_wait_mask(HANDLE hDevice, UINT *mask, UINT *cookie, BOOL *pe
|
||||||
{
|
{
|
||||||
req->handle = wine_server_obj_handle( hDevice );
|
req->handle = wine_server_obj_handle( hDevice );
|
||||||
req->flags = pending_write ? SERIALINFO_PENDING_WRITE : 0;
|
req->flags = pending_write ? SERIALINFO_PENDING_WRITE : 0;
|
||||||
if (start_wait) req->flags |= SERIALINFO_PENDING_WAIT;
|
|
||||||
if (!(status = wine_server_call( req )))
|
if (!(status = wine_server_call( req )))
|
||||||
{
|
{
|
||||||
*mask = reply->eventmask;
|
*mask = reply->eventmask;
|
||||||
if (cookie) *cookie = reply->cookie;
|
|
||||||
if (pending_write) *pending_write = reply->pending_write;
|
if (pending_write) *pending_write = reply->pending_write;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -982,7 +966,6 @@ typedef struct async_commio
|
||||||
struct async_fileio io;
|
struct async_fileio io;
|
||||||
DWORD* events;
|
DWORD* events;
|
||||||
UINT evtmask;
|
UINT evtmask;
|
||||||
UINT cookie;
|
|
||||||
UINT mstat;
|
UINT mstat;
|
||||||
BOOL pending_write;
|
BOOL pending_write;
|
||||||
serial_irq_info irq_info;
|
serial_irq_info irq_info;
|
||||||
|
@ -1095,7 +1078,7 @@ static BOOL async_wait_proc( void *user, ULONG_PTR *info, unsigned int *status )
|
||||||
if (!server_get_unix_fd( commio->io.handle, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
|
if (!server_get_unix_fd( commio->io.handle, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
|
||||||
{
|
{
|
||||||
serial_irq_info new_irq_info;
|
serial_irq_info new_irq_info;
|
||||||
UINT new_mstat, dummy, cookie;
|
UINT new_mstat, dummy;
|
||||||
|
|
||||||
TRACE( "device=%p fd=0x%08x mask=0x%08x buffer=%p irq_info=%p\n",
|
TRACE( "device=%p fd=0x%08x mask=0x%08x buffer=%p irq_info=%p\n",
|
||||||
commio->io.handle, fd, commio->evtmask, commio->events, &commio->irq_info );
|
commio->io.handle, fd, commio->evtmask, commio->events, &commio->irq_info );
|
||||||
|
@ -1126,24 +1109,14 @@ static BOOL async_wait_proc( void *user, ULONG_PTR *info, unsigned int *status )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
get_wait_mask( commio->io.handle, &dummy, &cookie, (commio->evtmask & EV_TXEMPTY) ? &commio->pending_write : NULL, FALSE );
|
get_wait_mask( commio->io.handle, &dummy, (commio->evtmask & EV_TXEMPTY) ? &commio->pending_write : NULL );
|
||||||
if (commio->cookie != cookie)
|
if (needs_close) close( fd );
|
||||||
{
|
return FALSE;
|
||||||
*commio->events = 0;
|
|
||||||
*status = STATUS_CANCELLED;
|
|
||||||
*info = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (needs_close) close( fd );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needs_close) close( fd );
|
if (needs_close) close( fd );
|
||||||
}
|
}
|
||||||
stop_waiting( commio->io.handle );
|
|
||||||
release_fileio( &commio->io );
|
release_fileio( &commio->io );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1161,7 +1134,7 @@ static NTSTATUS wait_on( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE ap
|
||||||
|
|
||||||
commio->events = out_buffer;
|
commio->events = out_buffer;
|
||||||
commio->pending_write = 0;
|
commio->pending_write = 0;
|
||||||
status = get_wait_mask( handle, &commio->evtmask, &commio->cookie, (commio->evtmask & EV_TXEMPTY) ? &commio->pending_write : NULL, TRUE );
|
status = get_wait_mask( handle, &commio->evtmask, (commio->evtmask & EV_TXEMPTY) ? &commio->pending_write : NULL );
|
||||||
if (status)
|
if (status)
|
||||||
{
|
{
|
||||||
free( commio );
|
free( commio );
|
||||||
|
|
|
@ -640,7 +640,7 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO
|
||||||
(ULONG_PTR)func == call->create_thread.func && (ULONG_PTR)arg == call->create_thread.arg)
|
(ULONG_PTR)func == call->create_thread.func && (ULONG_PTR)arg == call->create_thread.arg)
|
||||||
{
|
{
|
||||||
/* FIXME: hack for debugging 32-bit process without a 64-bit ntdll */
|
/* FIXME: hack for debugging 32-bit process without a 64-bit ntdll */
|
||||||
if (is_old_wow64() && func == (void *)0x7ffe1000) func = pDbgUiRemoteBreakin;
|
if (is_wow64()) func = pDbgUiRemoteBreakin;
|
||||||
attr->TotalLength = sizeof(buffer);
|
attr->TotalLength = sizeof(buffer);
|
||||||
attr->Attributes[0].Attribute = PS_ATTRIBUTE_CLIENT_ID;
|
attr->Attributes[0].Attribute = PS_ATTRIBUTE_CLIENT_ID;
|
||||||
attr->Attributes[0].Size = sizeof(id);
|
attr->Attributes[0].Size = sizeof(id);
|
||||||
|
|
|
@ -198,7 +198,7 @@ static const char *debugstr_sqllen( SQLLEN len )
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_BINDING_PARAMS 1024
|
#define MAX_BINDING_PARAMS 1024
|
||||||
static BOOL alloc_binding( struct param_binding *binding, UINT column, UINT row_count )
|
static BOOL alloc_binding( struct param_binding *binding, USHORT type, UINT column, UINT row_count )
|
||||||
{
|
{
|
||||||
if (column > MAX_BINDING_PARAMS)
|
if (column > MAX_BINDING_PARAMS)
|
||||||
{
|
{
|
||||||
|
@ -208,6 +208,7 @@ static BOOL alloc_binding( struct param_binding *binding, UINT column, UINT row_
|
||||||
if (!binding->param && !(binding->param = calloc( MAX_BINDING_PARAMS, sizeof(*binding->param)))) return FALSE;
|
if (!binding->param && !(binding->param = calloc( MAX_BINDING_PARAMS, sizeof(*binding->param)))) return FALSE;
|
||||||
|
|
||||||
if (!(binding->param[column - 1].len = calloc( row_count, sizeof(UINT64) ))) return FALSE;
|
if (!(binding->param[column - 1].len = calloc( row_count, sizeof(UINT64) ))) return FALSE;
|
||||||
|
binding->param[column - 1].type = type;
|
||||||
binding->count = column;
|
binding->count = column;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -232,10 +233,13 @@ SQLRETURN WINAPI SQLBindCol(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,
|
||||||
FIXME( "column 0 not handled\n" );
|
FIXME( "column 0 not handled\n" );
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
if (!alloc_binding( &handle->bind_col, ColumnNumber, handle->row_count )) return SQL_ERROR;
|
if (!alloc_binding( &handle->bind_col, SQL_PARAM_INPUT_OUTPUT, ColumnNumber, handle->row_count )) return SQL_ERROR;
|
||||||
|
handle->bind_col.param[i].col.target_type = TargetType;
|
||||||
|
handle->bind_col.param[i].col.target_value = TargetValue;
|
||||||
|
handle->bind_col.param[i].col.buffer_length = BufferLength;
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
params.StrLen_or_Ind = handle->bind_col.param[i].len;
|
if (StrLen_or_Ind) params.StrLen_or_Ind = handle->bind_col.param[i].len;
|
||||||
*(UINT64 *)params.StrLen_or_Ind = *StrLen_or_Ind;
|
|
||||||
if (SUCCESS(( ret = ODBC_CALL( SQLBindCol, ¶ms )))) handle->bind_col.param[i].ptr = StrLen_or_Ind;
|
if (SUCCESS(( ret = ODBC_CALL( SQLBindCol, ¶ms )))) handle->bind_col.param[i].ptr = StrLen_or_Ind;
|
||||||
TRACE ("Returning %d\n", ret);
|
TRACE ("Returning %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -273,7 +277,12 @@ SQLRETURN WINAPI SQLBindParam(SQLHSTMT StatementHandle, SQLUSMALLINT ParameterNu
|
||||||
FIXME( "parameter 0 not handled\n" );
|
FIXME( "parameter 0 not handled\n" );
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
if (!alloc_binding( &handle->bind_param, ParameterNumber, handle->row_count )) return SQL_ERROR;
|
if (!alloc_binding( &handle->bind_param, SQL_PARAM_INPUT, ParameterNumber, handle->row_count )) return SQL_ERROR;
|
||||||
|
handle->bind_param.param[i].param.value_type = ValueType;
|
||||||
|
handle->bind_param.param[i].param.parameter_type = ParameterType;
|
||||||
|
handle->bind_param.param[i].param.length_precision = LengthPrecision;
|
||||||
|
handle->bind_param.param[i].param.parameter_scale = ParameterScale;
|
||||||
|
handle->bind_param.param[i].param.parameter_value = ParameterValue;
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
params.StrLen_or_Ind = handle->bind_param.param[i].len;
|
params.StrLen_or_Ind = handle->bind_param.param[i].len;
|
||||||
|
@ -342,7 +351,7 @@ SQLRETURN WINAPI SQLColAttribute(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNu
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
params.NumericAttribute = &num_attr;
|
params.NumericAttribute = &num_attr;
|
||||||
if (SUCCESS(( ret = ODBC_CALL( SQLColAttribute, ¶ms )))) *NumericAttribute = num_attr;
|
if (SUCCESS(( ret = ODBC_CALL( SQLColAttribute, ¶ms ))) && NumericAttribute) *NumericAttribute = num_attr;
|
||||||
TRACE("Returning %d\n", ret);
|
TRACE("Returning %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -586,6 +595,66 @@ SQLRETURN WINAPI SQLExecDirect(SQLHSTMT StatementHandle, SQLCHAR *StatementText,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void len_to_user( SQLLEN *ptr, UINT8 *len, UINT row_count, UINT width )
|
||||||
|
{
|
||||||
|
UINT i;
|
||||||
|
for (i = 0; i < row_count; i++)
|
||||||
|
{
|
||||||
|
*ptr++ = *(SQLLEN *)(len + i * width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void len_from_user( UINT8 *len, SQLLEN *ptr, UINT row_count, UINT width )
|
||||||
|
{
|
||||||
|
UINT i;
|
||||||
|
for (i = 0; i < row_count; i++)
|
||||||
|
{
|
||||||
|
*(SQLLEN *)(len + i * width) = *ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_result_lengths( struct handle *handle, USHORT type )
|
||||||
|
{
|
||||||
|
UINT i, width = sizeof(void *) == 8 ? 8 : is_wow64 ? 8 : 4;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SQL_PARAM_OUTPUT:
|
||||||
|
for (i = 0; i < handle->bind_col.count; i++)
|
||||||
|
{
|
||||||
|
len_to_user( handle->bind_col.param[i].ptr, handle->bind_col.param[i].len, handle->row_count, width );
|
||||||
|
}
|
||||||
|
for (i = 0; i < handle->bind_param.count; i++)
|
||||||
|
{
|
||||||
|
len_to_user( handle->bind_param.param[i].ptr, handle->bind_param.param[i].len, handle->row_count, width );
|
||||||
|
}
|
||||||
|
for (i = 0; i < handle->bind_parameter.count; i++)
|
||||||
|
{
|
||||||
|
if (handle->bind_parameter.param[i].type != SQL_PARAM_OUTPUT &&
|
||||||
|
handle->bind_parameter.param[i].type != SQL_PARAM_INPUT_OUTPUT) continue;
|
||||||
|
|
||||||
|
len_to_user( handle->bind_parameter.param[i].ptr, handle->bind_parameter.param[i].len, handle->row_count, width );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQL_PARAM_INPUT:
|
||||||
|
for (i = 0; i < handle->bind_col.count; i++)
|
||||||
|
{
|
||||||
|
len_from_user( handle->bind_col.param[i].len, handle->bind_col.param[i].ptr, handle->row_count, width );
|
||||||
|
}
|
||||||
|
/* FIXME: handle bind_param */
|
||||||
|
for (i = 0; i < handle->bind_parameter.count; i++)
|
||||||
|
{
|
||||||
|
if (handle->bind_parameter.param[i].type != SQL_PARAM_INPUT &&
|
||||||
|
handle->bind_parameter.param[i].type != SQL_PARAM_INPUT_OUTPUT) continue;
|
||||||
|
|
||||||
|
len_from_user( handle->bind_parameter.param[i].len, handle->bind_parameter.param[i].ptr, handle->row_count, width );
|
||||||
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* SQLExecute [ODBC32.012]
|
* SQLExecute [ODBC32.012]
|
||||||
*/
|
*/
|
||||||
|
@ -600,50 +669,12 @@ SQLRETURN WINAPI SQLExecute(SQLHSTMT StatementHandle)
|
||||||
if (!handle) return SQL_INVALID_HANDLE;
|
if (!handle) return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
ret = ODBC_CALL( SQLExecute, ¶ms );
|
update_result_lengths( handle, SQL_PARAM_INPUT );
|
||||||
|
if (SUCCESS(( ret = ODBC_CALL( SQLExecute, ¶ms )))) update_result_lengths( handle, SQL_PARAM_OUTPUT );
|
||||||
TRACE("Returning %d\n", ret);
|
TRACE("Returning %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_result_lengths( struct handle *handle )
|
|
||||||
{
|
|
||||||
UINT i, j, width = sizeof(void *) == 8 ? 8 : is_wow64 ? 8 : 4;
|
|
||||||
|
|
||||||
for (i = 0; i < handle->bind_col.count; i++)
|
|
||||||
{
|
|
||||||
SQLLEN *ptr = handle->bind_col.param[i].ptr;
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
for (j = 0; j < handle->row_count; j++)
|
|
||||||
{
|
|
||||||
*ptr++ = *(SQLLEN *)(handle->bind_col.param[i].len + j * width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0; i < handle->bind_param.count; i++)
|
|
||||||
{
|
|
||||||
SQLLEN *ptr = handle->bind_param.param[i].ptr;
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
for (j = 0; j < handle->row_count; j++)
|
|
||||||
{
|
|
||||||
*ptr++ = *(SQLLEN *)(handle->bind_param.param[i].len + j * width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (i = 0; i < handle->bind_parameter.count; i++)
|
|
||||||
{
|
|
||||||
SQLLEN *ptr = handle->bind_parameter.param[i].ptr;
|
|
||||||
if (ptr)
|
|
||||||
{
|
|
||||||
for (j = 0; j < handle->row_count; j++)
|
|
||||||
{
|
|
||||||
*ptr++ = *(SQLLEN *)(handle->bind_parameter.param[i].len + j * width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* SQLFetch [ODBC32.013]
|
* SQLFetch [ODBC32.013]
|
||||||
*/
|
*/
|
||||||
|
@ -658,7 +689,7 @@ SQLRETURN WINAPI SQLFetch(SQLHSTMT StatementHandle)
|
||||||
if (!handle) return SQL_INVALID_HANDLE;
|
if (!handle) return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
if (SUCCESS(( ret = ODBC_CALL( SQLFetch, ¶ms )))) update_result_lengths( handle );
|
if (SUCCESS(( ret = ODBC_CALL( SQLFetch, ¶ms )))) update_result_lengths( handle, SQL_PARAM_OUTPUT );
|
||||||
TRACE("Returning %d\n", ret);
|
TRACE("Returning %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -678,7 +709,7 @@ SQLRETURN WINAPI SQLFetchScroll(SQLHSTMT StatementHandle, SQLSMALLINT FetchOrien
|
||||||
if (!handle) return SQL_INVALID_HANDLE;
|
if (!handle) return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
if (SUCCESS(( ret = ODBC_CALL( SQLFetchScroll, ¶ms )))) update_result_lengths( handle );
|
if (SUCCESS(( ret = ODBC_CALL( SQLFetchScroll, ¶ms )))) update_result_lengths( handle, SQL_PARAM_OUTPUT );
|
||||||
TRACE("Returning %d\n", ret);
|
TRACE("Returning %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1354,20 +1385,76 @@ static BOOL resize_result_lengths( struct handle *handle, UINT size )
|
||||||
UINT i;
|
UINT i;
|
||||||
for (i = 0; i < handle->bind_col.count; i++)
|
for (i = 0; i < handle->bind_col.count; i++)
|
||||||
{
|
{
|
||||||
UINT8 *tmp = realloc( handle->bind_col.param[i].len, size * sizeof(UINT64) );
|
UINT8 *tmp;
|
||||||
if (!tmp) return FALSE;
|
if (!handle->bind_col.param[i].ptr) continue;
|
||||||
|
if (!(tmp = realloc( handle->bind_col.param[i].len, size * sizeof(UINT64) ))) return FALSE;
|
||||||
|
if (tmp != handle->bind_col.param[i].len)
|
||||||
|
{
|
||||||
|
struct SQLBindCol_params params;
|
||||||
|
|
||||||
|
params.StatementHandle = handle->unix_handle;
|
||||||
|
params.ColumnNumber = i + 1;
|
||||||
|
params.TargetType = handle->bind_col.param[i].col.target_type;
|
||||||
|
params.TargetValue = handle->bind_col.param[i].col.target_value;
|
||||||
|
params.BufferLength = handle->bind_col.param[i].col.buffer_length;
|
||||||
|
params.StrLen_or_Ind = tmp;
|
||||||
|
if (!SUCCESS(ODBC_CALL( SQLBindCol, ¶ms )))
|
||||||
|
{
|
||||||
|
free( tmp );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
handle->bind_col.param[i].len = tmp;
|
handle->bind_col.param[i].len = tmp;
|
||||||
}
|
}
|
||||||
for (i = 0; i < handle->bind_param.count; i++)
|
for (i = 0; i < handle->bind_param.count; i++)
|
||||||
{
|
{
|
||||||
UINT8 *tmp = realloc( handle->bind_param.param[i].len, size * sizeof(UINT64) );
|
UINT8 *tmp;
|
||||||
if (!tmp) return FALSE;
|
if (!handle->bind_param.param[i].ptr) continue;
|
||||||
|
if (!(tmp = realloc( handle->bind_param.param[i].len, size * sizeof(UINT64) ))) return FALSE;
|
||||||
|
if (tmp != handle->bind_param.param[i].len)
|
||||||
|
{
|
||||||
|
struct SQLBindParam_params params;
|
||||||
|
|
||||||
|
params.StatementHandle = handle->unix_handle;
|
||||||
|
params.ParameterNumber = i + 1;
|
||||||
|
params.ValueType = handle->bind_param.param[i].param.value_type;
|
||||||
|
params.ParameterType = handle->bind_param.param[i].param.parameter_type;
|
||||||
|
params.LengthPrecision = handle->bind_param.param[i].param.length_precision;
|
||||||
|
params.ParameterScale = handle->bind_param.param[i].param.parameter_scale;
|
||||||
|
params.ParameterValue = handle->bind_param.param[i].param.parameter_value;
|
||||||
|
params.StrLen_or_Ind = tmp;
|
||||||
|
if (!SUCCESS(ODBC_CALL( SQLBindParam, ¶ms )))
|
||||||
|
{
|
||||||
|
free( tmp );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
handle->bind_param.param[i].len = tmp;
|
handle->bind_param.param[i].len = tmp;
|
||||||
}
|
}
|
||||||
for (i = 0; i < handle->bind_parameter.count; i++)
|
for (i = 0; i < handle->bind_parameter.count; i++)
|
||||||
{
|
{
|
||||||
UINT8 *tmp = realloc( handle->bind_parameter.param[i].len, size * sizeof(UINT64) );
|
UINT8 *tmp;
|
||||||
if (!tmp) return FALSE;
|
if (!(tmp = realloc( handle->bind_parameter.param[i].len, size * sizeof(UINT64) ))) return FALSE;
|
||||||
|
if (tmp != handle->bind_parameter.param[i].len)
|
||||||
|
{
|
||||||
|
struct SQLBindParameter_params params;
|
||||||
|
|
||||||
|
params.StatementHandle = handle->unix_handle;
|
||||||
|
params.ParameterNumber = i + 1;
|
||||||
|
params.InputOutputType = handle->bind_parameter.param[i].parameter.input_output_type;
|
||||||
|
params.ValueType = handle->bind_parameter.param[i].parameter.value_type;
|
||||||
|
params.ParameterType = handle->bind_parameter.param[i].parameter.parameter_type;
|
||||||
|
params.ColumnSize = handle->bind_parameter.param[i].parameter.column_size;
|
||||||
|
params.DecimalDigits = handle->bind_parameter.param[i].parameter.decimal_digits;
|
||||||
|
params.ParameterValue = handle->bind_parameter.param[i].parameter.parameter_value;
|
||||||
|
params.BufferLength = handle->bind_parameter.param[i].parameter.buffer_length;
|
||||||
|
params.StrLen_or_Ind = tmp;
|
||||||
|
if (!SUCCESS(ODBC_CALL( SQLBindParameter, ¶ms )))
|
||||||
|
{
|
||||||
|
free( tmp );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
handle->bind_parameter.param[i].len = tmp;
|
handle->bind_parameter.param[i].len = tmp;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1560,7 +1647,7 @@ SQLRETURN WINAPI SQLBulkOperations(SQLHSTMT StatementHandle, SQLSMALLINT Operati
|
||||||
if (!handle) return SQL_INVALID_HANDLE;
|
if (!handle) return SQL_INVALID_HANDLE;
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
if (SUCCESS(( ret = ODBC_CALL( SQLBulkOperations, ¶ms )))) update_result_lengths( handle );
|
if (SUCCESS(( ret = ODBC_CALL( SQLBulkOperations, ¶ms )))) update_result_lengths( handle, SQL_PARAM_OUTPUT );
|
||||||
TRACE("Returning %d\n", ret);
|
TRACE("Returning %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1876,7 +1963,7 @@ SQLRETURN WINAPI SQLSetPos(SQLHSTMT StatementHandle, SQLSETPOSIROW RowNumber, SQ
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
if (SUCCESS(( ret = ODBC_CALL( SQLSetPos, ¶ms ))) && Operation == SQL_REFRESH)
|
if (SUCCESS(( ret = ODBC_CALL( SQLSetPos, ¶ms ))) && Operation == SQL_REFRESH)
|
||||||
update_result_lengths( handle );
|
update_result_lengths( handle, SQL_PARAM_OUTPUT );
|
||||||
TRACE("Returning %d\n", ret);
|
TRACE("Returning %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1961,7 +2048,14 @@ SQLRETURN WINAPI SQLBindParameter(SQLHSTMT StatementHandle, SQLUSMALLINT Paramet
|
||||||
FIXME( "parameter 0 not handled\n" );
|
FIXME( "parameter 0 not handled\n" );
|
||||||
return SQL_ERROR;
|
return SQL_ERROR;
|
||||||
}
|
}
|
||||||
if (!alloc_binding( &handle->bind_parameter, ParameterNumber, handle->row_count )) return SQL_ERROR;
|
if (!alloc_binding( &handle->bind_parameter, InputOutputType, ParameterNumber, handle->row_count )) return SQL_ERROR;
|
||||||
|
handle->bind_parameter.param[i].parameter.input_output_type = InputOutputType;
|
||||||
|
handle->bind_parameter.param[i].parameter.value_type = ValueType;
|
||||||
|
handle->bind_parameter.param[i].parameter.parameter_type = ParameterType;
|
||||||
|
handle->bind_parameter.param[i].parameter.column_size = ColumnSize;
|
||||||
|
handle->bind_parameter.param[i].parameter.decimal_digits = DecimalDigits;
|
||||||
|
handle->bind_parameter.param[i].parameter.parameter_value = ParameterValue;
|
||||||
|
handle->bind_parameter.param[i].parameter.buffer_length = BufferLength;
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
params.StrLen_or_Ind = handle->bind_parameter.param[i].len;
|
params.StrLen_or_Ind = handle->bind_parameter.param[i].len;
|
||||||
|
@ -2277,7 +2371,7 @@ SQLRETURN WINAPI SQLColAttributeW(SQLHSTMT StatementHandle, SQLUSMALLINT ColumnN
|
||||||
|
|
||||||
params.StatementHandle = handle->unix_handle;
|
params.StatementHandle = handle->unix_handle;
|
||||||
params.NumericAttribute = &attr;
|
params.NumericAttribute = &attr;
|
||||||
if (SUCCESS((ret = ODBC_CALL( SQLColAttributeW, ¶ms )))) *NumericAttribute = attr;
|
if (SUCCESS((ret = ODBC_CALL( SQLColAttributeW, ¶ms ))) && NumericAttribute) *NumericAttribute = attr;
|
||||||
|
|
||||||
if (ret == SQL_SUCCESS && CharacterAttribute != NULL && SQLColAttributes_KnownStringAttribute(FieldIdentifier) &&
|
if (ret == SQL_SUCCESS && CharacterAttribute != NULL && SQLColAttributes_KnownStringAttribute(FieldIdentifier) &&
|
||||||
StringLength && *StringLength != wcslen(CharacterAttribute) * 2)
|
StringLength && *StringLength != wcslen(CharacterAttribute) * 2)
|
||||||
|
|
|
@ -152,8 +152,42 @@ enum sql_funcs
|
||||||
unix_funcs_count
|
unix_funcs_count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bind_col_args
|
||||||
|
{
|
||||||
|
INT16 target_type;
|
||||||
|
void *target_value;
|
||||||
|
INT64 buffer_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bind_param_args
|
||||||
|
{
|
||||||
|
INT16 value_type;
|
||||||
|
INT16 parameter_type;
|
||||||
|
UINT64 length_precision;
|
||||||
|
INT16 parameter_scale;
|
||||||
|
void *parameter_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bind_parameter_args
|
||||||
|
{
|
||||||
|
INT16 input_output_type;
|
||||||
|
INT16 value_type;
|
||||||
|
INT16 parameter_type;
|
||||||
|
UINT64 column_size;
|
||||||
|
INT16 decimal_digits;
|
||||||
|
void *parameter_value;
|
||||||
|
INT64 buffer_length;
|
||||||
|
};
|
||||||
|
|
||||||
struct param
|
struct param
|
||||||
{
|
{
|
||||||
|
INT16 type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct bind_col_args col;
|
||||||
|
struct bind_param_args param;
|
||||||
|
struct bind_parameter_args parameter;
|
||||||
|
};
|
||||||
UINT8 *len; /* result length array stored in Unix lib */
|
UINT8 *len; /* result length array stored in Unix lib */
|
||||||
void *ptr; /* result length ptr passed by client */
|
void *ptr; /* result length ptr passed by client */
|
||||||
};
|
};
|
||||||
|
|
|
@ -335,16 +335,44 @@ static HRESULT convert_dbproperty_mode(const WCHAR *src, VARIANT *dest)
|
||||||
{ L"Write", DB_MODE_WRITE },
|
{ L"Write", DB_MODE_WRITE },
|
||||||
};
|
};
|
||||||
struct mode_propval *prop;
|
struct mode_propval *prop;
|
||||||
|
WCHAR mode[64];
|
||||||
|
WCHAR *pos = NULL;
|
||||||
|
const WCHAR *lastpos = src;
|
||||||
|
|
||||||
if ((prop = bsearch(src, mode_propvals, ARRAY_SIZE(mode_propvals),
|
V_VT(dest) = VT_I4;
|
||||||
sizeof(struct mode_propval), dbmodeprop_compare)))
|
V_I4(dest) = 0;
|
||||||
|
|
||||||
|
pos = wcschr(src, '|');
|
||||||
|
while (pos != NULL)
|
||||||
{
|
{
|
||||||
V_VT(dest) = VT_I4;
|
lstrcpynW(mode, lastpos, pos - lastpos + 1);
|
||||||
V_I4(dest) = prop->value;
|
|
||||||
TRACE("%s = %#lx\n", debugstr_w(src), prop->value);
|
if (!(prop = bsearch(mode, mode_propvals, ARRAY_SIZE(mode_propvals),
|
||||||
return S_OK;
|
sizeof(struct mode_propval), dbmodeprop_compare)))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
V_I4(dest) |= prop->value;
|
||||||
|
|
||||||
|
lastpos = pos + 1;
|
||||||
|
pos = wcschr(lastpos, '|');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lastpos)
|
||||||
|
{
|
||||||
|
lstrcpyW(mode, lastpos);
|
||||||
|
if (!(prop = bsearch(mode, mode_propvals, ARRAY_SIZE(mode_propvals),
|
||||||
|
sizeof(struct mode_propval), dbmodeprop_compare)))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
V_I4(dest) |= prop->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("%s = %#lx\n", debugstr_w(src), V_I4(dest));
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
done:
|
||||||
|
FIXME("Failed to parse Mode (%s)\n", debugstr_w(src));
|
||||||
|
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,6 +783,11 @@ HRESULT get_data_source(IUnknown *outer, DWORD clsctx, LPCOLESTR initstring, REF
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = IDBProperties_SetProperties(dbprops, 1, propset);
|
hr = IDBProperties_SetProperties(dbprops, 1, propset);
|
||||||
|
/* Return S_OK for any successful code. */
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
IDBProperties_Release(dbprops);
|
IDBProperties_Release(dbprops);
|
||||||
free_dbpropset(1, propset);
|
free_dbpropset(1, propset);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
|
|
|
@ -557,6 +557,8 @@ static void test_initializationstring(void)
|
||||||
static const WCHAR *initstring_mode = L"Provider=MSDASQL.1;Data Source=dummy;Mode=invalid";
|
static const WCHAR *initstring_mode = L"Provider=MSDASQL.1;Data Source=dummy;Mode=invalid";
|
||||||
static const WCHAR *initstring_mode2 = L"Provider=MSDASQL.1;Data Source=dummy;Mode=WriteRead";
|
static const WCHAR *initstring_mode2 = L"Provider=MSDASQL.1;Data Source=dummy;Mode=WriteRead";
|
||||||
static const WCHAR *initstring_mode3 = L"Provider=MSDASQL.1;Data Source=dummy;Mode=ReadWRITE";
|
static const WCHAR *initstring_mode3 = L"Provider=MSDASQL.1;Data Source=dummy;Mode=ReadWRITE";
|
||||||
|
static const WCHAR *initstring_mode4 = L"Provider=MSDASQL.1;Data Source=dummy;Mode=ReadWrite|Share Deny None";
|
||||||
|
static const WCHAR *initstring_mode5 = L"Provider=MSDASQL.1;Data Source=dummy;Mode=ReadWrite|Share Deny None|Share Exclusive";
|
||||||
static const WCHAR *initstring_quote_semicolon = L"Provider=MSDASQL.1;"
|
static const WCHAR *initstring_quote_semicolon = L"Provider=MSDASQL.1;"
|
||||||
"Data Source=dummy;"
|
"Data Source=dummy;"
|
||||||
"Extended Properties=\"ConnectTo=11.0;Cell Error Mode=TextValue;Optimize Response=3;\"";
|
"Extended Properties=\"ConnectTo=11.0;Cell Error Mode=TextValue;Optimize Response=3;\"";
|
||||||
|
@ -625,6 +627,18 @@ static void test_initializationstring(void)
|
||||||
&IID_IDBInitialize, (IUnknown **)&dbinit);
|
&IID_IDBInitialize, (IUnknown **)&dbinit);
|
||||||
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
||||||
IDBInitialize_Release(dbinit);
|
IDBInitialize_Release(dbinit);
|
||||||
|
|
||||||
|
dbinit = NULL;
|
||||||
|
hr = IDataInitialize_GetDataSource(datainit, NULL, CLSCTX_INPROC_SERVER, (WCHAR *)initstring_mode4,
|
||||||
|
&IID_IDBInitialize, (IUnknown **)&dbinit);
|
||||||
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
||||||
|
IDBInitialize_Release(dbinit);
|
||||||
|
|
||||||
|
dbinit = NULL;
|
||||||
|
hr = IDataInitialize_GetDataSource(datainit, NULL, CLSCTX_INPROC_SERVER, (WCHAR *)initstring_mode5,
|
||||||
|
&IID_IDBInitialize, (IUnknown **)&dbinit);
|
||||||
|
ok(hr == S_OK, "got 0x%08lx\n", hr);
|
||||||
|
IDBInitialize_Release(dbinit);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ok(dbinit == NULL, "got %p\n", dbinit);
|
ok(dbinit == NULL, "got %p\n", dbinit);
|
||||||
|
|
|
@ -181,6 +181,8 @@ my %manual_win_thunks =
|
||||||
"wglGetExtensionsStringARB" => 1,
|
"wglGetExtensionsStringARB" => 1,
|
||||||
"wglGetExtensionsStringEXT" => 1,
|
"wglGetExtensionsStringEXT" => 1,
|
||||||
"wglGetPixelFormat" => 1,
|
"wglGetPixelFormat" => 1,
|
||||||
|
"wglGetPixelFormatAttribfvARB" => 1,
|
||||||
|
"wglGetPixelFormatAttribivARB" => 1,
|
||||||
"wglGetProcAddress" => 1,
|
"wglGetProcAddress" => 1,
|
||||||
"wglQueryCurrentRendererStringWINE" => 1,
|
"wglQueryCurrentRendererStringWINE" => 1,
|
||||||
"wglQueryRendererStringWINE" => 1,
|
"wglQueryRendererStringWINE" => 1,
|
||||||
|
@ -884,6 +886,31 @@ print HEADER "struct wgl_pbuffer;\n\n";
|
||||||
print HEADER "struct wgl_pixel_format\n";
|
print HEADER "struct wgl_pixel_format\n";
|
||||||
print HEADER "{\n";
|
print HEADER "{\n";
|
||||||
print HEADER " PIXELFORMATDESCRIPTOR pfd;\n";
|
print HEADER " PIXELFORMATDESCRIPTOR pfd;\n";
|
||||||
|
print HEADER " int swap_method;\n";
|
||||||
|
print HEADER " int transparent;\n";
|
||||||
|
print HEADER " int pixel_type;\n";
|
||||||
|
print HEADER " int draw_to_pbuffer;\n";
|
||||||
|
print HEADER " int max_pbuffer_pixels;\n";
|
||||||
|
print HEADER " int max_pbuffer_width;\n";
|
||||||
|
print HEADER " int max_pbuffer_height;\n";
|
||||||
|
print HEADER " int transparent_red_value;\n";
|
||||||
|
print HEADER " int transparent_red_value_valid;\n";
|
||||||
|
print HEADER " int transparent_green_value;\n";
|
||||||
|
print HEADER " int transparent_green_value_valid;\n";
|
||||||
|
print HEADER " int transparent_blue_value;\n";
|
||||||
|
print HEADER " int transparent_blue_value_valid;\n";
|
||||||
|
print HEADER " int transparent_alpha_value;\n";
|
||||||
|
print HEADER " int transparent_alpha_value_valid;\n";
|
||||||
|
print HEADER " int transparent_index_value;\n";
|
||||||
|
print HEADER " int transparent_index_value_valid;\n";
|
||||||
|
print HEADER " int sample_buffers;\n";
|
||||||
|
print HEADER " int samples;\n";
|
||||||
|
print HEADER " int bind_to_texture_rgb;\n";
|
||||||
|
print HEADER " int bind_to_texture_rgba;\n";
|
||||||
|
print HEADER " int bind_to_texture_rectangle_rgb;\n";
|
||||||
|
print HEADER " int bind_to_texture_rectangle_rgba;\n";
|
||||||
|
print HEADER " int framebuffer_srgb_capable;\n";
|
||||||
|
print HEADER " int float_components;\n";
|
||||||
print HEADER "};\n\n";
|
print HEADER "};\n\n";
|
||||||
|
|
||||||
print HEADER "struct opengl_funcs\n{\n";
|
print HEADER "struct opengl_funcs\n{\n";
|
||||||
|
|
|
@ -24217,24 +24217,6 @@ static HDC WINAPI wglGetPbufferDCARB( HPBUFFERARB hPbuffer )
|
||||||
return args.ret;
|
return args.ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL WINAPI wglGetPixelFormatAttribfvARB( HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues )
|
|
||||||
{
|
|
||||||
struct wglGetPixelFormatAttribfvARB_params args = { .teb = NtCurrentTeb(), .hdc = hdc, .iPixelFormat = iPixelFormat, .iLayerPlane = iLayerPlane, .nAttributes = nAttributes, .piAttributes = piAttributes, .pfValues = pfValues };
|
|
||||||
NTSTATUS status;
|
|
||||||
TRACE( "hdc %p, iPixelFormat %d, iLayerPlane %d, nAttributes %u, piAttributes %p, pfValues %p\n", hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues );
|
|
||||||
if ((status = UNIX_CALL( wglGetPixelFormatAttribfvARB, &args ))) WARN( "wglGetPixelFormatAttribfvARB returned %#lx\n", status );
|
|
||||||
return args.ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL WINAPI wglGetPixelFormatAttribivARB( HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues )
|
|
||||||
{
|
|
||||||
struct wglGetPixelFormatAttribivARB_params args = { .teb = NtCurrentTeb(), .hdc = hdc, .iPixelFormat = iPixelFormat, .iLayerPlane = iLayerPlane, .nAttributes = nAttributes, .piAttributes = piAttributes, .piValues = piValues };
|
|
||||||
NTSTATUS status;
|
|
||||||
TRACE( "hdc %p, iPixelFormat %d, iLayerPlane %d, nAttributes %u, piAttributes %p, piValues %p\n", hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues );
|
|
||||||
if ((status = UNIX_CALL( wglGetPixelFormatAttribivARB, &args ))) WARN( "wglGetPixelFormatAttribivARB returned %#lx\n", status );
|
|
||||||
return args.ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int WINAPI wglGetSwapIntervalEXT(void)
|
static int WINAPI wglGetSwapIntervalEXT(void)
|
||||||
{
|
{
|
||||||
struct wglGetSwapIntervalEXT_params args = { .teb = NtCurrentTeb() };
|
struct wglGetSwapIntervalEXT_params args = { .teb = NtCurrentTeb() };
|
||||||
|
@ -24340,6 +24322,8 @@ extern GLboolean WINAPI glUnmapNamedBufferEXT( GLuint buffer );
|
||||||
extern HDC WINAPI wglGetCurrentReadDCARB(void);
|
extern HDC WINAPI wglGetCurrentReadDCARB(void);
|
||||||
extern const char * WINAPI wglGetExtensionsStringARB( HDC hdc );
|
extern const char * WINAPI wglGetExtensionsStringARB( HDC hdc );
|
||||||
extern const char * WINAPI wglGetExtensionsStringEXT(void);
|
extern const char * WINAPI wglGetExtensionsStringEXT(void);
|
||||||
|
extern BOOL WINAPI wglGetPixelFormatAttribfvARB( HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues );
|
||||||
|
extern BOOL WINAPI wglGetPixelFormatAttribivARB( HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues );
|
||||||
extern const GLchar * WINAPI wglQueryCurrentRendererStringWINE( GLenum attribute );
|
extern const GLchar * WINAPI wglQueryCurrentRendererStringWINE( GLenum attribute );
|
||||||
extern const GLchar * WINAPI wglQueryRendererStringWINE( HDC dc, GLint renderer, GLenum attribute );
|
extern const GLchar * WINAPI wglQueryRendererStringWINE( HDC dc, GLint renderer, GLenum attribute );
|
||||||
const void *extension_procs[] =
|
const void *extension_procs[] =
|
||||||
|
|
|
@ -322,7 +322,9 @@ static struct wgl_pixel_format *get_pixel_formats( HDC hdc, UINT *num_formats,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status = UNIX_CALL( get_pixel_formats, &args ))) goto error;
|
if ((status = UNIX_CALL( get_pixel_formats, &args ))) goto error;
|
||||||
if (!(args.formats = malloc( sizeof(*args.formats) * args.num_formats ))) goto error;
|
/* Clear formats memory since not all drivers deal with all wgl_pixel_format
|
||||||
|
* fields at the moment. */
|
||||||
|
if (!(args.formats = calloc( args.num_formats, sizeof(*args.formats) ))) goto error;
|
||||||
args.max_formats = args.num_formats;
|
args.max_formats = args.num_formats;
|
||||||
if ((status = UNIX_CALL( get_pixel_formats, &args ))) goto error;
|
if ((status = UNIX_CALL( get_pixel_formats, &args ))) goto error;
|
||||||
|
|
||||||
|
@ -343,6 +345,153 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL wgl_attrib_uses_layer( int attrib )
|
||||||
|
{
|
||||||
|
switch (attrib)
|
||||||
|
{
|
||||||
|
case WGL_ACCELERATION_ARB:
|
||||||
|
case WGL_TRANSPARENT_ARB:
|
||||||
|
case WGL_SHARE_DEPTH_ARB:
|
||||||
|
case WGL_SHARE_STENCIL_ARB:
|
||||||
|
case WGL_SHARE_ACCUM_ARB:
|
||||||
|
case WGL_TRANSPARENT_RED_VALUE_ARB:
|
||||||
|
case WGL_TRANSPARENT_GREEN_VALUE_ARB:
|
||||||
|
case WGL_TRANSPARENT_BLUE_VALUE_ARB:
|
||||||
|
case WGL_TRANSPARENT_ALPHA_VALUE_ARB:
|
||||||
|
case WGL_TRANSPARENT_INDEX_VALUE_ARB:
|
||||||
|
case WGL_SUPPORT_GDI_ARB:
|
||||||
|
case WGL_SUPPORT_OPENGL_ARB:
|
||||||
|
case WGL_DOUBLE_BUFFER_ARB:
|
||||||
|
case WGL_STEREO_ARB:
|
||||||
|
case WGL_PIXEL_TYPE_ARB:
|
||||||
|
case WGL_COLOR_BITS_ARB:
|
||||||
|
case WGL_RED_BITS_ARB:
|
||||||
|
case WGL_RED_SHIFT_ARB:
|
||||||
|
case WGL_GREEN_BITS_ARB:
|
||||||
|
case WGL_GREEN_SHIFT_ARB:
|
||||||
|
case WGL_BLUE_BITS_ARB:
|
||||||
|
case WGL_BLUE_SHIFT_ARB:
|
||||||
|
case WGL_ALPHA_BITS_ARB:
|
||||||
|
case WGL_ALPHA_SHIFT_ARB:
|
||||||
|
case WGL_ACCUM_BITS_ARB:
|
||||||
|
case WGL_ACCUM_RED_BITS_ARB:
|
||||||
|
case WGL_ACCUM_GREEN_BITS_ARB:
|
||||||
|
case WGL_ACCUM_BLUE_BITS_ARB:
|
||||||
|
case WGL_ACCUM_ALPHA_BITS_ARB:
|
||||||
|
case WGL_DEPTH_BITS_ARB:
|
||||||
|
case WGL_STENCIL_BITS_ARB:
|
||||||
|
case WGL_AUX_BUFFERS_ARB:
|
||||||
|
case WGL_SAMPLE_BUFFERS_ARB:
|
||||||
|
case WGL_SAMPLES_ARB:
|
||||||
|
case WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB:
|
||||||
|
case WGL_FLOAT_COMPONENTS_NV:
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL wgl_pixel_format_get_attrib( const struct wgl_pixel_format *fmt, int attrib, int *value )
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
int valid = -1;
|
||||||
|
|
||||||
|
switch (attrib)
|
||||||
|
{
|
||||||
|
case WGL_DRAW_TO_WINDOW_ARB: val = !!(fmt->pfd.dwFlags & PFD_DRAW_TO_WINDOW); break;
|
||||||
|
case WGL_DRAW_TO_BITMAP_ARB: val = !!(fmt->pfd.dwFlags & PFD_DRAW_TO_BITMAP); break;
|
||||||
|
case WGL_ACCELERATION_ARB:
|
||||||
|
if (fmt->pfd.dwFlags & PFD_GENERIC_ACCELERATED)
|
||||||
|
val = WGL_GENERIC_ACCELERATION_ARB;
|
||||||
|
else if (fmt->pfd.dwFlags & PFD_GENERIC_FORMAT)
|
||||||
|
val = WGL_NO_ACCELERATION_ARB;
|
||||||
|
else
|
||||||
|
val = WGL_FULL_ACCELERATION_ARB;
|
||||||
|
break;
|
||||||
|
case WGL_NEED_PALETTE_ARB: val = !!(fmt->pfd.dwFlags & PFD_NEED_PALETTE); break;
|
||||||
|
case WGL_NEED_SYSTEM_PALETTE_ARB: val = !!(fmt->pfd.dwFlags & PFD_NEED_SYSTEM_PALETTE); break;
|
||||||
|
case WGL_SWAP_LAYER_BUFFERS_ARB: val = !!(fmt->pfd.dwFlags & PFD_SWAP_LAYER_BUFFERS); break;
|
||||||
|
case WGL_SWAP_METHOD_ARB: val = fmt->swap_method; break;
|
||||||
|
case WGL_NUMBER_OVERLAYS_ARB:
|
||||||
|
case WGL_NUMBER_UNDERLAYS_ARB:
|
||||||
|
/* We don't support any overlays/underlays. */
|
||||||
|
val = 0;
|
||||||
|
break;
|
||||||
|
case WGL_TRANSPARENT_ARB: val = fmt->transparent; break;
|
||||||
|
case WGL_SHARE_DEPTH_ARB:
|
||||||
|
case WGL_SHARE_STENCIL_ARB:
|
||||||
|
case WGL_SHARE_ACCUM_ARB:
|
||||||
|
/* We support only a main plane at the moment which by definition
|
||||||
|
* shares the depth/stencil/accum buffers with itself. */
|
||||||
|
val = GL_TRUE;
|
||||||
|
break;
|
||||||
|
case WGL_SUPPORT_GDI_ARB: val = !!(fmt->pfd.dwFlags & PFD_SUPPORT_GDI); break;
|
||||||
|
case WGL_SUPPORT_OPENGL_ARB: val = !!(fmt->pfd.dwFlags & PFD_SUPPORT_OPENGL); break;
|
||||||
|
case WGL_DOUBLE_BUFFER_ARB: val = !!(fmt->pfd.dwFlags & PFD_DOUBLEBUFFER); break;
|
||||||
|
case WGL_STEREO_ARB: val = !!(fmt->pfd.dwFlags & PFD_STEREO); break;
|
||||||
|
case WGL_PIXEL_TYPE_ARB: val = fmt->pixel_type; break;
|
||||||
|
case WGL_COLOR_BITS_ARB: val = fmt->pfd.cColorBits; break;
|
||||||
|
case WGL_RED_BITS_ARB: val = fmt->pfd.cRedBits; break;
|
||||||
|
case WGL_RED_SHIFT_ARB: val = fmt->pfd.cRedShift; break;
|
||||||
|
case WGL_GREEN_BITS_ARB: val = fmt->pfd.cGreenBits; break;
|
||||||
|
case WGL_GREEN_SHIFT_ARB: val = fmt->pfd.cGreenShift; break;
|
||||||
|
case WGL_BLUE_BITS_ARB: val = fmt->pfd.cBlueBits; break;
|
||||||
|
case WGL_BLUE_SHIFT_ARB: val = fmt->pfd.cBlueShift; break;
|
||||||
|
case WGL_ALPHA_BITS_ARB: val = fmt->pfd.cAlphaBits; break;
|
||||||
|
case WGL_ALPHA_SHIFT_ARB: val = fmt->pfd.cAlphaShift; break;
|
||||||
|
case WGL_ACCUM_BITS_ARB: val = fmt->pfd.cAccumBits; break;
|
||||||
|
case WGL_ACCUM_RED_BITS_ARB: val = fmt->pfd.cAccumRedBits; break;
|
||||||
|
case WGL_ACCUM_GREEN_BITS_ARB: val = fmt->pfd.cAccumGreenBits; break;
|
||||||
|
case WGL_ACCUM_BLUE_BITS_ARB: val = fmt->pfd.cAccumBlueBits; break;
|
||||||
|
case WGL_ACCUM_ALPHA_BITS_ARB: val = fmt->pfd.cAccumAlphaBits; break;
|
||||||
|
case WGL_DEPTH_BITS_ARB: val = fmt->pfd.cDepthBits; break;
|
||||||
|
case WGL_STENCIL_BITS_ARB: val = fmt->pfd.cStencilBits; break;
|
||||||
|
case WGL_AUX_BUFFERS_ARB: val = fmt->pfd.cAuxBuffers; break;
|
||||||
|
case WGL_DRAW_TO_PBUFFER_ARB: val = fmt->draw_to_pbuffer; break;
|
||||||
|
case WGL_MAX_PBUFFER_PIXELS_ARB: val = fmt->max_pbuffer_pixels; break;
|
||||||
|
case WGL_MAX_PBUFFER_WIDTH_ARB: val = fmt->max_pbuffer_width; break;
|
||||||
|
case WGL_MAX_PBUFFER_HEIGHT_ARB: val = fmt->max_pbuffer_height; break;
|
||||||
|
case WGL_TRANSPARENT_RED_VALUE_ARB:
|
||||||
|
val = fmt->transparent_red_value;
|
||||||
|
valid = !!fmt->transparent_red_value_valid;
|
||||||
|
break;
|
||||||
|
case WGL_TRANSPARENT_GREEN_VALUE_ARB:
|
||||||
|
val = fmt->transparent_green_value;
|
||||||
|
valid = !!fmt->transparent_green_value_valid;
|
||||||
|
break;
|
||||||
|
case WGL_TRANSPARENT_BLUE_VALUE_ARB:
|
||||||
|
val = fmt->transparent_blue_value;
|
||||||
|
valid = !!fmt->transparent_blue_value_valid;
|
||||||
|
break;
|
||||||
|
case WGL_TRANSPARENT_ALPHA_VALUE_ARB:
|
||||||
|
val = fmt->transparent_alpha_value;
|
||||||
|
valid = !!fmt->transparent_alpha_value_valid;
|
||||||
|
break;
|
||||||
|
case WGL_TRANSPARENT_INDEX_VALUE_ARB:
|
||||||
|
val = fmt->transparent_index_value;
|
||||||
|
valid = !!fmt->transparent_index_value_valid;
|
||||||
|
break;
|
||||||
|
case WGL_SAMPLE_BUFFERS_ARB: val = fmt->sample_buffers; break;
|
||||||
|
case WGL_SAMPLES_ARB: val = fmt->samples; break;
|
||||||
|
case WGL_BIND_TO_TEXTURE_RGB_ARB: val = fmt->bind_to_texture_rgb; break;
|
||||||
|
case WGL_BIND_TO_TEXTURE_RGBA_ARB: val = fmt->bind_to_texture_rgba; break;
|
||||||
|
case WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV: val = fmt->bind_to_texture_rectangle_rgb; break;
|
||||||
|
case WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV: val = fmt->bind_to_texture_rectangle_rgba; break;
|
||||||
|
case WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB: val = fmt->framebuffer_srgb_capable; break;
|
||||||
|
case WGL_FLOAT_COMPONENTS_NV: val = fmt->float_components; break;
|
||||||
|
default:
|
||||||
|
FIXME( "unsupported 0x%x WGL attribute\n", attrib );
|
||||||
|
valid = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we haven't already determined validity, use the default check */
|
||||||
|
if (valid == -1) valid = val != -1;
|
||||||
|
if (valid) *value = val;
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
INT WINAPI wglDescribePixelFormat( HDC hdc, int index, UINT size, PIXELFORMATDESCRIPTOR *ppfd )
|
INT WINAPI wglDescribePixelFormat( HDC hdc, int index, UINT size, PIXELFORMATDESCRIPTOR *ppfd )
|
||||||
{
|
{
|
||||||
struct wgl_pixel_format *formats;
|
struct wgl_pixel_format *formats;
|
||||||
|
@ -360,6 +509,102 @@ INT WINAPI wglDescribePixelFormat( HDC hdc, int index, UINT size, PIXELFORMATDES
|
||||||
return num_onscreen_formats;
|
return num_onscreen_formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* wglGetPixelFormatAttribivARB (OPENGL32.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI wglGetPixelFormatAttribivARB( HDC hdc, int index, int plane, UINT count,
|
||||||
|
const int *attributes, int *values )
|
||||||
|
{
|
||||||
|
static const DWORD invalid_data_error = 0xC007000D;
|
||||||
|
struct wgl_pixel_format *formats;
|
||||||
|
UINT i, num_formats, num_onscreen_formats;
|
||||||
|
|
||||||
|
TRACE( "hdc %p, index %d, plane %d, count %u, attributes %p, values %p\n",
|
||||||
|
hdc, index, plane, count, attributes, values );
|
||||||
|
|
||||||
|
formats = get_pixel_formats( hdc, &num_formats, &num_onscreen_formats );
|
||||||
|
|
||||||
|
/* If the driver doesn't yet provide ARB attrib information in
|
||||||
|
* wgl_pixel_format, fall back to an explicit call. */
|
||||||
|
if (num_formats && !formats[0].pixel_type)
|
||||||
|
{
|
||||||
|
struct wglGetPixelFormatAttribivARB_params args =
|
||||||
|
{
|
||||||
|
.teb = NtCurrentTeb(),
|
||||||
|
.hdc = hdc,
|
||||||
|
.iPixelFormat = index,
|
||||||
|
.iLayerPlane = plane,
|
||||||
|
.nAttributes = count,
|
||||||
|
.piAttributes = attributes,
|
||||||
|
.piValues = values
|
||||||
|
};
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if ((status = UNIX_CALL( wglGetPixelFormatAttribivARB, &args )))
|
||||||
|
WARN( "wglGetPixelFormatAttribivARB returned %#lx\n", status );
|
||||||
|
|
||||||
|
return args.ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!count) return TRUE;
|
||||||
|
if (count == 1 && attributes[0] == WGL_NUMBER_PIXEL_FORMATS_ARB)
|
||||||
|
{
|
||||||
|
values[0] = num_formats;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
if (index <= 0 || index > num_formats)
|
||||||
|
{
|
||||||
|
SetLastError( invalid_data_error );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
int attrib = attributes[i];
|
||||||
|
|
||||||
|
if (attrib == WGL_NUMBER_PIXEL_FORMATS_ARB)
|
||||||
|
{
|
||||||
|
values[i] = num_formats;
|
||||||
|
}
|
||||||
|
else if ((plane != 0 && wgl_attrib_uses_layer( attrib )) ||
|
||||||
|
!wgl_pixel_format_get_attrib( &formats[index - 1], attrib, &values[i] ))
|
||||||
|
{
|
||||||
|
SetLastError( invalid_data_error );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* wglGetPixelFormatAttribfvARB (OPENGL32.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI wglGetPixelFormatAttribfvARB( HDC hdc, int index, int plane, UINT count,
|
||||||
|
const int *attributes, FLOAT *values )
|
||||||
|
{
|
||||||
|
int *ivalues;
|
||||||
|
BOOL ret;
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
TRACE( "hdc %p, index %d, plane %d, count %u, attributes %p, values %p\n",
|
||||||
|
hdc, index, plane, count, attributes, values );
|
||||||
|
|
||||||
|
if (!(ivalues = malloc( count * sizeof(int) ))) return FALSE;
|
||||||
|
|
||||||
|
/* For now we can piggy-back on wglGetPixelFormatAttribivARB, since we don't support
|
||||||
|
* any non-integer attributes. */
|
||||||
|
ret = wglGetPixelFormatAttribivARB( hdc, index, plane, count, attributes, ivalues );
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
values[i] = ivalues[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
free( ivalues );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* wglGetPixelFormat (OPENGL32.@)
|
* wglGetPixelFormat (OPENGL32.@)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -48,6 +48,8 @@ struct avi_decompressor
|
||||||
|
|
||||||
HIC hvid;
|
HIC hvid;
|
||||||
BITMAPINFOHEADER* pBihIn;
|
BITMAPINFOHEADER* pBihIn;
|
||||||
|
|
||||||
|
CRITICAL_SECTION late_cs;
|
||||||
REFERENCE_TIME late;
|
REFERENCE_TIME late;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,7 +79,9 @@ static HRESULT avi_decompressor_sink_query_accept(struct strmbase_pin *iface, co
|
||||||
static HRESULT avi_decompressor_sink_end_flush(struct strmbase_sink *iface)
|
static HRESULT avi_decompressor_sink_end_flush(struct strmbase_sink *iface)
|
||||||
{
|
{
|
||||||
struct avi_decompressor *filter = impl_from_strmbase_filter(iface->pin.filter);
|
struct avi_decompressor *filter = impl_from_strmbase_filter(iface->pin.filter);
|
||||||
|
EnterCriticalSection(&filter->late_cs);
|
||||||
filter->late = -1;
|
filter->late = -1;
|
||||||
|
LeaveCriticalSection(&filter->late_cs);
|
||||||
if (filter->source.pin.peer)
|
if (filter->source.pin.peer)
|
||||||
return IPin_EndFlush(filter->source.pin.peer);
|
return IPin_EndFlush(filter->source.pin.peer);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
@ -167,8 +171,10 @@ static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface,
|
||||||
if (IMediaSample_IsSyncPoint(pSample) != S_OK)
|
if (IMediaSample_IsSyncPoint(pSample) != S_OK)
|
||||||
flags |= ICDECOMPRESS_NOTKEYFRAME;
|
flags |= ICDECOMPRESS_NOTKEYFRAME;
|
||||||
hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
|
hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
|
||||||
|
EnterCriticalSection(&This->late_cs);
|
||||||
if (hr == S_OK && AVIDec_DropSample(This, tStart))
|
if (hr == S_OK && AVIDec_DropSample(This, tStart))
|
||||||
flags |= ICDECOMPRESS_HURRYUP;
|
flags |= ICDECOMPRESS_HURRYUP;
|
||||||
|
LeaveCriticalSection(&This->late_cs);
|
||||||
|
|
||||||
res = ICDecompress(This->hvid, flags, This->pBihIn, pbSrcStream, &source_format->bmiHeader, pbDstStream);
|
res = ICDecompress(This->hvid, flags, This->pBihIn, pbSrcStream, &source_format->bmiHeader, pbDstStream);
|
||||||
if (res != ICERR_OK)
|
if (res != ICERR_OK)
|
||||||
|
@ -482,12 +488,13 @@ static HRESULT WINAPI avi_decompressor_source_qc_Notify(IQualityControl *iface,
|
||||||
TRACE("filter %p, sender %p, type %#x, proportion %ld, late %s, timestamp %s.\n",
|
TRACE("filter %p, sender %p, type %#x, proportion %ld, late %s, timestamp %s.\n",
|
||||||
filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp));
|
filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp));
|
||||||
|
|
||||||
EnterCriticalSection(&filter->filter.stream_cs);
|
/* can't take the stream CS here, Submarine Titans calls this function from a foreign thread while inside sink_Receive */
|
||||||
|
EnterCriticalSection(&filter->late_cs);
|
||||||
if (q.Late > 0)
|
if (q.Late > 0)
|
||||||
filter->late = q.Late + q.TimeStamp;
|
filter->late = q.Late + q.TimeStamp;
|
||||||
else
|
else
|
||||||
filter->late = -1;
|
filter->late = -1;
|
||||||
LeaveCriticalSection(&filter->filter.stream_cs);
|
LeaveCriticalSection(&filter->late_cs);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,6 +539,9 @@ static void avi_decompressor_destroy(struct strmbase_filter *iface)
|
||||||
IPin_Disconnect(filter->source.pin.peer);
|
IPin_Disconnect(filter->source.pin.peer);
|
||||||
IPin_Disconnect(&filter->source.pin.IPin_iface);
|
IPin_Disconnect(&filter->source.pin.IPin_iface);
|
||||||
|
|
||||||
|
filter->late_cs.DebugInfo->Spare[0] = 0;
|
||||||
|
DeleteCriticalSection(&filter->late_cs);
|
||||||
|
|
||||||
strmbase_sink_cleanup(&filter->sink);
|
strmbase_sink_cleanup(&filter->sink);
|
||||||
strmbase_source_cleanup(&filter->source);
|
strmbase_source_cleanup(&filter->source);
|
||||||
strmbase_passthrough_cleanup(&filter->passthrough);
|
strmbase_passthrough_cleanup(&filter->passthrough);
|
||||||
|
@ -550,7 +560,9 @@ static HRESULT avi_decompressor_init_stream(struct strmbase_filter *iface)
|
||||||
if (!filter->source.pin.peer)
|
if (!filter->source.pin.peer)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
|
EnterCriticalSection(&filter->late_cs);
|
||||||
filter->late = -1;
|
filter->late = -1;
|
||||||
|
LeaveCriticalSection(&filter->late_cs);
|
||||||
|
|
||||||
source_format = (VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat;
|
source_format = (VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat;
|
||||||
if ((res = ICDecompressBegin(filter->hvid, filter->pBihIn, &source_format->bmiHeader)))
|
if ((res = ICDecompressBegin(filter->hvid, filter->pBihIn, &source_format->bmiHeader)))
|
||||||
|
@ -618,6 +630,9 @@ HRESULT avi_dec_create(IUnknown *outer, IUnknown **out)
|
||||||
ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, FALSE,
|
ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, FALSE,
|
||||||
&object->sink.pin.IPin_iface);
|
&object->sink.pin.IPin_iface);
|
||||||
|
|
||||||
|
InitializeCriticalSectionEx(&object->late_cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
|
||||||
|
object->late_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": object.late_cs");
|
||||||
|
|
||||||
TRACE("Created AVI decompressor %p.\n", object);
|
TRACE("Created AVI decompressor %p.\n", object);
|
||||||
*out = &object->filter.IUnknown_inner;
|
*out = &object->filter.IUnknown_inner;
|
||||||
|
|
||||||
|
|
|
@ -873,6 +873,20 @@ static HRESULT testsink_connect(struct strmbase_sink *iface, IPin *peer, const A
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DWORD WINAPI call_qc_notify(void *ptr)
|
||||||
|
{
|
||||||
|
struct testfilter *filter = ptr;
|
||||||
|
IQualityControl *qc;
|
||||||
|
Quality q = { Famine, 2000, -10000000, 10000000 };
|
||||||
|
|
||||||
|
IPin_QueryInterface(filter->sink.pin.peer, &IID_IQualityControl, (void**)&qc);
|
||||||
|
/* don't worry too much about what it returns, just check that it doesn't deadlock */
|
||||||
|
IQualityControl_Notify(qc, &filter->filter.IBaseFilter_iface, q);
|
||||||
|
IQualityControl_Release(qc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample)
|
static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample)
|
||||||
{
|
{
|
||||||
struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter);
|
struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter);
|
||||||
|
@ -920,6 +934,13 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample
|
||||||
hr = IMediaSample_IsSyncPoint(sample);
|
hr = IMediaSample_IsSyncPoint(sample);
|
||||||
todo_wine_if (testmode == 5 || testmode == 6) ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
todo_wine_if (testmode == 5 || testmode == 6) ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
if (testmode == 7)
|
||||||
|
{
|
||||||
|
HANDLE h = CreateThread(NULL, 0, call_qc_notify, filter, 0, NULL);
|
||||||
|
ok(WaitForSingleObject(h, 1000) == WAIT_OBJECT_0, "Didn't expect deadlock.\n");
|
||||||
|
CloseHandle(h);
|
||||||
|
}
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1129,6 +1150,15 @@ static void test_sample_processing(IMediaControl *control, IMemInputPin *input,
|
||||||
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||||
todo_wine ok(!sink->got_sample, "Got %u calls to Receive().\n", sink->got_sample);
|
todo_wine ok(!sink->got_sample, "Got %u calls to Receive().\n", sink->got_sample);
|
||||||
|
|
||||||
|
testmode = 7;
|
||||||
|
hr = IMediaSample_SetSyncPoint(sample, TRUE);
|
||||||
|
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||||
|
sink->got_sample = 0;
|
||||||
|
hr = IMemInputPin_Receive(input, sample);
|
||||||
|
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||||
|
ok(sink->got_sample == 1, "Got %u calls to Receive().\n", sink->got_sample);
|
||||||
|
sink->got_sample = 0;
|
||||||
|
|
||||||
hr = IMediaControl_Stop(control);
|
hr = IMediaControl_Stop(control);
|
||||||
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||||
|
|
||||||
|
@ -1174,7 +1204,7 @@ static void test_streaming_events(IMediaControl *control, IPin *sink,
|
||||||
ok(!testsink->got_eos, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos);
|
ok(!testsink->got_eos, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos);
|
||||||
hr = IPin_EndOfStream(sink);
|
hr = IPin_EndOfStream(sink);
|
||||||
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||||
todo_wine ok(!testsink->got_sample, "Got %u calls to Receive().\n", testsink->got_sample);
|
ok(!testsink->got_sample, "Got %u calls to Receive().\n", testsink->got_sample);
|
||||||
ok(testsink->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos);
|
ok(testsink->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos);
|
||||||
testsink->got_eos = 0;
|
testsink->got_eos = 0;
|
||||||
|
|
||||||
|
@ -1185,7 +1215,7 @@ static void test_streaming_events(IMediaControl *control, IPin *sink,
|
||||||
testmode = 0;
|
testmode = 0;
|
||||||
hr = IMemInputPin_Receive(input, sample);
|
hr = IMemInputPin_Receive(input, sample);
|
||||||
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||||
todo_wine ok(testsink->got_sample == 1, "Got %u calls to Receive().\n", testsink->got_sample);
|
ok(testsink->got_sample == 1, "Got %u calls to Receive().\n", testsink->got_sample);
|
||||||
testsink->got_sample = 0;
|
testsink->got_sample = 0;
|
||||||
|
|
||||||
ok(!testsink->got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink->got_begin_flush);
|
ok(!testsink->got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink->got_begin_flush);
|
||||||
|
|
|
@ -1677,9 +1677,9 @@ static void test_seeking(void)
|
||||||
ok(ret, "Failed to delete file, error %lu.\n", GetLastError());
|
ok(ret, "Failed to delete file, error %lu.\n", GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_streaming(void)
|
static void test_streaming(const WCHAR *resname)
|
||||||
{
|
{
|
||||||
const WCHAR *filename = load_resource(L"test.avi");
|
const WCHAR *filename = load_resource(resname);
|
||||||
IBaseFilter *filter = create_avi_splitter();
|
IBaseFilter *filter = create_avi_splitter();
|
||||||
IFilterGraph2 *graph = connect_input(filter, filename);
|
IFilterGraph2 *graph = connect_input(filter, filename);
|
||||||
struct testfilter testsink;
|
struct testfilter testsink;
|
||||||
|
@ -1691,6 +1691,8 @@ static void test_streaming(void)
|
||||||
ULONG ref;
|
ULONG ref;
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
|
|
||||||
|
winetest_push_context("File %ls", resname);
|
||||||
|
|
||||||
testfilter_init(&testsink);
|
testfilter_init(&testsink);
|
||||||
IFilterGraph2_AddFilter(graph, &testsink.filter.IBaseFilter_iface, L"sink");
|
IFilterGraph2_AddFilter(graph, &testsink.filter.IBaseFilter_iface, L"sink");
|
||||||
IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
|
IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
|
||||||
|
@ -1761,6 +1763,8 @@ static void test_streaming(void)
|
||||||
ok(!ref, "Got outstanding refcount %ld.\n", ref);
|
ok(!ref, "Got outstanding refcount %ld.\n", ref);
|
||||||
ret = DeleteFileW(filename);
|
ret = DeleteFileW(filename);
|
||||||
ok(ret, "Failed to delete file, error %lu.\n", GetLastError());
|
ok(ret, "Failed to delete file, error %lu.\n", GetLastError());
|
||||||
|
|
||||||
|
winetest_pop_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
START_TEST(avisplit)
|
START_TEST(avisplit)
|
||||||
|
@ -1787,7 +1791,8 @@ START_TEST(avisplit)
|
||||||
test_unconnected_filter_state();
|
test_unconnected_filter_state();
|
||||||
test_connect_pin();
|
test_connect_pin();
|
||||||
test_seeking();
|
test_seeking();
|
||||||
test_streaming();
|
test_streaming(L"test.avi");
|
||||||
|
test_streaming(L"test_cinepak.avi");
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,3 +39,7 @@ test.wav RCDATA "test.wav"
|
||||||
/* ffmpeg -f lavfi -i smptebars -f lavfi -i "sine=frequency=1000" -t 2.04 -r 25 -f mpeg -vcodec mpeg1video -vf scale=64x48 -acodec mp2 -ar 32k -ab 96k test2.mpg */
|
/* ffmpeg -f lavfi -i smptebars -f lavfi -i "sine=frequency=1000" -t 2.04 -r 25 -f mpeg -vcodec mpeg1video -vf scale=64x48 -acodec mp2 -ar 32k -ab 96k test2.mpg */
|
||||||
/* @makedep: test2.mpg */
|
/* @makedep: test2.mpg */
|
||||||
test2.mpg RCDATA "test2.mpg"
|
test2.mpg RCDATA "test2.mpg"
|
||||||
|
|
||||||
|
/* ffmpeg -f lavfi -i smptebars -t 5 -r 1 -f avi -vcodec cinepak -pix_fmt rgb24 -vf scale=32x24 test_cinepak.avi */
|
||||||
|
/* @makedep: test_cinepak.avi */
|
||||||
|
test_cinepak.avi RCDATA "test_cinepak.avi"
|
||||||
|
|
BIN
dlls/quartz/tests/test_cinepak.avi
Normal file
BIN
dlls/quartz/tests/test_cinepak.avi
Normal file
Binary file not shown.
|
@ -28,6 +28,7 @@
|
||||||
#define WIN32_NO_STATUS
|
#define WIN32_NO_STATUS
|
||||||
#include "ntgdi_private.h"
|
#include "ntgdi_private.h"
|
||||||
#include "win32u_private.h"
|
#include "win32u_private.h"
|
||||||
|
#include "ntuser_private.h"
|
||||||
#include "wine/vulkan.h"
|
#include "wine/vulkan.h"
|
||||||
#include "wine/vulkan_driver.h"
|
#include "wine/vulkan_driver.h"
|
||||||
|
|
||||||
|
@ -83,13 +84,13 @@ static void d3dkmt_init_vulkan(void)
|
||||||
PFN_vkCreateInstance p_vkCreateInstance;
|
PFN_vkCreateInstance p_vkCreateInstance;
|
||||||
VkResult vr;
|
VkResult vr;
|
||||||
|
|
||||||
if (!(vulkan_funcs = __wine_get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION )))
|
if (!vulkan_init())
|
||||||
{
|
{
|
||||||
WARN( "Failed to open the Vulkan driver\n" );
|
WARN( "Failed to open the Vulkan driver\n" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_vkCreateInstance = vulkan_funcs->p_vkGetInstanceProcAddr( NULL, "vkCreateInstance" );
|
p_vkCreateInstance = p_vkGetInstanceProcAddr( NULL, "vkCreateInstance" );
|
||||||
if ((vr = p_vkCreateInstance( &create_info, NULL, &d3dkmt_vk_instance )))
|
if ((vr = p_vkCreateInstance( &create_info, NULL, &d3dkmt_vk_instance )))
|
||||||
{
|
{
|
||||||
WARN( "Failed to create a Vulkan instance, vr %d.\n", vr );
|
WARN( "Failed to create a Vulkan instance, vr %d.\n", vr );
|
||||||
|
@ -97,9 +98,9 @@ static void d3dkmt_init_vulkan(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_vkDestroyInstance = vulkan_funcs->p_vkGetInstanceProcAddr( d3dkmt_vk_instance, "vkDestroyInstance" );
|
p_vkDestroyInstance = p_vkGetInstanceProcAddr( d3dkmt_vk_instance, "vkDestroyInstance" );
|
||||||
#define LOAD_VK_FUNC( f ) \
|
#define LOAD_VK_FUNC( f ) \
|
||||||
if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( d3dkmt_vk_instance, #f ))) \
|
if (!(p##f = (void *)p_vkGetInstanceProcAddr( d3dkmt_vk_instance, #f ))) \
|
||||||
{ \
|
{ \
|
||||||
WARN( "Failed to load " #f ".\n" ); \
|
WARN( "Failed to load " #f ".\n" ); \
|
||||||
p_vkDestroyInstance( d3dkmt_vk_instance, NULL ); \
|
p_vkDestroyInstance( d3dkmt_vk_instance, NULL ); \
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "ntuser.h"
|
#include "ntuser.h"
|
||||||
#include "shellapi.h"
|
#include "shellapi.h"
|
||||||
#include "wine/list.h"
|
#include "wine/list.h"
|
||||||
|
#include "wine/vulkan.h"
|
||||||
|
|
||||||
|
|
||||||
#define WM_POPUPSYSTEMMENU 0x0313
|
#define WM_POPUPSYSTEMMENU 0x0313
|
||||||
|
@ -250,6 +251,10 @@ extern int peek_message( MSG *msg, const struct peek_message_filter *filter );
|
||||||
extern LRESULT system_tray_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void *data );
|
extern LRESULT system_tray_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void *data );
|
||||||
|
|
||||||
/* vulkan.c */
|
/* vulkan.c */
|
||||||
|
extern void *(*p_vkGetDeviceProcAddr)(VkDevice, const char *);
|
||||||
|
extern void *(*p_vkGetInstanceProcAddr)(VkInstance, const char *);
|
||||||
|
|
||||||
|
extern BOOL vulkan_init(void);
|
||||||
extern void vulkan_detach_surfaces( struct list *surfaces );
|
extern void vulkan_detach_surfaces( struct list *surfaces );
|
||||||
|
|
||||||
/* window.c */
|
/* window.c */
|
||||||
|
|
|
@ -39,16 +39,18 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
|
WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
|
||||||
|
|
||||||
#ifdef SONAME_LIBVULKAN
|
void *(*p_vkGetDeviceProcAddr)(VkDevice, const char *) = NULL;
|
||||||
|
void *(*p_vkGetInstanceProcAddr)(VkInstance, const char *) = NULL;
|
||||||
|
|
||||||
static void *vulkan_handle;
|
static void *vulkan_handle;
|
||||||
static const struct vulkan_driver_funcs *driver_funcs;
|
|
||||||
static struct vulkan_funcs vulkan_funcs;
|
static struct vulkan_funcs vulkan_funcs;
|
||||||
|
|
||||||
|
#ifdef SONAME_LIBVULKAN
|
||||||
|
|
||||||
|
static const struct vulkan_driver_funcs *driver_funcs;
|
||||||
|
|
||||||
static void (*p_vkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *);
|
static void (*p_vkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *);
|
||||||
static VkResult (*p_vkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
|
static VkResult (*p_vkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
|
||||||
static void *(*p_vkGetDeviceProcAddr)(VkDevice, const char *);
|
|
||||||
static void *(*p_vkGetInstanceProcAddr)(VkInstance, const char *);
|
|
||||||
|
|
||||||
struct surface
|
struct surface
|
||||||
{
|
{
|
||||||
|
@ -283,7 +285,7 @@ static const struct vulkan_driver_funcs lazydrv_funcs =
|
||||||
.p_vulkan_surface_presented = lazydrv_vulkan_surface_presented,
|
.p_vulkan_surface_presented = lazydrv_vulkan_surface_presented,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vulkan_init(void)
|
static void vulkan_init_once(void)
|
||||||
{
|
{
|
||||||
if (!(vulkan_handle = dlopen( SONAME_LIBVULKAN, RTLD_NOW )))
|
if (!(vulkan_handle = dlopen( SONAME_LIBVULKAN, RTLD_NOW )))
|
||||||
{
|
{
|
||||||
|
@ -323,36 +325,37 @@ void vulkan_detach_surfaces( struct list *surfaces )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* __wine_get_vulkan_driver (win32u.so)
|
|
||||||
*/
|
|
||||||
const struct vulkan_funcs *__wine_get_vulkan_driver( UINT version )
|
|
||||||
{
|
|
||||||
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
|
||||||
|
|
||||||
if (version != WINE_VULKAN_DRIVER_VERSION)
|
|
||||||
{
|
|
||||||
ERR( "version mismatch, vulkan wants %u but win32u has %u\n", version, WINE_VULKAN_DRIVER_VERSION );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_once( &init_once, vulkan_init );
|
|
||||||
return vulkan_handle ? &vulkan_funcs : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* SONAME_LIBVULKAN */
|
#else /* SONAME_LIBVULKAN */
|
||||||
|
|
||||||
void vulkan_detach_surfaces( struct list *surfaces )
|
void vulkan_detach_surfaces( struct list *surfaces )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vulkan_init_once(void)
|
||||||
|
{
|
||||||
|
ERR( "Wine was built without Vulkan support.\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SONAME_LIBVULKAN */
|
||||||
|
|
||||||
|
BOOL vulkan_init(void)
|
||||||
|
{
|
||||||
|
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_once( &init_once, vulkan_init_once );
|
||||||
|
return !!vulkan_handle;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* __wine_get_vulkan_driver (win32u.so)
|
* __wine_get_vulkan_driver (win32u.so)
|
||||||
*/
|
*/
|
||||||
const struct vulkan_funcs *__wine_get_vulkan_driver( UINT version )
|
const struct vulkan_funcs *__wine_get_vulkan_driver( UINT version )
|
||||||
{
|
{
|
||||||
ERR("Wine was built without Vulkan support.\n");
|
if (version != WINE_VULKAN_DRIVER_VERSION)
|
||||||
return NULL;
|
{
|
||||||
}
|
ERR( "version mismatch, vulkan wants %u but win32u has %u\n", version, WINE_VULKAN_DRIVER_VERSION );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SONAME_LIBVULKAN */
|
if (!vulkan_init()) return NULL;
|
||||||
|
return &vulkan_funcs;
|
||||||
|
}
|
||||||
|
|
|
@ -100,6 +100,9 @@ struct parser_source
|
||||||
bool need_segment;
|
bool need_segment;
|
||||||
|
|
||||||
bool eos;
|
bool eos;
|
||||||
|
|
||||||
|
bool interpolate_timestamps;
|
||||||
|
UINT64 prev_end_pts;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct parser *impl_from_strmbase_filter(struct strmbase_filter *iface)
|
static inline struct parser *impl_from_strmbase_filter(struct strmbase_filter *iface)
|
||||||
|
@ -630,7 +633,7 @@ static bool amt_from_wg_format_video_cinepak(AM_MEDIA_TYPE *mt, const struct wg_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_format *format)
|
static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm)
|
||||||
{
|
{
|
||||||
VIDEOINFOHEADER *video_format;
|
VIDEOINFOHEADER *video_format;
|
||||||
uint32_t frame_time;
|
uint32_t frame_time;
|
||||||
|
@ -671,7 +674,8 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form
|
||||||
mt->pbFormat = (BYTE *)video_format;
|
mt->pbFormat = (BYTE *)video_format;
|
||||||
|
|
||||||
memset(video_format, 0, sizeof(*video_format));
|
memset(video_format, 0, sizeof(*video_format));
|
||||||
SetRect(&video_format->rcSource, 0, 0, format->u.video.width, format->u.video.height);
|
if (wm)
|
||||||
|
SetRect(&video_format->rcSource, 0, 0, format->u.video.width, format->u.video.height);
|
||||||
video_format->rcTarget = video_format->rcSource;
|
video_format->rcTarget = video_format->rcSource;
|
||||||
if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1)
|
if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1)
|
||||||
video_format->AvgTimePerFrame = frame_time;
|
video_format->AvgTimePerFrame = frame_time;
|
||||||
|
@ -681,6 +685,8 @@ static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_form
|
||||||
video_format->bmiHeader.biPlanes = 1;
|
video_format->bmiHeader.biPlanes = 1;
|
||||||
video_format->bmiHeader.biCompression = mt->subtype.Data1;
|
video_format->bmiHeader.biCompression = mt->subtype.Data1;
|
||||||
video_format->bmiHeader.biBitCount = 24;
|
video_format->bmiHeader.biBitCount = 24;
|
||||||
|
if (!wm)
|
||||||
|
video_format->bmiHeader.biSizeImage = 3 * format->u.video.width * format->u.video.height;
|
||||||
video_format->dwBitRate = 0;
|
video_format->dwBitRate = 0;
|
||||||
memcpy(video_format+1, format->u.video.codec_data, format->u.video.codec_data_len);
|
memcpy(video_format+1, format->u.video.codec_data, format->u.video.codec_data_len);
|
||||||
|
|
||||||
|
@ -747,7 +753,7 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool
|
||||||
return amt_from_wg_format_video_cinepak(mt, format);
|
return amt_from_wg_format_video_cinepak(mt, format);
|
||||||
|
|
||||||
case WG_MAJOR_TYPE_VIDEO_WMV:
|
case WG_MAJOR_TYPE_VIDEO_WMV:
|
||||||
return amt_from_wg_format_video_wmv(mt, format);
|
return amt_from_wg_format_video_wmv(mt, format, wm);
|
||||||
|
|
||||||
case WG_MAJOR_TYPE_VIDEO_MPEG1:
|
case WG_MAJOR_TYPE_VIDEO_MPEG1:
|
||||||
return amt_from_wg_format_video_mpeg1(mt, format);
|
return amt_from_wg_format_video_mpeg1(mt, format);
|
||||||
|
@ -977,6 +983,30 @@ static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *fo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool amt_to_wg_format_video_cinepak(const AM_MEDIA_TYPE *mt, struct wg_format *format)
|
||||||
|
{
|
||||||
|
const VIDEOINFOHEADER *video_format = (const VIDEOINFOHEADER *)mt->pbFormat;
|
||||||
|
|
||||||
|
if (!IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo))
|
||||||
|
{
|
||||||
|
FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mt->cbFormat < sizeof(VIDEOINFOHEADER) || !mt->pbFormat)
|
||||||
|
{
|
||||||
|
ERR("Unexpected format size %lu.\n", mt->cbFormat);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
format->major_type = WG_MAJOR_TYPE_VIDEO_CINEPAK;
|
||||||
|
format->u.video.width = video_format->bmiHeader.biWidth;
|
||||||
|
format->u.video.height = video_format->bmiHeader.biHeight;
|
||||||
|
format->u.video.fps_n = 10000000;
|
||||||
|
format->u.video.fps_d = video_format->AvgTimePerFrame;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format *format)
|
static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format *format)
|
||||||
{
|
{
|
||||||
const VIDEOINFOHEADER *video_format = (const VIDEOINFOHEADER *)mt->pbFormat;
|
const VIDEOINFOHEADER *video_format = (const VIDEOINFOHEADER *)mt->pbFormat;
|
||||||
|
@ -1051,6 +1081,8 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format)
|
||||||
|
|
||||||
if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Video))
|
if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Video))
|
||||||
{
|
{
|
||||||
|
if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_CVID))
|
||||||
|
return amt_to_wg_format_video_cinepak(mt, format);
|
||||||
if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV1)
|
if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV1)
|
||||||
|| IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV2)
|
|| IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV2)
|
||||||
|| IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMVA)
|
|| IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMVA)
|
||||||
|
@ -1153,30 +1185,34 @@ static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample,
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer->has_pts)
|
if (buffer->has_pts || (pin->interpolate_timestamps && pin->prev_end_pts != 0))
|
||||||
{
|
{
|
||||||
REFERENCE_TIME start_pts = buffer->pts;
|
UINT64 start_pts = (buffer->has_pts ? buffer->pts : pin->prev_end_pts);
|
||||||
|
REFERENCE_TIME start_reftime = start_pts;
|
||||||
|
|
||||||
if (offset)
|
if (offset)
|
||||||
start_pts += scale_uint64(offset, 10000000, bytes_per_second);
|
start_reftime += scale_uint64(offset, 10000000, bytes_per_second);
|
||||||
start_pts -= pin->seek.llCurrent;
|
start_reftime -= pin->seek.llCurrent;
|
||||||
start_pts *= pin->seek.dRate;
|
start_reftime *= pin->seek.dRate;
|
||||||
|
|
||||||
if (buffer->has_duration)
|
if (buffer->has_duration)
|
||||||
{
|
{
|
||||||
REFERENCE_TIME end_pts = buffer->pts + buffer->duration;
|
UINT64 end_pts = start_pts + buffer->duration;
|
||||||
|
REFERENCE_TIME end_reftime = end_pts;
|
||||||
|
|
||||||
|
pin->prev_end_pts = end_pts;
|
||||||
if (offset + size < buffer->size)
|
if (offset + size < buffer->size)
|
||||||
end_pts = buffer->pts + scale_uint64(offset + size, 10000000, bytes_per_second);
|
end_reftime = end_reftime + scale_uint64(offset + size, 10000000, bytes_per_second);
|
||||||
end_pts -= pin->seek.llCurrent;
|
end_reftime -= pin->seek.llCurrent;
|
||||||
end_pts *= pin->seek.dRate;
|
end_reftime *= pin->seek.dRate;
|
||||||
|
|
||||||
IMediaSample_SetTime(sample, &start_pts, &end_pts);
|
IMediaSample_SetTime(sample, &start_reftime, &end_reftime);
|
||||||
IMediaSample_SetMediaTime(sample, &start_pts, &end_pts);
|
IMediaSample_SetMediaTime(sample, &start_reftime, &end_reftime);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IMediaSample_SetTime(sample, &start_pts, NULL);
|
pin->prev_end_pts = 0;
|
||||||
|
IMediaSample_SetTime(sample, &start_reftime, NULL);
|
||||||
IMediaSample_SetMediaTime(sample, NULL, NULL);
|
IMediaSample_SetMediaTime(sample, NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2291,6 +2327,7 @@ static const struct strmbase_sink_ops avi_splitter_sink_ops =
|
||||||
static BOOL avi_splitter_filter_init_gst(struct parser *filter)
|
static BOOL avi_splitter_filter_init_gst(struct parser *filter)
|
||||||
{
|
{
|
||||||
wg_parser_t parser = filter->wg_parser;
|
wg_parser_t parser = filter->wg_parser;
|
||||||
|
struct parser_source *src;
|
||||||
uint32_t i, stream_count;
|
uint32_t i, stream_count;
|
||||||
WCHAR source_name[20];
|
WCHAR source_name[20];
|
||||||
|
|
||||||
|
@ -2298,8 +2335,10 @@ static BOOL avi_splitter_filter_init_gst(struct parser *filter)
|
||||||
for (i = 0; i < stream_count; ++i)
|
for (i = 0; i < stream_count; ++i)
|
||||||
{
|
{
|
||||||
swprintf(source_name, ARRAY_SIZE(source_name), L"Stream %02u", i);
|
swprintf(source_name, ARRAY_SIZE(source_name), L"Stream %02u", i);
|
||||||
if (!create_pin(filter, wg_parser_get_stream(parser, i), source_name))
|
src = create_pin(filter, wg_parser_get_stream(parser, i), source_name);
|
||||||
|
if (!src)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
src->interpolate_timestamps = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
|
@ -661,8 +661,8 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde
|
||||||
DMO_MEDIA_TYPE *type)
|
DMO_MEDIA_TYPE *type)
|
||||||
{
|
{
|
||||||
struct wma_decoder *decoder = impl_from_IMediaObject(iface);
|
struct wma_decoder *decoder = impl_from_IMediaObject(iface);
|
||||||
|
UINT32 depth, channels, rate;
|
||||||
IMFMediaType *media_type;
|
IMFMediaType *media_type;
|
||||||
UINT32 depth;
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("iface %p, index %lu, type_index %lu, type %p\n", iface, index, type_index, type);
|
TRACE("iface %p, index %lu, type_index %lu, type %p\n", iface, index, type_index, type);
|
||||||
|
@ -686,6 +686,16 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde
|
||||||
else
|
else
|
||||||
hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
|
hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, &channels);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, depth * channels / 8);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, depth * channels / 8 * rate);
|
||||||
|
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
hr = IMFMediaType_DeleteItem(media_type, &MF_MT_USER_DATA);
|
hr = IMFMediaType_DeleteItem(media_type, &MF_MT_USER_DATA);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
|
|
|
@ -3391,45 +3391,6 @@ invalid_layer:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* macdrv_wglGetPixelFormatAttribfvARB
|
|
||||||
*
|
|
||||||
* WGL_ARB_pixel_format: wglGetPixelFormatAttribfvARB
|
|
||||||
*/
|
|
||||||
static BOOL macdrv_wglGetPixelFormatAttribfvARB(HDC hdc, int iPixelFormat, int iLayerPlane,
|
|
||||||
UINT nAttributes, const int *piAttributes, FLOAT *pfValues)
|
|
||||||
{
|
|
||||||
int *attr;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
TRACE("hdc %p iPixelFormat %d iLayerPlane %d nAttributes %u piAttributes %p pfValues %p\n",
|
|
||||||
hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues);
|
|
||||||
|
|
||||||
/* Allocate a temporary array to store integer values */
|
|
||||||
attr = malloc(nAttributes * sizeof(int));
|
|
||||||
if (!attr)
|
|
||||||
{
|
|
||||||
ERR("couldn't allocate %d array\n", nAttributes);
|
|
||||||
return GL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Piggy-back on wglGetPixelFormatAttribivARB */
|
|
||||||
ret = macdrv_wglGetPixelFormatAttribivARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, attr);
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
UINT i;
|
|
||||||
|
|
||||||
/* Convert integer values to float. Should also check for attributes
|
|
||||||
that can give decimal values here */
|
|
||||||
for (i = 0; i < nAttributes; i++)
|
|
||||||
pfValues[i] = attr[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
free(attr);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* macdrv_wglGetSwapIntervalEXT
|
* macdrv_wglGetSwapIntervalEXT
|
||||||
*
|
*
|
||||||
|
@ -4136,7 +4097,7 @@ static void load_extensions(void)
|
||||||
|
|
||||||
register_extension("WGL_ARB_pixel_format");
|
register_extension("WGL_ARB_pixel_format");
|
||||||
opengl_funcs.ext.p_wglChoosePixelFormatARB = macdrv_wglChoosePixelFormatARB;
|
opengl_funcs.ext.p_wglChoosePixelFormatARB = macdrv_wglChoosePixelFormatARB;
|
||||||
opengl_funcs.ext.p_wglGetPixelFormatAttribfvARB = macdrv_wglGetPixelFormatAttribfvARB;
|
opengl_funcs.ext.p_wglGetPixelFormatAttribfvARB = (void *)1; /* never called */
|
||||||
opengl_funcs.ext.p_wglGetPixelFormatAttribivARB = macdrv_wglGetPixelFormatAttribivARB;
|
opengl_funcs.ext.p_wglGetPixelFormatAttribivARB = macdrv_wglGetPixelFormatAttribivARB;
|
||||||
|
|
||||||
if (gluCheckExtension((GLubyte*)"GL_ARB_color_buffer_float", (GLubyte*)gl_info.glExtensions))
|
if (gluCheckExtension((GLubyte*)"GL_ARB_color_buffer_float", (GLubyte*)gl_info.glExtensions))
|
||||||
|
|
|
@ -1553,132 +1553,208 @@ void destroy_gl_drawable( HWND hwnd )
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* glxdrv_DescribePixelFormat
|
* describe_pixel_format
|
||||||
*
|
*
|
||||||
* Get the pixel-format descriptor associated to the given id
|
* Get the wgl_pixel_format description for the given id
|
||||||
*/
|
*/
|
||||||
static int describe_pixel_format( int iPixelFormat, PIXELFORMATDESCRIPTOR *ppfd )
|
static int describe_pixel_format( int iPixelFormat, struct wgl_pixel_format *pf )
|
||||||
{
|
{
|
||||||
/*XVisualInfo *vis;*/
|
int value, drawable_type = 0, render_type = 0;
|
||||||
int value;
|
int rb, gb, bb, ab;
|
||||||
int rb,gb,bb,ab;
|
const struct glx_pixel_format *fmt;
|
||||||
const struct glx_pixel_format *fmt;
|
|
||||||
|
|
||||||
if (!has_opengl()) return 0;
|
if (!has_opengl()) return 0;
|
||||||
|
|
||||||
/* Look for the iPixelFormat in our list of supported formats. If it is supported we get the index in the FBConfig table and the number of supported formats back */
|
/* Look for the iPixelFormat in our list of supported formats. If it is
|
||||||
fmt = get_pixel_format(gdi_display, iPixelFormat, TRUE /* Offscreen */);
|
* supported we get the index in the FBConfig table and the number of
|
||||||
if (!fmt) {
|
* supported formats back */
|
||||||
WARN("unexpected format %d\n", iPixelFormat);
|
fmt = get_pixel_format( gdi_display, iPixelFormat, TRUE /* Offscreen */);
|
||||||
return 0;
|
if (!fmt)
|
||||||
}
|
{
|
||||||
|
WARN( "unexpected format %d\n", iPixelFormat );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
memset(ppfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
/* If we can't get basic information, there is no point continuing */
|
||||||
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_DRAWABLE_TYPE, &drawable_type )) return 0;
|
||||||
ppfd->nVersion = 1;
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_RENDER_TYPE, &render_type )) return 0;
|
||||||
|
|
||||||
/* These flags are always the same... */
|
memset( pf, 0, sizeof(*pf) );
|
||||||
ppfd->dwFlags = PFD_SUPPORT_OPENGL;
|
pf->pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||||
/* Now the flags extracted from the Visual */
|
pf->pfd.nVersion = 1;
|
||||||
|
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_DRAWABLE_TYPE, &value);
|
/* These flags are always the same... */
|
||||||
if(value & GLX_WINDOW_BIT)
|
pf->pfd.dwFlags = PFD_SUPPORT_OPENGL;
|
||||||
ppfd->dwFlags |= PFD_DRAW_TO_WINDOW;
|
/* Now the flags extracted from the Visual */
|
||||||
|
|
||||||
/* On Windows bitmap rendering is only offered using the GDI Software renderer. We reserve some formats (see get_formats for more info)
|
if (drawable_type & GLX_WINDOW_BIT) pf->pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
|
||||||
* for bitmap rendering since we require indirect rendering for this. Further pixel format logs of a GeforceFX, Geforce8800GT, Radeon HD3400 and a
|
|
||||||
* Radeon 9000 indicated that all bitmap formats have PFD_SUPPORT_GDI. Except for 2 formats on the Radeon 9000 none of the hw accelerated formats
|
|
||||||
* offered the GDI bit either. */
|
|
||||||
ppfd->dwFlags |= fmt->dwFlags & (PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI);
|
|
||||||
|
|
||||||
/* PFD_GENERIC_FORMAT - gdi software rendering
|
/* On Windows bitmap rendering is only offered using the GDI Software
|
||||||
* PFD_GENERIC_ACCELERATED - some parts are accelerated by a display driver (MCD e.g. 3dfx minigl)
|
* renderer. We reserve some formats (see get_formats for more info) for
|
||||||
* none set - full hardware accelerated by a ICD
|
* bitmap rendering since we require indirect rendering for this. Further
|
||||||
*
|
* pixel format logs of a GeforceFX, Geforce8800GT, Radeon HD3400 and a
|
||||||
* We only set PFD_GENERIC_FORMAT on bitmap formats (see get_formats) as that's what ATI and Nvidia Windows drivers do */
|
* Radeon 9000 indicated that all bitmap formats have PFD_SUPPORT_GDI.
|
||||||
ppfd->dwFlags |= fmt->dwFlags & (PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED);
|
* Except for 2 formats on the Radeon 9000 none of the hw accelerated
|
||||||
|
* formats offered the GDI bit either. */
|
||||||
|
pf->pfd.dwFlags |= fmt->dwFlags & (PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI);
|
||||||
|
|
||||||
if (!(ppfd->dwFlags & PFD_GENERIC_FORMAT))
|
/* PFD_GENERIC_FORMAT - gdi software rendering
|
||||||
ppfd->dwFlags |= PFD_SUPPORT_COMPOSITION;
|
* PFD_GENERIC_ACCELERATED - some parts are accelerated by a display driver
|
||||||
|
* (MCD e.g. 3dfx minigl) none set - full hardware accelerated by a ICD
|
||||||
|
*
|
||||||
|
* We only set PFD_GENERIC_FORMAT on bitmap formats (see get_formats) as
|
||||||
|
* that's what ATI and Nvidia Windows drivers do */
|
||||||
|
pf->pfd.dwFlags |= fmt->dwFlags & (PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED);
|
||||||
|
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_DOUBLEBUFFER, &value);
|
if (!(pf->pfd.dwFlags & PFD_GENERIC_FORMAT)) pf->pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;
|
||||||
if (value) {
|
|
||||||
ppfd->dwFlags |= PFD_DOUBLEBUFFER;
|
|
||||||
ppfd->dwFlags &= ~PFD_SUPPORT_GDI;
|
|
||||||
}
|
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_STEREO, &value); if (value) ppfd->dwFlags |= PFD_STEREO;
|
|
||||||
|
|
||||||
/* Pixel type */
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_DOUBLEBUFFER, &value );
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_RENDER_TYPE, &value);
|
if (value)
|
||||||
if (value & GLX_RGBA_BIT)
|
{
|
||||||
ppfd->iPixelType = PFD_TYPE_RGBA;
|
pf->pfd.dwFlags |= PFD_DOUBLEBUFFER;
|
||||||
else
|
pf->pfd.dwFlags &= ~PFD_SUPPORT_GDI;
|
||||||
ppfd->iPixelType = PFD_TYPE_COLORINDEX;
|
}
|
||||||
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_STEREO, &value );
|
||||||
|
if (value) pf->pfd.dwFlags |= PFD_STEREO;
|
||||||
|
|
||||||
/* Color bits */
|
/* Pixel type */
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_BUFFER_SIZE, &value);
|
if (render_type & GLX_RGBA_BIT) pf->pfd.iPixelType = PFD_TYPE_RGBA;
|
||||||
ppfd->cColorBits = value;
|
else pf->pfd.iPixelType = PFD_TYPE_COLORINDEX;
|
||||||
|
|
||||||
/* Red, green, blue and alpha bits / shifts */
|
/* Color bits */
|
||||||
if (ppfd->iPixelType == PFD_TYPE_RGBA) {
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_BUFFER_SIZE, &value );
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_RED_SIZE, &rb);
|
pf->pfd.cColorBits = value;
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_GREEN_SIZE, &gb);
|
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_BLUE_SIZE, &bb);
|
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ALPHA_SIZE, &ab);
|
|
||||||
|
|
||||||
ppfd->cBlueBits = bb;
|
/* Red, green, blue and alpha bits / shifts */
|
||||||
ppfd->cBlueShift = 0;
|
if (pf->pfd.iPixelType == PFD_TYPE_RGBA)
|
||||||
ppfd->cGreenBits = gb;
|
{
|
||||||
ppfd->cGreenShift = bb;
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_RED_SIZE, &rb );
|
||||||
ppfd->cRedBits = rb;
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_GREEN_SIZE, &gb );
|
||||||
ppfd->cRedShift = gb + bb;
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_BLUE_SIZE, &bb );
|
||||||
ppfd->cAlphaBits = ab;
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_ALPHA_SIZE, &ab );
|
||||||
if (ab)
|
|
||||||
ppfd->cAlphaShift = rb + gb + bb;
|
pf->pfd.cBlueBits = bb;
|
||||||
|
pf->pfd.cBlueShift = 0;
|
||||||
|
pf->pfd.cGreenBits = gb;
|
||||||
|
pf->pfd.cGreenShift = bb;
|
||||||
|
pf->pfd.cRedBits = rb;
|
||||||
|
pf->pfd.cRedShift = gb + bb;
|
||||||
|
pf->pfd.cAlphaBits = ab;
|
||||||
|
if (ab) pf->pfd.cAlphaShift = rb + gb + bb;
|
||||||
|
else pf->pfd.cAlphaShift = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ppfd->cAlphaShift = 0;
|
{
|
||||||
} else {
|
pf->pfd.cRedBits = 0;
|
||||||
ppfd->cRedBits = 0;
|
pf->pfd.cRedShift = 0;
|
||||||
ppfd->cRedShift = 0;
|
pf->pfd.cBlueBits = 0;
|
||||||
ppfd->cBlueBits = 0;
|
pf->pfd.cBlueShift = 0;
|
||||||
ppfd->cBlueShift = 0;
|
pf->pfd.cGreenBits = 0;
|
||||||
ppfd->cGreenBits = 0;
|
pf->pfd.cGreenShift = 0;
|
||||||
ppfd->cGreenShift = 0;
|
pf->pfd.cAlphaBits = 0;
|
||||||
ppfd->cAlphaBits = 0;
|
pf->pfd.cAlphaShift = 0;
|
||||||
ppfd->cAlphaShift = 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Accum RGBA bits */
|
/* Accum RGBA bits */
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ACCUM_RED_SIZE, &rb);
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_ACCUM_RED_SIZE, &rb );
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ACCUM_GREEN_SIZE, &gb);
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_ACCUM_GREEN_SIZE, &gb );
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ACCUM_BLUE_SIZE, &bb);
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_ACCUM_BLUE_SIZE, &bb );
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ACCUM_ALPHA_SIZE, &ab);
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_ACCUM_ALPHA_SIZE, &ab );
|
||||||
|
|
||||||
ppfd->cAccumBits = rb+gb+bb+ab;
|
pf->pfd.cAccumBits = rb + gb + bb + ab;
|
||||||
ppfd->cAccumRedBits = rb;
|
pf->pfd.cAccumRedBits = rb;
|
||||||
ppfd->cAccumGreenBits = gb;
|
pf->pfd.cAccumGreenBits = gb;
|
||||||
ppfd->cAccumBlueBits = bb;
|
pf->pfd.cAccumBlueBits = bb;
|
||||||
ppfd->cAccumAlphaBits = ab;
|
pf->pfd.cAccumAlphaBits = ab;
|
||||||
|
|
||||||
/* Aux bits */
|
/* Aux bits */
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_AUX_BUFFERS, &value);
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_AUX_BUFFERS, &value );
|
||||||
ppfd->cAuxBuffers = value;
|
pf->pfd.cAuxBuffers = value;
|
||||||
|
|
||||||
/* Depth bits */
|
/* Depth bits */
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_DEPTH_SIZE, &value);
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_DEPTH_SIZE, &value );
|
||||||
ppfd->cDepthBits = value;
|
pf->pfd.cDepthBits = value;
|
||||||
|
|
||||||
/* stencil bits */
|
/* stencil bits */
|
||||||
pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_STENCIL_SIZE, &value);
|
pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_STENCIL_SIZE, &value );
|
||||||
ppfd->cStencilBits = value;
|
pf->pfd.cStencilBits = value;
|
||||||
|
|
||||||
ppfd->iLayerType = PFD_MAIN_PLANE;
|
pf->pfd.iLayerType = PFD_MAIN_PLANE;
|
||||||
|
|
||||||
if (TRACE_ON(wgl)) {
|
if (!has_swap_method) pf->swap_method = WGL_SWAP_EXCHANGE_ARB;
|
||||||
dump_PIXELFORMATDESCRIPTOR(ppfd);
|
else if (!pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_SWAP_METHOD_OML, &value ))
|
||||||
}
|
{
|
||||||
|
switch (value) {
|
||||||
|
case GLX_SWAP_EXCHANGE_OML: pf->swap_method = WGL_SWAP_EXCHANGE_ARB; break;
|
||||||
|
case GLX_SWAP_COPY_OML: pf->swap_method = WGL_SWAP_COPY_ARB; break;
|
||||||
|
case GLX_SWAP_UNDEFINED_OML: pf->swap_method = WGL_SWAP_UNDEFINED_ARB; break;
|
||||||
|
default: { ERR( "Unexpected swap method %x.\n", value ); pf->swap_method = -1; break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else pf->swap_method = -1;
|
||||||
|
|
||||||
return nb_onscreen_formats;
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_TRANSPARENT_TYPE, &value) ) pf->transparent = -1;
|
||||||
|
else pf->transparent = value != GLX_NONE;
|
||||||
|
|
||||||
|
if (render_type & GLX_RGBA_BIT) pf->pixel_type = WGL_TYPE_RGBA_ARB;
|
||||||
|
else if (render_type & GLX_COLOR_INDEX_BIT) pf->pixel_type = WGL_TYPE_COLORINDEX_ARB;
|
||||||
|
else if (render_type & GLX_RGBA_FLOAT_BIT) pf->pixel_type = WGL_TYPE_RGBA_FLOAT_ATI;
|
||||||
|
else if (render_type & GLX_RGBA_FLOAT_ATI_BIT) pf->pixel_type = WGL_TYPE_RGBA_FLOAT_ATI;
|
||||||
|
else if (render_type & GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT) pf->pixel_type = WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT;
|
||||||
|
else { ERR( "unexpected RenderType(%x)\n", render_type ); pf->pixel_type = -1; }
|
||||||
|
|
||||||
|
pf->draw_to_pbuffer = (drawable_type & GLX_PBUFFER_BIT) ? GL_TRUE : GL_FALSE;
|
||||||
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_MAX_PBUFFER_PIXELS, &value )) value = -1;
|
||||||
|
pf->max_pbuffer_pixels = value;
|
||||||
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_MAX_PBUFFER_WIDTH, &value )) value = -1;
|
||||||
|
pf->max_pbuffer_width = value;
|
||||||
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_MAX_PBUFFER_HEIGHT, &value )) value = -1;
|
||||||
|
pf->max_pbuffer_height = value;
|
||||||
|
|
||||||
|
if (!pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_TRANSPARENT_RED_VALUE, &value ))
|
||||||
|
{
|
||||||
|
pf->transparent_red_value_valid = GL_TRUE;
|
||||||
|
pf->transparent_red_value = value;
|
||||||
|
}
|
||||||
|
if (!pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_TRANSPARENT_GREEN_VALUE, &value ))
|
||||||
|
{
|
||||||
|
pf->transparent_green_value_valid = GL_TRUE;
|
||||||
|
pf->transparent_green_value = value;
|
||||||
|
}
|
||||||
|
if (!pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_TRANSPARENT_BLUE_VALUE, &value ))
|
||||||
|
{
|
||||||
|
pf->transparent_blue_value_valid = GL_TRUE;
|
||||||
|
pf->transparent_blue_value = value;
|
||||||
|
}
|
||||||
|
if (!pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_TRANSPARENT_ALPHA_VALUE, &value ))
|
||||||
|
{
|
||||||
|
pf->transparent_alpha_value_valid = GL_TRUE;
|
||||||
|
pf->transparent_alpha_value = value;
|
||||||
|
}
|
||||||
|
if (!pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_TRANSPARENT_INDEX_VALUE, &value ))
|
||||||
|
{
|
||||||
|
pf->transparent_index_value_valid = GL_TRUE;
|
||||||
|
pf->transparent_index_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_SAMPLE_BUFFERS_ARB, &value )) value = -1;
|
||||||
|
pf->sample_buffers = value;
|
||||||
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_SAMPLES_ARB, &value )) value = -1;
|
||||||
|
pf->samples = value;
|
||||||
|
|
||||||
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, &value )) value = -1;
|
||||||
|
pf->framebuffer_srgb_capable = value;
|
||||||
|
|
||||||
|
pf->bind_to_texture_rgb = pf->bind_to_texture_rgba =
|
||||||
|
use_render_texture_emulation && render_type != GLX_COLOR_INDEX_BIT && (render_type & GLX_PBUFFER_BIT);
|
||||||
|
pf->bind_to_texture_rectangle_rgb = pf->bind_to_texture_rectangle_rgba = GL_FALSE;
|
||||||
|
|
||||||
|
if (pglXGetFBConfigAttrib( gdi_display, fmt->fbconfig, GLX_FLOAT_COMPONENTS_NV, &value )) value = -1;
|
||||||
|
pf->float_components = value;
|
||||||
|
|
||||||
|
if (TRACE_ON(wgl)) dump_PIXELFORMATDESCRIPTOR( &pf->pfd );
|
||||||
|
|
||||||
|
return nb_onscreen_formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2520,7 +2596,7 @@ struct choose_pixel_format_arb_format
|
||||||
{
|
{
|
||||||
int format;
|
int format;
|
||||||
int original_index;
|
int original_index;
|
||||||
PIXELFORMATDESCRIPTOR pfd;
|
struct wgl_pixel_format pf;
|
||||||
int depth, stencil;
|
int depth, stencil;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2537,7 +2613,7 @@ static int compare_formats(const void *a, const void *b)
|
||||||
|
|
||||||
if (offscreen_a != offscreen_b)
|
if (offscreen_a != offscreen_b)
|
||||||
return offscreen_a - offscreen_b;
|
return offscreen_a - offscreen_b;
|
||||||
if (memcmp(&fmt_a->pfd, &fmt_b->pfd, sizeof(fmt_a->pfd)))
|
if (memcmp(&fmt_a->pf.pfd, &fmt_b->pf.pfd, sizeof(fmt_a->pf.pfd)))
|
||||||
return fmt_a->original_index - fmt_b->original_index;
|
return fmt_a->original_index - fmt_b->original_index;
|
||||||
if (fmt_a->depth != fmt_b->depth)
|
if (fmt_a->depth != fmt_b->depth)
|
||||||
return fmt_a->depth - fmt_b->depth;
|
return fmt_a->depth - fmt_b->depth;
|
||||||
|
@ -2652,16 +2728,16 @@ static BOOL X11DRV_wglChoosePixelFormatARB( HDC hdc, const int *piAttribIList, c
|
||||||
format->format = i + 1;
|
format->format = i + 1;
|
||||||
format->original_index = it;
|
format->original_index = it;
|
||||||
|
|
||||||
memset(&format->pfd, 0, sizeof(format->pfd));
|
memset(&format->pf, 0, sizeof(format->pf));
|
||||||
if (!describe_pixel_format(format->format, &format->pfd))
|
if (!describe_pixel_format(format->format, &format->pf))
|
||||||
ERR("describe_pixel_format failed, format %d.\n", format->format);
|
ERR("describe_pixel_format failed, format %d.\n", format->format);
|
||||||
|
|
||||||
format->depth = format->pfd.cDepthBits;
|
format->depth = format->pf.pfd.cDepthBits;
|
||||||
format->stencil = format->pfd.cStencilBits;
|
format->stencil = format->pf.pfd.cStencilBits;
|
||||||
if (!depth_bits && !(format->pfd.dwFlags & PFD_GENERIC_FORMAT))
|
if (!depth_bits && !(format->pf.pfd.dwFlags & PFD_GENERIC_FORMAT))
|
||||||
{
|
{
|
||||||
format->pfd.cDepthBits = 0;
|
format->pf.pfd.cDepthBits = 0;
|
||||||
format->pfd.cStencilBits = 0;
|
format->pf.pfd.cStencilBits = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
++format_count;
|
++format_count;
|
||||||
|
@ -2678,329 +2754,6 @@ static BOOL X11DRV_wglChoosePixelFormatARB( HDC hdc, const int *piAttribIList, c
|
||||||
return GL_TRUE;
|
return GL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* X11DRV_wglGetPixelFormatAttribivARB
|
|
||||||
*
|
|
||||||
* WGL_ARB_pixel_format: wglGetPixelFormatAttribivARB
|
|
||||||
*/
|
|
||||||
static BOOL X11DRV_wglGetPixelFormatAttribivARB( HDC hdc, int iPixelFormat, int iLayerPlane,
|
|
||||||
UINT nAttributes, const int *piAttributes, int *piValues )
|
|
||||||
{
|
|
||||||
UINT i;
|
|
||||||
const struct glx_pixel_format *fmt;
|
|
||||||
int hTest;
|
|
||||||
int tmp;
|
|
||||||
int curGLXAttr = 0;
|
|
||||||
PIXELFORMATDESCRIPTOR pfd;
|
|
||||||
|
|
||||||
TRACE("(%p, %d, %d, %d, %p, %p)\n", hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues);
|
|
||||||
|
|
||||||
if (0 < iLayerPlane) {
|
|
||||||
FIXME("unsupported iLayerPlane(%d) > 0, returns FALSE\n", iLayerPlane);
|
|
||||||
return GL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert the WGL pixelformat to a GLX one, if this fails then most likely the iPixelFormat isn't supported.
|
|
||||||
* We don't have to fail yet as a program can specify an invalid iPixelFormat (lets say 0) if it wants to query
|
|
||||||
* the number of supported WGL formats. Whether the iPixelFormat is valid is handled in the for-loop below. */
|
|
||||||
fmt = get_pixel_format(gdi_display, iPixelFormat, TRUE /* Offscreen */);
|
|
||||||
if(!fmt) {
|
|
||||||
WARN("Unable to convert iPixelFormat %d to a GLX one!\n", iPixelFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!describe_pixel_format(iPixelFormat, &pfd))
|
|
||||||
{
|
|
||||||
WARN("describe_pixel_format failed.\n");
|
|
||||||
memset(&pfd, 0, sizeof(pfd));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nAttributes; ++i) {
|
|
||||||
const int curWGLAttr = piAttributes[i];
|
|
||||||
TRACE("pAttr[%d] = %x\n", i, curWGLAttr);
|
|
||||||
|
|
||||||
switch (curWGLAttr) {
|
|
||||||
case WGL_NUMBER_PIXEL_FORMATS_ARB:
|
|
||||||
piValues[i] = nb_pixel_formats;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_SUPPORT_OPENGL_ARB:
|
|
||||||
piValues[i] = GL_TRUE;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_ACCELERATION_ARB:
|
|
||||||
curGLXAttr = GLX_CONFIG_CAVEAT;
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
if(fmt->dwFlags & PFD_GENERIC_FORMAT)
|
|
||||||
piValues[i] = WGL_NO_ACCELERATION_ARB;
|
|
||||||
else if(fmt->dwFlags & PFD_GENERIC_ACCELERATED)
|
|
||||||
piValues[i] = WGL_GENERIC_ACCELERATION_ARB;
|
|
||||||
else
|
|
||||||
piValues[i] = WGL_FULL_ACCELERATION_ARB;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_TRANSPARENT_ARB:
|
|
||||||
curGLXAttr = GLX_TRANSPARENT_TYPE;
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, curGLXAttr, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
piValues[i] = GL_FALSE;
|
|
||||||
if (GLX_NONE != tmp) piValues[i] = GL_TRUE;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_PIXEL_TYPE_ARB:
|
|
||||||
curGLXAttr = GLX_RENDER_TYPE;
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, curGLXAttr, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
TRACE("WGL_PIXEL_TYPE_ARB: GLX_RENDER_TYPE = 0x%x\n", tmp);
|
|
||||||
if (tmp & GLX_RGBA_BIT) { piValues[i] = WGL_TYPE_RGBA_ARB; }
|
|
||||||
else if (tmp & GLX_COLOR_INDEX_BIT) { piValues[i] = WGL_TYPE_COLORINDEX_ARB; }
|
|
||||||
else if (tmp & GLX_RGBA_FLOAT_BIT) { piValues[i] = WGL_TYPE_RGBA_FLOAT_ATI; }
|
|
||||||
else if (tmp & GLX_RGBA_FLOAT_ATI_BIT) { piValues[i] = WGL_TYPE_RGBA_FLOAT_ATI; }
|
|
||||||
else if (tmp & GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT) { piValues[i] = WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT; }
|
|
||||||
else {
|
|
||||||
ERR("unexpected RenderType(%x)\n", tmp);
|
|
||||||
piValues[i] = WGL_TYPE_RGBA_ARB;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_COLOR_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_BUFFER_SIZE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGL_BIND_TO_TEXTURE_RGB_ARB:
|
|
||||||
case WGL_BIND_TO_TEXTURE_RGBA_ARB:
|
|
||||||
if (!use_render_texture_emulation) {
|
|
||||||
piValues[i] = GL_FALSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
curGLXAttr = GLX_RENDER_TYPE;
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, curGLXAttr, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
if (GLX_COLOR_INDEX_BIT == tmp) {
|
|
||||||
piValues[i] = GL_FALSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_DRAWABLE_TYPE, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
piValues[i] = (tmp & GLX_PBUFFER_BIT) ? GL_TRUE : GL_FALSE;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_BLUE_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_BLUE_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_RED_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_RED_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_GREEN_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_GREEN_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_ALPHA_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_ALPHA_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_DEPTH_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_DEPTH_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_STENCIL_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_STENCIL_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_DOUBLE_BUFFER_ARB:
|
|
||||||
curGLXAttr = GLX_DOUBLEBUFFER;
|
|
||||||
break;
|
|
||||||
case WGL_STEREO_ARB:
|
|
||||||
curGLXAttr = GLX_STEREO;
|
|
||||||
break;
|
|
||||||
case WGL_AUX_BUFFERS_ARB:
|
|
||||||
curGLXAttr = GLX_AUX_BUFFERS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGL_RED_SHIFT_ARB:
|
|
||||||
if (!pfd.nSize) goto pix_error;
|
|
||||||
piValues[i] = pfd.cRedShift;
|
|
||||||
continue;
|
|
||||||
case WGL_GREEN_SHIFT_ARB:
|
|
||||||
if (!pfd.nSize) goto pix_error;
|
|
||||||
piValues[i] = pfd.cGreenShift;
|
|
||||||
continue;
|
|
||||||
case WGL_BLUE_SHIFT_ARB:
|
|
||||||
if (!pfd.nSize) goto pix_error;
|
|
||||||
piValues[i] = pfd.cBlueShift;
|
|
||||||
continue;
|
|
||||||
case WGL_ALPHA_SHIFT_ARB:
|
|
||||||
if (!pfd.nSize) goto pix_error;
|
|
||||||
piValues[i] = pfd.cAlphaShift;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_SUPPORT_GDI_ARB:
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
piValues[i] = (fmt->dwFlags & PFD_SUPPORT_GDI) != 0;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_DRAW_TO_BITMAP_ARB:
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
piValues[i] = (fmt->dwFlags & PFD_DRAW_TO_BITMAP) != 0;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_DRAW_TO_WINDOW_ARB:
|
|
||||||
case WGL_DRAW_TO_PBUFFER_ARB:
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_DRAWABLE_TYPE, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
if((curWGLAttr == WGL_DRAW_TO_WINDOW_ARB && (tmp&GLX_WINDOW_BIT)) ||
|
|
||||||
(curWGLAttr == WGL_DRAW_TO_PBUFFER_ARB && (tmp&GLX_PBUFFER_BIT)))
|
|
||||||
piValues[i] = GL_TRUE;
|
|
||||||
else
|
|
||||||
piValues[i] = GL_FALSE;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_SWAP_METHOD_ARB:
|
|
||||||
if (has_swap_method)
|
|
||||||
{
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_SWAP_METHOD_OML, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
switch (tmp)
|
|
||||||
{
|
|
||||||
case GLX_SWAP_EXCHANGE_OML:
|
|
||||||
piValues[i] = WGL_SWAP_EXCHANGE_ARB;
|
|
||||||
break;
|
|
||||||
case GLX_SWAP_COPY_OML:
|
|
||||||
piValues[i] = WGL_SWAP_COPY_ARB;
|
|
||||||
break;
|
|
||||||
case GLX_SWAP_UNDEFINED_OML:
|
|
||||||
piValues[i] = WGL_SWAP_UNDEFINED_ARB;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERR("Unexpected swap method %x.\n", tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WARN("GLX_OML_swap_method not supported, returning WGL_SWAP_EXCHANGE_ARB.\n");
|
|
||||||
piValues[i] = WGL_SWAP_EXCHANGE_ARB;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case WGL_PBUFFER_LARGEST_ARB:
|
|
||||||
curGLXAttr = GLX_LARGEST_PBUFFER;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGL_SAMPLE_BUFFERS_ARB:
|
|
||||||
curGLXAttr = GLX_SAMPLE_BUFFERS_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGL_SAMPLES_ARB:
|
|
||||||
curGLXAttr = GLX_SAMPLES_ARB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGL_FLOAT_COMPONENTS_NV:
|
|
||||||
curGLXAttr = GLX_FLOAT_COMPONENTS_NV;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT:
|
|
||||||
curGLXAttr = GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT:
|
|
||||||
curGLXAttr = GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WGL_ACCUM_RED_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_ACCUM_RED_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_ACCUM_GREEN_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_ACCUM_GREEN_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_ACCUM_BLUE_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_ACCUM_BLUE_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_ACCUM_ALPHA_BITS_ARB:
|
|
||||||
curGLXAttr = GLX_ACCUM_ALPHA_SIZE;
|
|
||||||
break;
|
|
||||||
case WGL_ACCUM_BITS_ARB:
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ACCUM_RED_SIZE, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
piValues[i] = tmp;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ACCUM_GREEN_SIZE, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
piValues[i] += tmp;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ACCUM_BLUE_SIZE, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
piValues[i] += tmp;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ACCUM_ALPHA_SIZE, &tmp);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
piValues[i] += tmp;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
default:
|
|
||||||
FIXME("unsupported %x WGL Attribute\n", curWGLAttr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve a GLX FBConfigAttrib when the attribute to query is valid and
|
|
||||||
* iPixelFormat != 0. When iPixelFormat is 0 the only value which makes
|
|
||||||
* sense to query is WGL_NUMBER_PIXEL_FORMATS_ARB.
|
|
||||||
*
|
|
||||||
* TODO: properly test the behavior of wglGetPixelFormatAttrib*v on Windows
|
|
||||||
* and check which options can work using iPixelFormat=0 and which not.
|
|
||||||
* A problem would be that this function is an extension. This would
|
|
||||||
* mean that the behavior could differ between different vendors (ATI, Nvidia, ..).
|
|
||||||
*/
|
|
||||||
if (0 != curGLXAttr && iPixelFormat != 0) {
|
|
||||||
if (!fmt) goto pix_error;
|
|
||||||
hTest = pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, curGLXAttr, piValues + i);
|
|
||||||
if (hTest) goto get_error;
|
|
||||||
curGLXAttr = 0;
|
|
||||||
} else {
|
|
||||||
piValues[i] = GL_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return GL_TRUE;
|
|
||||||
|
|
||||||
get_error:
|
|
||||||
ERR("(%p): unexpected failure on GetFBConfigAttrib(%x) returns FALSE\n", hdc, curGLXAttr);
|
|
||||||
return GL_FALSE;
|
|
||||||
|
|
||||||
pix_error:
|
|
||||||
ERR("(%p): unexpected iPixelFormat(%d) vs nFormats(%d), returns FALSE\n", hdc, iPixelFormat, nb_pixel_formats);
|
|
||||||
return GL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* X11DRV_wglGetPixelFormatAttribfvARB
|
|
||||||
*
|
|
||||||
* WGL_ARB_pixel_format: wglGetPixelFormatAttribfvARB
|
|
||||||
*/
|
|
||||||
static BOOL X11DRV_wglGetPixelFormatAttribfvARB( HDC hdc, int iPixelFormat, int iLayerPlane,
|
|
||||||
UINT nAttributes, const int *piAttributes, FLOAT *pfValues )
|
|
||||||
{
|
|
||||||
int *attr;
|
|
||||||
int ret;
|
|
||||||
UINT i;
|
|
||||||
|
|
||||||
TRACE("(%p, %d, %d, %d, %p, %p)\n", hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues);
|
|
||||||
|
|
||||||
/* Allocate a temporary array to store integer values */
|
|
||||||
attr = malloc( nAttributes * sizeof(int) );
|
|
||||||
if (!attr) {
|
|
||||||
ERR("couldn't allocate %d array\n", nAttributes);
|
|
||||||
return GL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Piggy-back on wglGetPixelFormatAttribivARB */
|
|
||||||
ret = X11DRV_wglGetPixelFormatAttribivARB(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, attr);
|
|
||||||
if (ret) {
|
|
||||||
/* Convert integer values to float. Should also check for attributes
|
|
||||||
that can give decimal values here */
|
|
||||||
for (i=0; i<nAttributes;i++) {
|
|
||||||
pfValues[i] = attr[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free( attr );
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* X11DRV_wglBindTexImageARB
|
* X11DRV_wglBindTexImageARB
|
||||||
*
|
*
|
||||||
|
@ -3260,8 +3013,8 @@ static void X11DRV_WineGL_LoadExtensions(void)
|
||||||
|
|
||||||
register_extension( "WGL_ARB_pixel_format" );
|
register_extension( "WGL_ARB_pixel_format" );
|
||||||
opengl_funcs.ext.p_wglChoosePixelFormatARB = X11DRV_wglChoosePixelFormatARB;
|
opengl_funcs.ext.p_wglChoosePixelFormatARB = X11DRV_wglChoosePixelFormatARB;
|
||||||
opengl_funcs.ext.p_wglGetPixelFormatAttribfvARB = X11DRV_wglGetPixelFormatAttribfvARB;
|
opengl_funcs.ext.p_wglGetPixelFormatAttribfvARB = (void *)1; /* never called */
|
||||||
opengl_funcs.ext.p_wglGetPixelFormatAttribivARB = X11DRV_wglGetPixelFormatAttribivARB;
|
opengl_funcs.ext.p_wglGetPixelFormatAttribivARB = (void *)1; /* never called */
|
||||||
|
|
||||||
if (has_extension( glxExtensions, "GLX_ARB_fbconfig_float"))
|
if (has_extension( glxExtensions, "GLX_ARB_fbconfig_float"))
|
||||||
{
|
{
|
||||||
|
@ -3445,7 +3198,7 @@ static void glxdrv_get_pixel_formats( struct wgl_pixel_format *formats,
|
||||||
if (formats)
|
if (formats)
|
||||||
{
|
{
|
||||||
for (i = 0; i < min( max_formats, nb_pixel_formats ); ++i)
|
for (i = 0; i < min( max_formats, nb_pixel_formats ); ++i)
|
||||||
describe_pixel_format( i + 1, &formats[i].pfd );
|
describe_pixel_format( i + 1, &formats[i] );
|
||||||
}
|
}
|
||||||
*num_formats = nb_pixel_formats;
|
*num_formats = nb_pixel_formats;
|
||||||
*num_onscreen_formats = nb_onscreen_formats;
|
*num_onscreen_formats = nb_onscreen_formats;
|
||||||
|
|
|
@ -49,6 +49,8 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||||
#include "wine/vulkan_driver.h"
|
#include "wine/vulkan_driver.h"
|
||||||
|
|
||||||
static void *xrandr_handle;
|
static void *xrandr_handle;
|
||||||
|
static void *vulkan_handle;
|
||||||
|
static void *(*p_vkGetInstanceProcAddr)(VkInstance, const char *);
|
||||||
|
|
||||||
#define MAKE_FUNCPTR(f) static typeof(f) * p##f;
|
#define MAKE_FUNCPTR(f) static typeof(f) * p##f;
|
||||||
MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
|
MAKE_FUNCPTR(XRRConfigCurrentConfiguration)
|
||||||
|
@ -136,6 +138,45 @@ sym_not_found:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SONAME_LIBVULKAN
|
||||||
|
|
||||||
|
static void vulkan_init_once(void)
|
||||||
|
{
|
||||||
|
if (!(vulkan_handle = dlopen( SONAME_LIBVULKAN, RTLD_NOW )))
|
||||||
|
{
|
||||||
|
ERR( "Failed to load %s\n", SONAME_LIBVULKAN );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOAD_FUNCPTR( f ) \
|
||||||
|
if (!(p_##f = dlsym( vulkan_handle, #f ))) \
|
||||||
|
{ \
|
||||||
|
ERR( "Failed to find " #f "\n" ); \
|
||||||
|
dlclose( vulkan_handle ); \
|
||||||
|
vulkan_handle = NULL; \
|
||||||
|
return; \
|
||||||
|
}
|
||||||
|
|
||||||
|
LOAD_FUNCPTR( vkGetInstanceProcAddr );
|
||||||
|
#undef LOAD_FUNCPTR
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* SONAME_LIBVULKAN */
|
||||||
|
|
||||||
|
static void vulkan_init_once(void)
|
||||||
|
{
|
||||||
|
ERR( "Wine was built without Vulkan support.\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SONAME_LIBVULKAN */
|
||||||
|
|
||||||
|
static BOOL vulkan_init(void)
|
||||||
|
{
|
||||||
|
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_once( &init_once, vulkan_init_once );
|
||||||
|
return !!vulkan_handle;
|
||||||
|
}
|
||||||
|
|
||||||
static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
|
static int XRandRErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -641,11 +682,11 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
|
||||||
"VK_KHR_display",
|
"VK_KHR_display",
|
||||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||||
};
|
};
|
||||||
const struct vulkan_funcs *vulkan_funcs = __wine_get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION );
|
|
||||||
VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
|
VkResult (*pvkGetRandROutputDisplayEXT)( VkPhysicalDevice, Display *, RROutput, VkDisplayKHR * );
|
||||||
PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
|
PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR;
|
||||||
PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
|
PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices;
|
||||||
uint32_t device_count, device_idx, output_idx, i;
|
uint32_t device_count, device_idx, output_idx, i;
|
||||||
|
PFN_vkDestroyInstance pvkDestroyInstance = NULL;
|
||||||
VkPhysicalDevice *vk_physical_devices = NULL;
|
VkPhysicalDevice *vk_physical_devices = NULL;
|
||||||
VkPhysicalDeviceProperties2 properties2;
|
VkPhysicalDeviceProperties2 properties2;
|
||||||
PFN_vkCreateInstance pvkCreateInstance;
|
PFN_vkCreateInstance pvkCreateInstance;
|
||||||
|
@ -656,8 +697,7 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
VkResult vr;
|
VkResult vr;
|
||||||
|
|
||||||
if (!vulkan_funcs)
|
if (!vulkan_init()) goto done;
|
||||||
goto done;
|
|
||||||
|
|
||||||
memset( &create_info, 0, sizeof(create_info) );
|
memset( &create_info, 0, sizeof(create_info) );
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
|
@ -665,7 +705,7 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
|
||||||
create_info.ppEnabledExtensionNames = extensions;
|
create_info.ppEnabledExtensionNames = extensions;
|
||||||
|
|
||||||
#define LOAD_VK_FUNC(f) \
|
#define LOAD_VK_FUNC(f) \
|
||||||
if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \
|
if (!(p##f = (void *)p_vkGetInstanceProcAddr( vk_instance, #f ))) \
|
||||||
{ \
|
{ \
|
||||||
WARN("Failed to load " #f ".\n"); \
|
WARN("Failed to load " #f ".\n"); \
|
||||||
goto done; \
|
goto done; \
|
||||||
|
@ -683,6 +723,7 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
|
||||||
LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
|
LOAD_VK_FUNC(vkEnumeratePhysicalDevices)
|
||||||
LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR)
|
LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR)
|
||||||
LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
|
LOAD_VK_FUNC(vkGetRandROutputDisplayEXT)
|
||||||
|
LOAD_VK_FUNC(vkDestroyInstance)
|
||||||
#undef LOAD_VK_FUNC
|
#undef LOAD_VK_FUNC
|
||||||
|
|
||||||
vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
|
vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL );
|
||||||
|
@ -747,12 +788,7 @@ static BOOL get_gpu_properties_from_vulkan( struct x11drv_gpu *gpu, const XRRPro
|
||||||
|
|
||||||
done:
|
done:
|
||||||
free( vk_physical_devices );
|
free( vk_physical_devices );
|
||||||
if (vk_instance)
|
if (vk_instance && pvkDestroyInstance) pvkDestroyInstance( vk_instance, NULL );
|
||||||
{
|
|
||||||
PFN_vkDestroyInstance p_vkDestroyInstance;
|
|
||||||
p_vkDestroyInstance = vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, "vkDestroyInstance" );
|
|
||||||
p_vkDestroyInstance( vk_instance, NULL );
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3016,9 +3016,7 @@ struct get_serial_info_reply
|
||||||
{
|
{
|
||||||
struct reply_header __header;
|
struct reply_header __header;
|
||||||
unsigned int eventmask;
|
unsigned int eventmask;
|
||||||
unsigned int cookie;
|
|
||||||
unsigned int pending_write;
|
unsigned int pending_write;
|
||||||
char __pad_20[4];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -3035,7 +3033,6 @@ struct set_serial_info_reply
|
||||||
struct reply_header __header;
|
struct reply_header __header;
|
||||||
};
|
};
|
||||||
#define SERIALINFO_PENDING_WRITE 0x04
|
#define SERIALINFO_PENDING_WRITE 0x04
|
||||||
#define SERIALINFO_PENDING_WAIT 0x08
|
|
||||||
|
|
||||||
|
|
||||||
struct cancel_sync_request
|
struct cancel_sync_request
|
||||||
|
@ -6534,7 +6531,7 @@ union generic_reply
|
||||||
|
|
||||||
/* ### protocol_version begin ### */
|
/* ### protocol_version begin ### */
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 806
|
#define SERVER_PROTOCOL_VERSION 808
|
||||||
|
|
||||||
/* ### protocol_version end ### */
|
/* ### protocol_version end ### */
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#define WINE_GLAPI
|
#define WINE_GLAPI
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WINE_WGL_DRIVER_VERSION 25
|
#define WINE_WGL_DRIVER_VERSION 26
|
||||||
|
|
||||||
struct wgl_context;
|
struct wgl_context;
|
||||||
struct wgl_pbuffer;
|
struct wgl_pbuffer;
|
||||||
|
@ -15,6 +15,31 @@ struct wgl_pbuffer;
|
||||||
struct wgl_pixel_format
|
struct wgl_pixel_format
|
||||||
{
|
{
|
||||||
PIXELFORMATDESCRIPTOR pfd;
|
PIXELFORMATDESCRIPTOR pfd;
|
||||||
|
int swap_method;
|
||||||
|
int transparent;
|
||||||
|
int pixel_type;
|
||||||
|
int draw_to_pbuffer;
|
||||||
|
int max_pbuffer_pixels;
|
||||||
|
int max_pbuffer_width;
|
||||||
|
int max_pbuffer_height;
|
||||||
|
int transparent_red_value;
|
||||||
|
int transparent_red_value_valid;
|
||||||
|
int transparent_green_value;
|
||||||
|
int transparent_green_value_valid;
|
||||||
|
int transparent_blue_value;
|
||||||
|
int transparent_blue_value_valid;
|
||||||
|
int transparent_alpha_value;
|
||||||
|
int transparent_alpha_value_valid;
|
||||||
|
int transparent_index_value;
|
||||||
|
int transparent_index_value_valid;
|
||||||
|
int sample_buffers;
|
||||||
|
int samples;
|
||||||
|
int bind_to_texture_rgb;
|
||||||
|
int bind_to_texture_rgba;
|
||||||
|
int bind_to_texture_rectangle_rgb;
|
||||||
|
int bind_to_texture_rectangle_rgba;
|
||||||
|
int framebuffer_srgb_capable;
|
||||||
|
int float_components;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct opengl_funcs
|
struct opengl_funcs
|
||||||
|
|
|
@ -815,17 +815,35 @@ typedef struct DECLSPEC_ALIGN(8) MEM_EXTENDED_PARAMETER {
|
||||||
#define MEM_EXTENDED_PARAMETER_EC_CODE 0x00000040
|
#define MEM_EXTENDED_PARAMETER_EC_CODE 0x00000040
|
||||||
#define MEM_EXTENDED_PARAMETER_IMAGE_NO_HPAT 0x00000080
|
#define MEM_EXTENDED_PARAMETER_IMAGE_NO_HPAT 0x00000080
|
||||||
|
|
||||||
#define PAGE_NOACCESS 0x01
|
#define PAGE_NOACCESS 0x00000001
|
||||||
#define PAGE_READONLY 0x02
|
#define PAGE_READONLY 0x00000002
|
||||||
#define PAGE_READWRITE 0x04
|
#define PAGE_READWRITE 0x00000004
|
||||||
#define PAGE_WRITECOPY 0x08
|
#define PAGE_WRITECOPY 0x00000008
|
||||||
#define PAGE_EXECUTE 0x10
|
#define PAGE_EXECUTE 0x00000010
|
||||||
#define PAGE_EXECUTE_READ 0x20
|
#define PAGE_EXECUTE_READ 0x00000020
|
||||||
#define PAGE_EXECUTE_READWRITE 0x40
|
#define PAGE_EXECUTE_READWRITE 0x00000040
|
||||||
#define PAGE_EXECUTE_WRITECOPY 0x80
|
#define PAGE_EXECUTE_WRITECOPY 0x00000080
|
||||||
#define PAGE_GUARD 0x100
|
#define PAGE_GUARD 0x00000100
|
||||||
#define PAGE_NOCACHE 0x200
|
#define PAGE_NOCACHE 0x00000200
|
||||||
#define PAGE_WRITECOMBINE 0x400
|
#define PAGE_WRITECOMBINE 0x00000400
|
||||||
|
#define PAGE_GRAPHICS_NOACCESS 0x00000800
|
||||||
|
#define PAGE_GRAPHICS_READONLY 0x00001000
|
||||||
|
#define PAGE_GRAPHICS_READWRITE 0x00002000
|
||||||
|
#define PAGE_GRAPHICS_EXECUTE 0x00004000
|
||||||
|
#define PAGE_GRAPHICS_EXECUTE_READ 0x00008000
|
||||||
|
#define PAGE_GRAPHICS_EXECUTE_READWRITE 0x00010000
|
||||||
|
#define PAGE_GRAPHICS_COHERENT 0x00020000
|
||||||
|
#define PAGE_GRAPHICS_NOCACHE 0x00040000
|
||||||
|
#define PAGE_ENCLAVE_MASK 0x10000000
|
||||||
|
#define PAGE_ENCLAVE_UNVALIDATED 0x20000000
|
||||||
|
#define PAGE_ENCLAVE_NO_CHANGE 0x20000000
|
||||||
|
#define PAGE_TARGETS_NO_UPDATE 0x40000000
|
||||||
|
#define PAGE_TARGETS_INVALID 0x40000000
|
||||||
|
#define PAGE_REVERT_TO_FILE_MAP 0x80000000
|
||||||
|
#define PAGE_ENCLAVE_THREAD_CONTROL 0x80000000
|
||||||
|
#define PAGE_ENCLAVE_DECOMMIT (PAGE_ENCLAVE_MASK | 0)
|
||||||
|
#define PAGE_ENCLAVE_SS_FIRST (PAGE_ENCLAVE_MASK | 1)
|
||||||
|
#define PAGE_ENCLAVE_SS_REST (PAGE_ENCLAVE_MASK | 2)
|
||||||
|
|
||||||
#define MEM_COMMIT 0x00001000
|
#define MEM_COMMIT 0x00001000
|
||||||
#define MEM_RESERVE 0x00002000
|
#define MEM_RESERVE 0x00002000
|
||||||
|
|
|
@ -1546,8 +1546,8 @@ void WCMD_echo (const WCHAR *args)
|
||||||
* first command to be executed may not be at the front of the
|
* first command to be executed may not be at the front of the
|
||||||
* commands->thiscommand string (eg. it may point after a DO or ELSE)
|
* commands->thiscommand string (eg. it may point after a DO or ELSE)
|
||||||
*/
|
*/
|
||||||
static void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
||||||
BOOL isIF, BOOL executecmds)
|
BOOL isIF, BOOL executecmds)
|
||||||
{
|
{
|
||||||
CMD_NODE *curPosition = *cmdList;
|
CMD_NODE *curPosition = *cmdList;
|
||||||
int myDepth = CMD_node_get_depth(*cmdList);
|
int myDepth = CMD_node_get_depth(*cmdList);
|
||||||
|
@ -1850,11 +1850,11 @@ static void WCMD_add_dirstowalk(DIRECTORY_STACK *dirsToWalk)
|
||||||
* are recursively passed. If any have duplicates, then the * token should
|
* are recursively passed. If any have duplicates, then the * token should
|
||||||
* not be honoured.
|
* not be honoured.
|
||||||
*/
|
*/
|
||||||
static int WCMD_for_nexttoken(int lasttoken, WCHAR *tokenstr,
|
int WCMD_for_nexttoken(int lasttoken, const WCHAR *tokenstr,
|
||||||
int *totalfound, BOOL *doall,
|
int *totalfound, BOOL *doall,
|
||||||
BOOL *duplicates)
|
BOOL *duplicates)
|
||||||
{
|
{
|
||||||
WCHAR *pos = tokenstr;
|
const WCHAR *pos = tokenstr;
|
||||||
int nexttoken = -1;
|
int nexttoken = -1;
|
||||||
|
|
||||||
if (totalfound) *totalfound = 0;
|
if (totalfound) *totalfound = 0;
|
||||||
|
@ -2136,7 +2136,7 @@ static FILE *WCMD_forf_getinput(BOOL usebackq, WCHAR *itemstr, BOOL iscmd)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
static void WCMD_for_OLD (WCHAR *p, CMD_NODE **cmdList) {
|
||||||
|
|
||||||
WIN32_FIND_DATAW fd;
|
WIN32_FIND_DATAW fd;
|
||||||
HANDLE hff;
|
HANDLE hff;
|
||||||
|
@ -2541,6 +2541,32 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
|
||||||
if (cmdEnd && CMD_node_get_command(cmdEnd)->command == NULL) *cmdList = CMD_node_next(cmdEnd);
|
if (cmdEnd && CMD_node_get_command(cmdEnd)->command == NULL) *cmdList = CMD_node_next(cmdEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WCMD_for(WCHAR *p, CMD_NODE **cmdList)
|
||||||
|
{
|
||||||
|
CMD_FOR_CONTROL *for_ctrl;
|
||||||
|
|
||||||
|
for_ctrl = for_control_parse(p);
|
||||||
|
if (!for_ctrl)
|
||||||
|
{
|
||||||
|
/* temporary code: use OLD code for non migrated FOR constructs */
|
||||||
|
WCMD_for_OLD(p, cmdList);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (*cmdList = CMD_node_next(*cmdList); /* swallow options */
|
||||||
|
*cmdList && CMD_node_get_command(*cmdList)->command != NULL;
|
||||||
|
*cmdList = CMD_node_next(*cmdList))
|
||||||
|
{
|
||||||
|
for_control_append_set(for_ctrl, CMD_node_get_command(*cmdList)->command);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* step over terminating NULL CMD_NODE of set */
|
||||||
|
*cmdList = CMD_node_next(*cmdList);
|
||||||
|
|
||||||
|
for_control_execute(for_ctrl, cmdList);
|
||||||
|
for_control_dispose(for_ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* WCMD_give_help
|
* WCMD_give_help
|
||||||
*
|
*
|
||||||
|
|
|
@ -757,11 +757,6 @@ setlocal EnableDelayedExpansion
|
||||||
set WINE_FOO=foo bar
|
set WINE_FOO=foo bar
|
||||||
for %%i in ("!WINE_FOO!") do echo %%i
|
for %%i in ("!WINE_FOO!") do echo %%i
|
||||||
for %%i in (!WINE_FOO!) do echo %%i
|
for %%i in (!WINE_FOO!) do echo %%i
|
||||||
rem tests disabled for now... wine's cmd loops endlessly here
|
|
||||||
rem set WINE_FOO=4 4 4
|
|
||||||
rem for /l %%i in (!WINE_FOO!) do echo %%i
|
|
||||||
rem set WINE_FOO=4
|
|
||||||
rem for /l %%i in (1 2 !WINE_FOO!) do echo %%i
|
|
||||||
setlocal DisableDelayedExpansion
|
setlocal DisableDelayedExpansion
|
||||||
|
|
||||||
echo --- in digit variables
|
echo --- in digit variables
|
||||||
|
|
|
@ -1014,21 +1014,21 @@ A D
|
||||||
B C
|
B C
|
||||||
B D
|
B D
|
||||||
--- nested FORs and args tempering
|
--- nested FORs and args tempering
|
||||||
@todo_wine@inner argument {-foo, bar}
|
inner argument {-foo, bar}
|
||||||
@todo_wine@inner argument {-x, y}
|
inner argument {-x, y}
|
||||||
--- nesting and delayed expansion
|
--- nesting and delayed expansion
|
||||||
a 1 2
|
a 1 2
|
||||||
@todo_wine@1-A2
|
1-A2
|
||||||
@todo_wine@1-B1
|
1-B1
|
||||||
@todo_wine@2-A1
|
2-A1
|
||||||
@todo_wine@2-B2
|
2-B2
|
||||||
@todo_wine@b 1 3
|
b 1 3
|
||||||
@todo_wine@1-A2
|
1-A2
|
||||||
@todo_wine@1-B1
|
1-B1
|
||||||
@todo_wine@2-A2
|
2-A2
|
||||||
@todo_wine@2-B2
|
2-B2
|
||||||
@todo_wine@3-A1
|
3-A1
|
||||||
@todo_wine@3-B2
|
3-B2
|
||||||
--- nesting if/for
|
--- nesting if/for
|
||||||
@todo_wine@"f"
|
@todo_wine@"f"
|
||||||
@todo_wine@"g"
|
@todo_wine@"g"
|
||||||
|
@ -1385,7 +1385,7 @@ h=%h i=b j=c k= l= m=%m n=%n o=%o@or_broken@h=%h i=b j=c k= l= m= n=%n o=%o
|
||||||
h=%h i=b j=c k= l= m=%m n=%n o=%o@or_broken@h=%h i=b j=c k= l= m= n=%n o=%o
|
h=%h i=b j=c k= l= m=%m n=%n o=%o@or_broken@h=%h i=b j=c k= l= m= n=%n o=%o
|
||||||
1:3.14,%B
|
1:3.14,%B
|
||||||
2:3.14,
|
2:3.14,
|
||||||
@todo_wine@4:3,14
|
4:3,14
|
||||||
------ parameter splitting
|
------ parameter splitting
|
||||||
:forFParameterSplittingFunc myparam1=myvalue1 myparam2=myparam2 mytest@space@@space@@space@
|
:forFParameterSplittingFunc myparam1=myvalue1 myparam2=myparam2 mytest@space@@space@@space@
|
||||||
:forFParameterSplittingFunc myparam1=myvalue1 myparam2=myparam2 mytest@space@@space@@space@
|
:forFParameterSplittingFunc myparam1=myvalue1 myparam2=myparam2 mytest@space@@space@@space@
|
||||||
|
|
|
@ -83,6 +83,27 @@ typedef struct _CMD_IF_CONDITION
|
||||||
};
|
};
|
||||||
} CMD_IF_CONDITION;
|
} CMD_IF_CONDITION;
|
||||||
|
|
||||||
|
typedef struct _CMD_FOR_CONTROL
|
||||||
|
{
|
||||||
|
enum for_control_operator {
|
||||||
|
CMD_FOR_FILE_SET /* /F */,
|
||||||
|
CMD_FOR_NUMBERS /* /L */} operator;
|
||||||
|
unsigned flags; /* |-ed CMD_FOR_FLAG_* */
|
||||||
|
int variable_index;
|
||||||
|
const WCHAR *set;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct /* for CMD_FOR_FILE_SET */
|
||||||
|
{
|
||||||
|
WCHAR eol;
|
||||||
|
BOOL use_backq;
|
||||||
|
int num_lines_to_skip;
|
||||||
|
const WCHAR *delims;
|
||||||
|
const WCHAR *tokens;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} CMD_FOR_CONTROL;
|
||||||
|
|
||||||
typedef struct _CMD_COMMAND
|
typedef struct _CMD_COMMAND
|
||||||
{
|
{
|
||||||
WCHAR *command; /* Command string to execute */
|
WCHAR *command; /* Command string to execute */
|
||||||
|
@ -129,6 +150,21 @@ void if_condition_dispose(CMD_IF_CONDITION *);
|
||||||
BOOL if_condition_evaluate(CMD_IF_CONDITION *cond, int *test);
|
BOOL if_condition_evaluate(CMD_IF_CONDITION *cond, int *test);
|
||||||
const char *debugstr_if_condition(const CMD_IF_CONDITION *cond);
|
const char *debugstr_if_condition(const CMD_IF_CONDITION *cond);
|
||||||
|
|
||||||
|
void for_control_create(enum for_control_operator for_op, unsigned flags, const WCHAR *options, int var_idx, CMD_FOR_CONTROL *for_ctrl);
|
||||||
|
void for_control_create_fileset(unsigned flags, int var_idx, WCHAR eol, int num_lines_to_skip, BOOL use_backq,
|
||||||
|
const WCHAR *delims, const WCHAR *tokens,
|
||||||
|
CMD_FOR_CONTROL *for_ctrl);
|
||||||
|
CMD_FOR_CONTROL *for_control_parse(WCHAR *opts_var);
|
||||||
|
void for_control_append_set(CMD_FOR_CONTROL *for_ctrl, const WCHAR *string);
|
||||||
|
void for_control_dump(const CMD_FOR_CONTROL *for_ctrl);
|
||||||
|
void for_control_dispose(CMD_FOR_CONTROL *for_ctrl);
|
||||||
|
void for_control_execute(CMD_FOR_CONTROL *for_ctrl, CMD_NODE **cmdList);
|
||||||
|
int WCMD_for_nexttoken(int lasttoken, const WCHAR *tokenstr,
|
||||||
|
int *totalfound, BOOL *doall,
|
||||||
|
BOOL *duplicates);
|
||||||
|
void WCMD_part_execute(CMD_NODE **cmdList, const WCHAR *firstcmd,
|
||||||
|
BOOL isIF, BOOL executecmds);
|
||||||
|
|
||||||
void WCMD_assoc (const WCHAR *, BOOL);
|
void WCMD_assoc (const WCHAR *, BOOL);
|
||||||
void WCMD_batch (WCHAR *, WCHAR *, BOOL, WCHAR *, HANDLE);
|
void WCMD_batch (WCHAR *, WCHAR *, BOOL, WCHAR *, HANDLE);
|
||||||
void WCMD_call (WCHAR *command);
|
void WCMD_call (WCHAR *command);
|
||||||
|
|
|
@ -991,6 +991,94 @@ static void command_dispose(CMD_COMMAND *cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void for_control_dispose(CMD_FOR_CONTROL *for_ctrl)
|
||||||
|
{
|
||||||
|
free((void*)for_ctrl->set);
|
||||||
|
switch (for_ctrl->operator)
|
||||||
|
{
|
||||||
|
case CMD_FOR_FILE_SET:
|
||||||
|
free((void*)for_ctrl->delims);
|
||||||
|
free((void*)for_ctrl->tokens);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *debugstr_for_control(const CMD_FOR_CONTROL *for_ctrl)
|
||||||
|
{
|
||||||
|
static const char* for_ctrl_strings[] = {"file", "numbers"};
|
||||||
|
const char *flags, *options;
|
||||||
|
|
||||||
|
if (for_ctrl->operator >= ARRAY_SIZE(for_ctrl_strings))
|
||||||
|
{
|
||||||
|
FIXME("Unexpected operator\n");
|
||||||
|
return wine_dbg_sprintf("<<%u>>", for_ctrl->operator);
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = "";
|
||||||
|
switch (for_ctrl->operator)
|
||||||
|
{
|
||||||
|
case CMD_FOR_FILE_SET:
|
||||||
|
{
|
||||||
|
WCHAR eol_buf[4] = {L'\'', for_ctrl->eol, L'\'', L'\0'};
|
||||||
|
const WCHAR *eol = for_ctrl->eol ? eol_buf : L"<nul>";
|
||||||
|
options = wine_dbg_sprintf("eol=%ls skip=%d use_backq=%c delims=%s tokens=%s ",
|
||||||
|
eol, for_ctrl->num_lines_to_skip, for_ctrl->use_backq ? 'Y' : 'N',
|
||||||
|
wine_dbgstr_w(for_ctrl->delims), wine_dbgstr_w(for_ctrl->tokens));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
options = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return wine_dbg_sprintf("[FOR] %s %s%s%%%c (%ls)",
|
||||||
|
for_ctrl_strings[for_ctrl->operator], flags, options,
|
||||||
|
for_var_index_to_char(for_ctrl->variable_index), for_ctrl->set);
|
||||||
|
}
|
||||||
|
|
||||||
|
void for_control_create(enum for_control_operator for_op, unsigned flags, const WCHAR *options, int var_idx, CMD_FOR_CONTROL *for_ctrl)
|
||||||
|
{
|
||||||
|
for_ctrl->operator = for_op;
|
||||||
|
for_ctrl->flags = flags;
|
||||||
|
for_ctrl->variable_index = var_idx;
|
||||||
|
for_ctrl->set = NULL;
|
||||||
|
switch (for_ctrl->operator)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void for_control_create_fileset(unsigned flags, int var_idx, WCHAR eol, int num_lines_to_skip, BOOL use_backq,
|
||||||
|
const WCHAR *delims, const WCHAR *tokens,
|
||||||
|
CMD_FOR_CONTROL *for_ctrl)
|
||||||
|
{
|
||||||
|
for_ctrl->operator = CMD_FOR_FILE_SET;
|
||||||
|
for_ctrl->flags = flags;
|
||||||
|
for_ctrl->variable_index = var_idx;
|
||||||
|
for_ctrl->set = NULL;
|
||||||
|
|
||||||
|
for_ctrl->eol = eol;
|
||||||
|
for_ctrl->use_backq = use_backq;
|
||||||
|
for_ctrl->num_lines_to_skip = num_lines_to_skip;
|
||||||
|
for_ctrl->delims = delims;
|
||||||
|
for_ctrl->tokens = tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
void for_control_append_set(CMD_FOR_CONTROL *for_ctrl, const WCHAR *set)
|
||||||
|
{
|
||||||
|
if (for_ctrl->set)
|
||||||
|
{
|
||||||
|
for_ctrl->set = xrealloc((void*)for_ctrl->set,
|
||||||
|
(wcslen(for_ctrl->set) + 1 + wcslen(set) + 1) * sizeof(WCHAR));
|
||||||
|
wcscat((WCHAR*)for_ctrl->set, L" ");
|
||||||
|
wcscat((WCHAR*)for_ctrl->set, set);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for_ctrl->set = xstrdupW(set);
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* node_dispose_tree
|
* node_dispose_tree
|
||||||
*
|
*
|
||||||
|
@ -2093,6 +2181,170 @@ static BOOL WCMD_IsEndQuote(const WCHAR *quote, int quoteIndex)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WCHAR *for_fileset_option_split(WCHAR *from, const WCHAR* key)
|
||||||
|
{
|
||||||
|
size_t len = wcslen(key);
|
||||||
|
|
||||||
|
if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
|
||||||
|
from, len, key, len) != CSTR_EQUAL)
|
||||||
|
return NULL;
|
||||||
|
from += len;
|
||||||
|
if (len && key[len - 1] == L'=')
|
||||||
|
while (*from && *from != L' ' && *from != L'\t') from++;
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
CMD_FOR_CONTROL *for_control_parse(WCHAR *opts_var)
|
||||||
|
{
|
||||||
|
CMD_FOR_CONTROL *for_ctrl;
|
||||||
|
enum for_control_operator for_op;
|
||||||
|
WCHAR mode = L' ', option;
|
||||||
|
WCHAR options[MAXSTRING];
|
||||||
|
WCHAR *arg;
|
||||||
|
unsigned flags = 0;
|
||||||
|
int arg_index;
|
||||||
|
int var_idx;
|
||||||
|
|
||||||
|
options[0] = L'\0';
|
||||||
|
/* native allows two options only in the /D /R case, a repetition of the option
|
||||||
|
* and prints an error otherwise
|
||||||
|
*/
|
||||||
|
for (arg_index = 0; ; arg_index++)
|
||||||
|
{
|
||||||
|
arg = WCMD_parameter(opts_var, arg_index, NULL, FALSE, FALSE);
|
||||||
|
|
||||||
|
if (!arg || *arg != L'/') break;
|
||||||
|
option = towupper(arg[1]);
|
||||||
|
if (mode != L' ' && (mode != L'D' || option != 'R') && mode != option)
|
||||||
|
break;
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case L'R':
|
||||||
|
if (mode == L'D')
|
||||||
|
{
|
||||||
|
mode = L'X';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall thru */
|
||||||
|
case L'D':
|
||||||
|
case L'L':
|
||||||
|
case L'F':
|
||||||
|
mode = option;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* error unexpected 'arg' at this time */
|
||||||
|
WARN("for qualifier '%c' unhandled\n", *arg);
|
||||||
|
goto syntax_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case L'L':
|
||||||
|
for_op = CMD_FOR_NUMBERS;
|
||||||
|
break;
|
||||||
|
case L'F':
|
||||||
|
for_op = CMD_FOR_FILE_SET;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == L'F')
|
||||||
|
{
|
||||||
|
/* Retrieve next parameter to see if is root/options (raw form required
|
||||||
|
* with for /f, or unquoted in for /r)
|
||||||
|
*/
|
||||||
|
arg = WCMD_parameter(opts_var, arg_index, NULL, for_op == CMD_FOR_FILE_SET, FALSE);
|
||||||
|
|
||||||
|
/* Next parm is either qualifier, path/options or variable -
|
||||||
|
* only care about it if it is the path/options
|
||||||
|
*/
|
||||||
|
if (arg && *arg != L'/' && *arg != L'%')
|
||||||
|
{
|
||||||
|
arg_index++;
|
||||||
|
wcscpy(options, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure line continues with variable */
|
||||||
|
arg = WCMD_parameter(opts_var, arg_index++, NULL, FALSE, FALSE);
|
||||||
|
if (!arg || *arg != L'%' || (var_idx = for_var_char_to_index(arg[1])) == -1)
|
||||||
|
goto syntax_error; /* FIXME native prints the offending token "%<whatever>" was unexpected at this time */
|
||||||
|
for_ctrl = xalloc(sizeof(*for_ctrl));
|
||||||
|
if (for_op == CMD_FOR_FILE_SET)
|
||||||
|
{
|
||||||
|
size_t len = wcslen(options);
|
||||||
|
WCHAR *p = options, *end;
|
||||||
|
WCHAR eol = L'\0';
|
||||||
|
int num_lines_to_skip = 0;
|
||||||
|
BOOL use_backq = FALSE;
|
||||||
|
WCHAR *delims = NULL, *tokens = NULL;
|
||||||
|
/* strip enclosing double-quotes when present */
|
||||||
|
if (len >= 2 && p[0] == L'"' && p[len - 1] == L'"')
|
||||||
|
{
|
||||||
|
p[len - 1] = L'\0';
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
for ( ; *p; p = end)
|
||||||
|
{
|
||||||
|
p = WCMD_skip_leading_spaces(p);
|
||||||
|
/* Save End of line character (Ignore line if first token (based on delims) starts with it) */
|
||||||
|
if ((end = for_fileset_option_split(p, L"eol=")))
|
||||||
|
{
|
||||||
|
/* assuming one char for eol marker */
|
||||||
|
if (end != p + 5) goto syntax_error;
|
||||||
|
eol = p[4];
|
||||||
|
}
|
||||||
|
/* Save number of lines to skip (Can be in base 10, hex (0x...) or octal (0xx) */
|
||||||
|
else if ((end = for_fileset_option_split(p, L"skip=")))
|
||||||
|
{
|
||||||
|
WCHAR *nextchar;
|
||||||
|
num_lines_to_skip = wcstoul(p + 5, &nextchar, 0);
|
||||||
|
if (end != nextchar) goto syntax_error;
|
||||||
|
}
|
||||||
|
/* Save if usebackq semantics are in effect */
|
||||||
|
else if ((end = for_fileset_option_split(p, L"usebackq")))
|
||||||
|
use_backq = TRUE;
|
||||||
|
/* Save the supplied delims */
|
||||||
|
else if ((end = for_fileset_option_split(p, L"delims=")))
|
||||||
|
{
|
||||||
|
size_t copy_len;
|
||||||
|
|
||||||
|
/* interpret space when last character of whole options string as part of delims= */
|
||||||
|
if (end[0] && !end[1]) end++;
|
||||||
|
copy_len = end - (p + 7) /* delims= */;
|
||||||
|
delims = xalloc((copy_len + 1) * sizeof(WCHAR));
|
||||||
|
memcpy(delims, p + 7, copy_len * sizeof(WCHAR));
|
||||||
|
delims[copy_len] = L'\0';
|
||||||
|
}
|
||||||
|
/* Save the tokens being requested */
|
||||||
|
else if ((end = for_fileset_option_split(p, L"tokens=")))
|
||||||
|
{
|
||||||
|
size_t copy_len;
|
||||||
|
|
||||||
|
copy_len = end - (p + 7) /* tokens= */;
|
||||||
|
tokens = xalloc((copy_len + 1) * sizeof(WCHAR));
|
||||||
|
memcpy(tokens, p + 7, copy_len * sizeof(WCHAR));
|
||||||
|
tokens[copy_len] = L'\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARN("FOR option not found %ls\n", p);
|
||||||
|
goto syntax_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for_control_create_fileset(flags, var_idx, eol, num_lines_to_skip, use_backq,
|
||||||
|
delims ? delims : xstrdupW(L" \t"),
|
||||||
|
tokens ? tokens : xstrdupW(L"1"), for_ctrl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for_control_create(for_op, flags, options, var_idx, for_ctrl);
|
||||||
|
return for_ctrl;
|
||||||
|
syntax_error:
|
||||||
|
WCMD_output_stderr(WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* WCMD_ReadAndParseLine
|
* WCMD_ReadAndParseLine
|
||||||
*
|
*
|
||||||
|
@ -2710,6 +2962,97 @@ BOOL if_condition_evaluate(CMD_IF_CONDITION *cond, int *test)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CMD_NODE *for_loop_fileset_parse_line(CMD_NODE *cmdList, int varidx, WCHAR *buffer,
|
||||||
|
WCHAR forf_eol, const WCHAR *forf_delims, const WCHAR *forf_tokens)
|
||||||
|
{
|
||||||
|
WCHAR *parm;
|
||||||
|
int varoffset;
|
||||||
|
int nexttoken, lasttoken = -1;
|
||||||
|
BOOL starfound = FALSE;
|
||||||
|
BOOL thisduplicate = FALSE;
|
||||||
|
BOOL anyduplicates = FALSE;
|
||||||
|
int totalfound;
|
||||||
|
static WCHAR emptyW[] = L"";
|
||||||
|
|
||||||
|
/* Extract the parameters based on the tokens= value (There will always
|
||||||
|
be some value, as if it is not supplied, it defaults to tokens=1).
|
||||||
|
Rough logic:
|
||||||
|
Count how many tokens are named in the line, identify the lowest
|
||||||
|
Empty (set to null terminated string) that number of named variables
|
||||||
|
While lasttoken != nextlowest
|
||||||
|
%letter = parameter number 'nextlowest'
|
||||||
|
letter++ (if >26 or >52 abort)
|
||||||
|
Go through token= string finding next lowest number
|
||||||
|
If token ends in * set %letter = raw position of token(nextnumber+1)
|
||||||
|
*/
|
||||||
|
lasttoken = -1;
|
||||||
|
nexttoken = WCMD_for_nexttoken(lasttoken, forf_tokens, &totalfound,
|
||||||
|
&starfound, &thisduplicate);
|
||||||
|
|
||||||
|
TRACE("Using var=%lc on %d max\n", for_var_index_to_char(varidx), totalfound);
|
||||||
|
/* Empty out variables */
|
||||||
|
for (varoffset = 0;
|
||||||
|
varoffset < totalfound && for_var_index_in_range(varidx, varoffset);
|
||||||
|
varoffset++)
|
||||||
|
WCMD_set_for_loop_variable(varidx + varoffset, emptyW);
|
||||||
|
|
||||||
|
/* Loop extracting the tokens
|
||||||
|
* Note: nexttoken of 0 means there were no tokens requested, to handle
|
||||||
|
* the special case of tokens=*
|
||||||
|
*/
|
||||||
|
varoffset = 0;
|
||||||
|
TRACE("Parsing buffer into tokens: '%s'\n", wine_dbgstr_w(buffer));
|
||||||
|
while (nexttoken > 0 && (nexttoken > lasttoken))
|
||||||
|
{
|
||||||
|
anyduplicates |= thisduplicate;
|
||||||
|
|
||||||
|
if (!for_var_index_in_range(varidx, varoffset))
|
||||||
|
{
|
||||||
|
WARN("Out of range offset\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Extract the token number requested and set into the next variable context */
|
||||||
|
parm = WCMD_parameter_with_delims(buffer, (nexttoken-1), NULL, TRUE, FALSE, forf_delims);
|
||||||
|
TRACE("Parsed token %d(%d) as parameter %s\n", nexttoken,
|
||||||
|
varidx + varoffset, wine_dbgstr_w(parm));
|
||||||
|
if (parm)
|
||||||
|
{
|
||||||
|
WCMD_set_for_loop_variable(varidx + varoffset, parm);
|
||||||
|
varoffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the next token */
|
||||||
|
lasttoken = nexttoken;
|
||||||
|
nexttoken = WCMD_for_nexttoken(lasttoken, forf_tokens, NULL,
|
||||||
|
&starfound, &thisduplicate);
|
||||||
|
}
|
||||||
|
/* If all the rest of the tokens were requested, and there is still space in
|
||||||
|
* the variable range, write them now
|
||||||
|
*/
|
||||||
|
if (!anyduplicates && starfound && for_var_index_in_range(varidx, varoffset))
|
||||||
|
{
|
||||||
|
nexttoken++;
|
||||||
|
WCMD_parameter_with_delims(buffer, (nexttoken-1), &parm, FALSE, FALSE, forf_delims);
|
||||||
|
TRACE("Parsed all remaining tokens (%d) as parameter %s\n",
|
||||||
|
varidx + varoffset, wine_dbgstr_w(parm));
|
||||||
|
if (parm)
|
||||||
|
WCMD_set_for_loop_variable(varidx + varoffset, parm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute the body of the for loop with these values */
|
||||||
|
if (forloopcontext->variable[varidx] && forloopcontext->variable[varidx][0] != forf_eol)
|
||||||
|
{
|
||||||
|
/* +3 for "do " */
|
||||||
|
WCMD_part_execute(&cmdList, CMD_node_get_command(cmdList)->command + 3, FALSE, TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TRACE("Skipping line because of eol\n");
|
||||||
|
cmdList = NULL;
|
||||||
|
}
|
||||||
|
return cmdList;
|
||||||
|
}
|
||||||
|
|
||||||
void WCMD_save_for_loop_context(BOOL reset)
|
void WCMD_save_for_loop_context(BOOL reset)
|
||||||
{
|
{
|
||||||
FOR_CONTEXT *new = xalloc(sizeof(*new));
|
FOR_CONTEXT *new = xalloc(sizeof(*new));
|
||||||
|
@ -2748,6 +3091,179 @@ void WCMD_set_for_loop_variable(int var_idx, const WCHAR *value)
|
||||||
forloopcontext->variable[var_idx] = xstrdupW(value);
|
forloopcontext->variable[var_idx] = xstrdupW(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL match_ending_delim(WCHAR *string)
|
||||||
|
{
|
||||||
|
WCHAR *to = string + wcslen(string);
|
||||||
|
|
||||||
|
/* strip trailing delim */
|
||||||
|
if (to > string) to--;
|
||||||
|
if (to > string && *to == string[0])
|
||||||
|
{
|
||||||
|
*to = L'\0';
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
WARN("Can't find ending delimiter (%ls)\n", string);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMD_NODE *for_control_execute_from_FILE(CMD_FOR_CONTROL *for_ctrl, FILE *input, CMD_NODE *cmdList)
|
||||||
|
{
|
||||||
|
WCHAR buffer[MAXSTRING];
|
||||||
|
int skip_count = for_ctrl->num_lines_to_skip;
|
||||||
|
CMD_NODE *body = NULL;
|
||||||
|
|
||||||
|
/* Read line by line until end of file */
|
||||||
|
while (fgetws(buffer, ARRAY_SIZE(buffer), input))
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (skip_count)
|
||||||
|
{
|
||||||
|
TRACE("skipping %d\n", skip_count);
|
||||||
|
skip_count--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
len = wcslen(buffer);
|
||||||
|
/* Either our buffer isn't large enough to fit a full line, or there's a stray
|
||||||
|
* '\0' in the buffer.
|
||||||
|
*/
|
||||||
|
if (!feof(input) && (len == 0 || (buffer[len - 1] != '\n' && buffer[len - 1] != '\r')))
|
||||||
|
break;
|
||||||
|
while (len && (buffer[len - 1] == '\n' || buffer[len - 1] == '\r'))
|
||||||
|
buffer[--len] = L'\0';
|
||||||
|
body = for_loop_fileset_parse_line(cmdList, for_ctrl->variable_index, buffer,
|
||||||
|
for_ctrl->eol, for_ctrl->delims, for_ctrl->tokens);
|
||||||
|
buffer[0] = 0;
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMD_NODE *for_control_execute_fileset(CMD_FOR_CONTROL *for_ctrl, CMD_NODE *cmdList)
|
||||||
|
{
|
||||||
|
WCHAR set[MAXSTRING];
|
||||||
|
WCHAR *args;
|
||||||
|
size_t len;
|
||||||
|
CMD_NODE *body = NULL;
|
||||||
|
FILE *input;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
wcscpy(set, for_ctrl->set);
|
||||||
|
handleExpansion(set, context != NULL, delayedsubst);
|
||||||
|
|
||||||
|
args = WCMD_skip_leading_spaces(set);
|
||||||
|
for (len = wcslen(args); len && (args[len - 1] == L' ' || args[len - 1] == L'\t'); len--)
|
||||||
|
args[len - 1] = L'\0';
|
||||||
|
if (args[0] == (for_ctrl->use_backq ? L'\'' : L'"') && match_ending_delim(args))
|
||||||
|
{
|
||||||
|
args++;
|
||||||
|
if (!for_ctrl->num_lines_to_skip)
|
||||||
|
{
|
||||||
|
body = for_loop_fileset_parse_line(cmdList, for_ctrl->variable_index, args,
|
||||||
|
for_ctrl->eol, for_ctrl->delims, for_ctrl->tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[0] == (for_ctrl->use_backq ? L'`' : L'\'') && match_ending_delim(args))
|
||||||
|
{
|
||||||
|
WCHAR temp_cmd[MAX_PATH];
|
||||||
|
|
||||||
|
args++;
|
||||||
|
wsprintfW(temp_cmd, L"CMD.EXE /C %s", args);
|
||||||
|
TRACE("Reading output of '%s'\n", wine_dbgstr_w(temp_cmd));
|
||||||
|
input = _wpopen(temp_cmd, L"rt,ccs=unicode");
|
||||||
|
if (!input)
|
||||||
|
{
|
||||||
|
WCMD_print_error();
|
||||||
|
WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), args);
|
||||||
|
errorlevel = 1;
|
||||||
|
return NULL; /* FOR loop aborts at first failure here */
|
||||||
|
}
|
||||||
|
body = for_control_execute_from_FILE(for_ctrl, input, cmdList);
|
||||||
|
fclose(input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; ; i++)
|
||||||
|
{
|
||||||
|
WCHAR *element = WCMD_parameter(args, i, NULL, TRUE, FALSE);
|
||||||
|
if (!element || !*element) break;
|
||||||
|
if (element[0] == L'"' && match_ending_delim(element)) element++;
|
||||||
|
/* Open the file, read line by line and process */
|
||||||
|
TRACE("Reading input to parse from '%s'\n", wine_dbgstr_w(element));
|
||||||
|
input = _wfopen(element, L"rt,ccs=unicode");
|
||||||
|
if (!input)
|
||||||
|
{
|
||||||
|
WCMD_print_error();
|
||||||
|
WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), element);
|
||||||
|
errorlevel = 1;
|
||||||
|
return NULL; /* FOR loop aborts at first failure here */
|
||||||
|
}
|
||||||
|
body = for_control_execute_from_FILE(for_ctrl, input, cmdList);
|
||||||
|
fclose(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CMD_NODE *for_control_execute_numbers(CMD_FOR_CONTROL *for_ctrl, CMD_NODE *cmdList)
|
||||||
|
{
|
||||||
|
WCHAR set[MAXSTRING];
|
||||||
|
CMD_NODE *body = NULL;
|
||||||
|
int numbers[3] = {0, 0, 0}, var;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
wcscpy(set, for_ctrl->set);
|
||||||
|
handleExpansion(set, context != NULL, delayedsubst);
|
||||||
|
|
||||||
|
/* Note: native doesn't check the actual number of parameters, and set
|
||||||
|
* them by default to 0.
|
||||||
|
* so (-10 1) is interpreted as (-10 1 0)
|
||||||
|
* and (10) loops for ever !!!
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ARRAY_SIZE(numbers); i++)
|
||||||
|
{
|
||||||
|
WCHAR *element = WCMD_parameter(set, i, NULL, FALSE, FALSE);
|
||||||
|
if (!element || !*element) break;
|
||||||
|
/* native doesn't no error handling */
|
||||||
|
numbers[i] = wcstol(element, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var = numbers[0];
|
||||||
|
(numbers[1] < 0) ? var >= numbers[2] : var <= numbers[2];
|
||||||
|
var += numbers[1])
|
||||||
|
{
|
||||||
|
WCHAR tmp[32];
|
||||||
|
|
||||||
|
body = cmdList;
|
||||||
|
swprintf(tmp, ARRAY_SIZE(tmp), L"%d", var);
|
||||||
|
WCMD_set_for_loop_variable(for_ctrl->variable_index, tmp);
|
||||||
|
TRACE("Processing FOR number %s\n", wine_dbgstr_w(tmp));
|
||||||
|
WCMD_part_execute(&body, CMD_node_get_command(cmdList)->command + 3, FALSE, TRUE);
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
void for_control_execute(CMD_FOR_CONTROL *for_ctrl, CMD_NODE **cmdList)
|
||||||
|
{
|
||||||
|
CMD_NODE *last;
|
||||||
|
WCMD_save_for_loop_context(FALSE);
|
||||||
|
|
||||||
|
switch (for_ctrl->operator)
|
||||||
|
{
|
||||||
|
case CMD_FOR_FILE_SET:
|
||||||
|
last = for_control_execute_fileset(for_ctrl, *cmdList);
|
||||||
|
break;
|
||||||
|
case CMD_FOR_NUMBERS:
|
||||||
|
last = for_control_execute_numbers(for_ctrl, *cmdList);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
last = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
WCMD_restore_for_loop_context();
|
||||||
|
*cmdList = last;
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* WCMD_process_commands
|
* WCMD_process_commands
|
||||||
*
|
*
|
||||||
|
|
|
@ -2245,7 +2245,6 @@ enum message_type
|
||||||
int flags;
|
int flags;
|
||||||
@REPLY
|
@REPLY
|
||||||
unsigned int eventmask;
|
unsigned int eventmask;
|
||||||
unsigned int cookie;
|
|
||||||
unsigned int pending_write;
|
unsigned int pending_write;
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
@ -2256,7 +2255,6 @@ enum message_type
|
||||||
int flags; /* bitmask to set values (see below) */
|
int flags; /* bitmask to set values (see below) */
|
||||||
@END
|
@END
|
||||||
#define SERIALINFO_PENDING_WRITE 0x04
|
#define SERIALINFO_PENDING_WRITE 0x04
|
||||||
#define SERIALINFO_PENDING_WAIT 0x08
|
|
||||||
|
|
||||||
/* Cancel all sync io on a thread */
|
/* Cancel all sync io on a thread */
|
||||||
@REQ(cancel_sync)
|
@REQ(cancel_sync)
|
||||||
|
|
|
@ -1455,9 +1455,8 @@ C_ASSERT( FIELD_OFFSET(struct get_serial_info_request, handle) == 12 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct get_serial_info_request, flags) == 16 );
|
C_ASSERT( FIELD_OFFSET(struct get_serial_info_request, flags) == 16 );
|
||||||
C_ASSERT( sizeof(struct get_serial_info_request) == 24 );
|
C_ASSERT( sizeof(struct get_serial_info_request) == 24 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct get_serial_info_reply, eventmask) == 8 );
|
C_ASSERT( FIELD_OFFSET(struct get_serial_info_reply, eventmask) == 8 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct get_serial_info_reply, cookie) == 12 );
|
C_ASSERT( FIELD_OFFSET(struct get_serial_info_reply, pending_write) == 12 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct get_serial_info_reply, pending_write) == 16 );
|
C_ASSERT( sizeof(struct get_serial_info_reply) == 16 );
|
||||||
C_ASSERT( sizeof(struct get_serial_info_reply) == 24 );
|
|
||||||
C_ASSERT( FIELD_OFFSET(struct set_serial_info_request, handle) == 12 );
|
C_ASSERT( FIELD_OFFSET(struct set_serial_info_request, handle) == 12 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct set_serial_info_request, flags) == 16 );
|
C_ASSERT( FIELD_OFFSET(struct set_serial_info_request, flags) == 16 );
|
||||||
C_ASSERT( sizeof(struct set_serial_info_request) == 24 );
|
C_ASSERT( sizeof(struct set_serial_info_request) == 24 );
|
||||||
|
|
|
@ -76,9 +76,7 @@ struct serial
|
||||||
struct timeout_user *read_timer;
|
struct timeout_user *read_timer;
|
||||||
SERIAL_TIMEOUTS timeouts;
|
SERIAL_TIMEOUTS timeouts;
|
||||||
unsigned int eventmask;
|
unsigned int eventmask;
|
||||||
unsigned int generation; /* event mask change counter */
|
|
||||||
unsigned int pending_write : 1;
|
unsigned int pending_write : 1;
|
||||||
unsigned int pending_wait : 1;
|
|
||||||
|
|
||||||
struct termios original;
|
struct termios original;
|
||||||
|
|
||||||
|
@ -142,9 +140,7 @@ struct object *create_serial( struct fd *fd )
|
||||||
|
|
||||||
serial->read_timer = NULL;
|
serial->read_timer = NULL;
|
||||||
serial->eventmask = 0;
|
serial->eventmask = 0;
|
||||||
serial->generation = 0;
|
|
||||||
serial->pending_write = 0;
|
serial->pending_write = 0;
|
||||||
serial->pending_wait = 0;
|
|
||||||
memset( &serial->timeouts, 0, sizeof(serial->timeouts) );
|
memset( &serial->timeouts, 0, sizeof(serial->timeouts) );
|
||||||
init_async_queue( &serial->wait_q );
|
init_async_queue( &serial->wait_q );
|
||||||
serial->fd = (struct fd *)grab_object( fd );
|
serial->fd = (struct fd *)grab_object( fd );
|
||||||
|
@ -242,14 +238,19 @@ static void serial_ioctl( struct fd *fd, ioctl_code_t code, struct async *async
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
serial->eventmask = *(unsigned int *)get_req_data();
|
serial->eventmask = *(unsigned int *)get_req_data();
|
||||||
serial->generation++;
|
async_wake_up( &serial->wait_q, STATUS_CANCELLED );
|
||||||
fd_async_wake_up( serial->fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS );
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case IOCTL_SERIAL_WAIT_ON_MASK:
|
case IOCTL_SERIAL_WAIT_ON_MASK:
|
||||||
{
|
{
|
||||||
struct wait_req *req;
|
struct wait_req *req;
|
||||||
|
|
||||||
|
if (async_queued( &serial->wait_q ))
|
||||||
|
{
|
||||||
|
set_error( STATUS_INVALID_PARAMETER );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(req = mem_alloc(sizeof(*req))))
|
if (!(req = mem_alloc(sizeof(*req))))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -329,20 +330,8 @@ DECL_HANDLER(get_serial_info)
|
||||||
|
|
||||||
if ((serial = get_serial_obj( current->process, req->handle, 0 )))
|
if ((serial = get_serial_obj( current->process, req->handle, 0 )))
|
||||||
{
|
{
|
||||||
if (req->flags & SERIALINFO_PENDING_WAIT)
|
|
||||||
{
|
|
||||||
if (serial->pending_wait)
|
|
||||||
{
|
|
||||||
release_object( serial );
|
|
||||||
set_error( STATUS_INVALID_PARAMETER );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
serial->pending_wait = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* event mask */
|
/* event mask */
|
||||||
reply->eventmask = serial->eventmask;
|
reply->eventmask = serial->eventmask;
|
||||||
reply->cookie = serial->generation;
|
|
||||||
|
|
||||||
/* pending write */
|
/* pending write */
|
||||||
reply->pending_write = serial->pending_write;
|
reply->pending_write = serial->pending_write;
|
||||||
|
@ -359,18 +348,6 @@ DECL_HANDLER(set_serial_info)
|
||||||
|
|
||||||
if ((serial = get_serial_obj( current->process, req->handle, 0 )))
|
if ((serial = get_serial_obj( current->process, req->handle, 0 )))
|
||||||
{
|
{
|
||||||
if (req->flags & SERIALINFO_PENDING_WAIT)
|
|
||||||
{
|
|
||||||
if (!serial->pending_wait)
|
|
||||||
{
|
|
||||||
release_object( serial );
|
|
||||||
set_error( STATUS_INVALID_PARAMETER );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
serial->pending_wait = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pending write */
|
|
||||||
if (req->flags & SERIALINFO_PENDING_WRITE)
|
if (req->flags & SERIALINFO_PENDING_WRITE)
|
||||||
serial->pending_write = 1;
|
serial->pending_write = 1;
|
||||||
|
|
||||||
|
|
|
@ -2856,7 +2856,6 @@ static void dump_get_serial_info_request( const struct get_serial_info_request *
|
||||||
static void dump_get_serial_info_reply( const struct get_serial_info_reply *req )
|
static void dump_get_serial_info_reply( const struct get_serial_info_reply *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " eventmask=%08x", req->eventmask );
|
fprintf( stderr, " eventmask=%08x", req->eventmask );
|
||||||
fprintf( stderr, ", cookie=%08x", req->cookie );
|
|
||||||
fprintf( stderr, ", pending_write=%08x", req->pending_write );
|
fprintf( stderr, ", pending_write=%08x", req->pending_write );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user