Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
October 2018
- 60 participants
- 608 discussions
[PATCH 3/4] crypt32: Add support for exporting public key information from a 3rd party CSP.
by Dmitry Timoshkov 22 Oct '18
by Dmitry Timoshkov 22 Oct '18
22 Oct '18
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/crypt32/encode.c | 90 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 81 insertions(+), 9 deletions(-)
diff --git a/dlls/crypt32/encode.c b/dlls/crypt32/encode.c
index 62d2bc91f7..9a9850d683 100644
--- a/dlls/crypt32/encode.c
+++ b/dlls/crypt32/encode.c
@@ -4779,20 +4779,22 @@ BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
NULL, 0, NULL, pInfo, pcbInfo);
}
-static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
+typedef BOOL (WINAPI *EncodePublicKeyAndParametersFunc)(DWORD dwCertEncodingType,
+ LPSTR pszPublicKeyObjId, BYTE *pbPubKey, DWORD cbPubKey, DWORD dwFlags, void *pvAuxInfo,
+ BYTE **ppPublicKey, DWORD *pcbPublicKey, BYTE **ppbParams, DWORD *pcbParams);
+
+static BOOL WINAPI CRYPT_ExportPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
{
BOOL ret;
HCRYPTKEY key;
- static CHAR oid[] = szOID_RSA_RSA;
+ static CHAR rsa_oid[] = szOID_RSA_RSA;
TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv,
dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags,
pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0);
- if (!pszPublicKeyObjId)
- pszPublicKeyObjId = oid;
if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
{
DWORD keySize = 0;
@@ -4800,16 +4802,86 @@ static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDL
ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
if (ret)
{
- LPBYTE pubKey = CryptMemAlloc(keySize);
+ PUBLICKEYSTRUC *pubKey = CryptMemAlloc(keySize);
if (pubKey)
{
- ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
- &keySize);
+ ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, (BYTE *)pubKey, &keySize);
if (ret)
{
- DWORD encodedLen = 0;
+ DWORD encodedLen;
+
+ if (!pszPublicKeyObjId)
+ {
+ static HCRYPTOIDFUNCSET set;
+ EncodePublicKeyAndParametersFunc encodeFunc = NULL;
+ HCRYPTOIDFUNCADDR hFunc = NULL;
+
+ pszPublicKeyObjId = (LPSTR)CertAlgIdToOID(pubKey->aiKeyAlg);
+ TRACE("public key algid %#x (%s)\n", pubKey->aiKeyAlg, debugstr_a(pszPublicKeyObjId));
+
+ if (!set) /* FIXME: there is no a public macro */
+ set = CryptInitOIDFunctionSet("CryptDllEncodePublicKeyAndParameters", 0);
+
+ CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId, 0, (void **)&encodeFunc, &hFunc);
+ if (encodeFunc)
+ {
+ BYTE *key_data = NULL;
+ DWORD key_size = 0;
+ BYTE *params = NULL;
+ DWORD params_size = 0;
+
+ ret = encodeFunc(dwCertEncodingType, pszPublicKeyObjId, (BYTE *)pubKey, keySize,
+ dwFlags, pvAuxInfo, &key_data, &key_size, ¶ms, ¶ms_size);
+ if (ret)
+ {
+ DWORD oid_size = strlen(pszPublicKeyObjId) + 1;
+ DWORD size_needed = sizeof(*pInfo) + oid_size + key_size + params_size;
+
+ if (!pInfo)
+ *pcbInfo = size_needed;
+ else if (*pcbInfo < size_needed)
+ {
+ *pcbInfo = size_needed;
+ SetLastError(ERROR_MORE_DATA);
+ ret = FALSE;
+ }
+ else
+ {
+ *pcbInfo = size_needed;
+ pInfo->Algorithm.pszObjId = (char *)(pInfo + 1);
+ lstrcpyA(pInfo->Algorithm.pszObjId, pszPublicKeyObjId);
+ if (params)
+ {
+ pInfo->Algorithm.Parameters.cbData = params_size;
+ pInfo->Algorithm.Parameters.pbData = (BYTE *)pInfo->Algorithm.pszObjId + oid_size;
+ memcpy(pInfo->Algorithm.Parameters.pbData, params, params_size);
+ }
+ else
+ {
+ pInfo->Algorithm.Parameters.cbData = 0;
+ pInfo->Algorithm.Parameters.pbData = NULL;
+ }
+ pInfo->PublicKey.pbData = (BYTE *)pInfo->Algorithm.pszObjId + oid_size + params_size;
+ pInfo->PublicKey.cbData = key_size;
+ memcpy(pInfo->PublicKey.pbData, key_data, key_size);
+ pInfo->PublicKey.cUnusedBits = 0;
+ }
+
+ CryptMemFree(key_data);
+ CryptMemFree(params);
+ }
+
+ CryptMemFree(pubKey);
+ CryptFreeOIDFunctionAddress(hFunc, 0);
+ return ret;
+ }
+
+ /* fallback to RSA */
+ pszPublicKeyObjId = rsa_oid;
+ }
+ encodedLen = 0;
ret = CryptEncodeObject(dwCertEncodingType,
RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
if (ret)
@@ -4887,7 +4959,7 @@ BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptPro
0, (void **)&exportFunc, &hFunc);
}
if (!exportFunc)
- exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
+ exportFunc = CRYPT_ExportPublicKeyInfoEx;
ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
if (hFunc)
--
2.17.1
1
0
22 Oct '18
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/crypt32/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/crypt32/main.c b/dlls/crypt32/main.c
index 79a0ce1fd3..d93fb91677 100644
--- a/dlls/crypt32/main.c
+++ b/dlls/crypt32/main.c
@@ -174,7 +174,7 @@ BOOL WINAPI I_CryptGetOssGlobal(DWORD x)
return FALSE;
}
-HCRYPTPROV WINAPI I_CryptGetDefaultCryptProv(DWORD reserved)
+HCRYPTPROV WINAPI DECLSPEC_HOTPATCH I_CryptGetDefaultCryptProv(DWORD reserved)
{
HCRYPTPROV ret;
--
2.17.1
1
0
[PATCH 1/4] crypt32/tests: Actually test the return value of CryptGetKeyParam.
by Dmitry Timoshkov 22 Oct '18
by Dmitry Timoshkov 22 Oct '18
22 Oct '18
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/crypt32/tests/encode.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c
index 4a6626ab00..2da2a87b08 100644
--- a/dlls/crypt32/tests/encode.c
+++ b/dlls/crypt32/tests/encode.c
@@ -8435,7 +8435,7 @@ static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
ok(ret, "CryptImportPublicKeyInfoEx failed: %08x\n", GetLastError());
dwSize = sizeof(ai);
- CryptGetKeyParam(key, KP_ALGID, (LPVOID)&ai, &dwSize, 0);
+ ret = CryptGetKeyParam(key, KP_ALGID, (LPVOID)&ai, &dwSize, 0);
ok(ret, "CryptGetKeyParam failed: %08x\n", GetLastError());
if(ret)
{
@@ -8451,7 +8451,7 @@ static void testImportPublicKey(HCRYPTPROV csp, PCERT_PUBLIC_KEY_INFO info)
ok(ret, "CryptImportPublicKeyInfoEx failed: %08x\n", GetLastError());
dwSize = sizeof(ai);
- CryptGetKeyParam(key, KP_ALGID, (LPVOID)&ai, &dwSize, 0);
+ ret = CryptGetKeyParam(key, KP_ALGID, (LPVOID)&ai, &dwSize, 0);
ok(ret, "CryptGetKeyParam failed: %08x\n", GetLastError());
if(ret)
{
--
2.17.1
1
0
[PATCH v5] gdi32: Support the gamma correction for the subpixel rendering.
by Byeongsik Jeon 22 Oct '18
by Byeongsik Jeon 22 Oct '18
22 Oct '18
Signed-off-by: Byeongsik Jeon <bsjeon(a)hanmail.net>
---
v5: Fix the reproduced thread safety problem.
dlls/gdi32/dc.c | 1 +
dlls/gdi32/dibdrv/dibdrv.h | 8 +++++-
dlls/gdi32/dibdrv/graphics.c | 18 +++++++------
dlls/gdi32/dibdrv/primitives.c | 49 +++++++++++++++++++++++++---------
dlls/gdi32/font.c | 43 +++++++++++++++++++++++++++++
dlls/gdi32/gdi_private.h | 10 +++++++
6 files changed, 108 insertions(+), 21 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index 892d3e9744..8ee8a52d94 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -168,6 +168,7 @@ static void free_dc_state( DC *dc )
if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
if (dc->region) DeleteObject( dc->region );
if (dc->path) free_gdi_path( dc->path );
+ HeapFree( GetProcessHeap(), 0, dc->font_gamma_ramp );
HeapFree( GetProcessHeap(), 0, dc );
}
diff --git a/dlls/gdi32/dibdrv/dibdrv.h b/dlls/gdi32/dibdrv/dibdrv.h
index f79f5b0867..02164c9692 100644
--- a/dlls/gdi32/dibdrv/dibdrv.h
+++ b/dlls/gdi32/dibdrv/dibdrv.h
@@ -85,6 +85,12 @@ struct intensity_range
BYTE b_min, b_max;
};
+struct font_intensities
+{
+ struct intensity_range ranges[17];
+ struct font_gamma_ramp *gamma_ramp;
+};
+
typedef struct dibdrv_physdev
{
struct gdi_physdev dev;
@@ -192,7 +198,7 @@ typedef struct primitive_funcs
void (* draw_glyph)(const dib_info *dst, const RECT *rc, const dib_info *glyph,
const POINT *origin, DWORD text_pixel, const struct intensity_range *ranges);
void (* draw_subpixel_glyph)(const dib_info *dst, const RECT *rc, const dib_info *glyph,
- const POINT *origin, DWORD text_pixel );
+ const POINT *origin, DWORD text_pixel, const struct font_gamma_ramp *gamma_ramp);
DWORD (* get_pixel)(const dib_info *dib, int x, int y);
DWORD (* colorref_to_pixel)(const dib_info *dib, COLORREF color);
COLORREF (* pixel_to_colorref)(const dib_info *dib, DWORD pixel);
diff --git a/dlls/gdi32/dibdrv/graphics.c b/dlls/gdi32/dibdrv/graphics.c
index 08f8c3d6d2..7d71fbb12a 100644
--- a/dlls/gdi32/dibdrv/graphics.c
+++ b/dlls/gdi32/dibdrv/graphics.c
@@ -683,8 +683,8 @@ static inline void get_text_bkgnd_masks( DC *dc, const dib_info *dib, rop_mask *
static void draw_glyph( dib_info *dib, int x, int y, const GLYPHMETRICS *metrics,
const dib_info *glyph_dib, DWORD text_color,
- const struct intensity_range *ranges, const struct clipped_rects *clipped_rects,
- RECT *bounds )
+ const struct font_intensities *intensity,
+ const struct clipped_rects *clipped_rects, RECT *bounds )
{
int i;
RECT rect, clipped_rect;
@@ -705,10 +705,10 @@ static void draw_glyph( dib_info *dib, int x, int y, const GLYPHMETRICS *metrics
if (glyph_dib->bit_count == 32)
dib->funcs->draw_subpixel_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
- text_color );
+ text_color, intensity->gamma_ramp );
else
dib->funcs->draw_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
- text_color, ranges );
+ text_color, intensity->ranges );
}
}
}
@@ -816,7 +816,7 @@ static void render_string( DC *dc, dib_info *dib, struct cached_font *font, INT
struct cached_glyph *glyph;
dib_info glyph_dib;
DWORD text_color;
- struct intensity_range ranges[17];
+ struct font_intensities intensity;
glyph_dib.bit_count = get_glyph_depth( font->aa_flags );
glyph_dib.rect.left = 0;
@@ -826,8 +826,10 @@ static void render_string( DC *dc, dib_info *dib, struct cached_font *font, INT
text_color = get_pixel_color( dc, dib, dc->textColor, TRUE );
- if (glyph_dib.bit_count == 8)
- get_aa_ranges( dib->funcs->pixel_to_colorref( dib, text_color ), ranges );
+ if (glyph_dib.bit_count == 32)
+ intensity.gamma_ramp = dc->font_gamma_ramp;
+ else
+ get_aa_ranges( dib->funcs->pixel_to_colorref( dib, text_color ), intensity.ranges );
for (i = 0; i < count; i++)
{
@@ -841,7 +843,7 @@ static void render_string( DC *dc, dib_info *dib, struct cached_font *font, INT
glyph_dib.stride = get_dib_stride( glyph->metrics.gmBlackBoxX, glyph_dib.bit_count );
glyph_dib.bits.ptr = glyph->bits;
- draw_glyph( dib, x, y, &glyph->metrics, &glyph_dib, text_color, ranges, clipped_rects, bounds );
+ draw_glyph( dib, x, y, &glyph->metrics, &glyph_dib, text_color, &intensity, clipped_rects, bounds );
if (dx)
{
diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c
index 0d097b2da6..01a1c7c1d8 100644
--- a/dlls/gdi32/dibdrv/primitives.c
+++ b/dlls/gdi32/dibdrv/primitives.c
@@ -6272,16 +6272,35 @@ static void draw_glyph_null( const dib_info *dib, const RECT *rect, const dib_in
{
return;
}
+static inline BYTE blend_color_gamma( BYTE dst, BYTE text, BYTE alpha,
+ const struct font_gamma_ramp *gamma_ramp )
+{
+ if (alpha == 0) return dst;
+ if (alpha == 255) return text;
+ if (dst == text) return dst;
+
+ return gamma_ramp->encode[ blend_color( gamma_ramp->decode[dst],
+ gamma_ramp->decode[text],
+ alpha ) ];
+}
-static inline DWORD blend_subpixel( BYTE r, BYTE g, BYTE b, DWORD text, DWORD alpha )
+static inline DWORD blend_subpixel( BYTE r, BYTE g, BYTE b, DWORD text, DWORD alpha,
+ const struct font_gamma_ramp *gamma_ramp )
{
+ if (gamma_ramp != NULL && gamma_ramp->gamma != 1000)
+ {
+ return blend_color_gamma( r, text >> 16, (BYTE)(alpha >> 16), gamma_ramp ) << 16 |
+ blend_color_gamma( g, text >> 8, (BYTE)(alpha >> 8), gamma_ramp ) << 8 |
+ blend_color_gamma( b, text, (BYTE) alpha, gamma_ramp );
+ }
return blend_color( r, text >> 16, (BYTE)(alpha >> 16) ) << 16 |
blend_color( g, text >> 8, (BYTE)(alpha >> 8) ) << 8 |
blend_color( b, text, (BYTE) alpha );
}
static void draw_subpixel_glyph_8888( const dib_info *dib, const RECT *rect, const dib_info *glyph,
- const POINT *origin, DWORD text_pixel )
+ const POINT *origin, DWORD text_pixel,
+ const struct font_gamma_ramp *gamma_ramp )
{
DWORD *dst_ptr = get_pixel_ptr_32( dib, rect->left, rect->top );
const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6292,7 +6311,8 @@ static void draw_subpixel_glyph_8888( const dib_info *dib, const RECT *rect, con
for (x = 0; x < rect->right - rect->left; x++)
{
if (glyph_ptr[x] == 0) continue;
- dst_ptr[x] = blend_subpixel( dst_ptr[x] >> 16, dst_ptr[x] >> 8, dst_ptr[x], text_pixel, glyph_ptr[x] );
+ dst_ptr[x] = blend_subpixel( dst_ptr[x] >> 16, dst_ptr[x] >> 8, dst_ptr[x],
+ text_pixel, glyph_ptr[x], gamma_ramp );
}
dst_ptr += dib->stride / 4;
glyph_ptr += glyph->stride / 4;
@@ -6300,7 +6320,8 @@ static void draw_subpixel_glyph_8888( const dib_info *dib, const RECT *rect, con
}
static void draw_subpixel_glyph_32( const dib_info *dib, const RECT *rect, const dib_info *glyph,
- const POINT *origin, DWORD text_pixel )
+ const POINT *origin, DWORD text_pixel,
+ const struct font_gamma_ramp *gamma_ramp )
{
DWORD *dst_ptr = get_pixel_ptr_32( dib, rect->left, rect->top );
const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6319,7 +6340,7 @@ static void draw_subpixel_glyph_32( const dib_info *dib, const RECT *rect, const
val = blend_subpixel( get_field(dst_ptr[x], dib->red_shift, dib->red_len),
get_field(dst_ptr[x], dib->green_shift, dib->green_len),
get_field(dst_ptr[x], dib->blue_shift, dib->blue_len),
- text, glyph_ptr[x] );
+ text, glyph_ptr[x], gamma_ramp );
dst_ptr[x] = rgb_to_pixel_masks( dib, val >> 16, val >> 8, val );
}
dst_ptr += dib->stride / 4;
@@ -6328,7 +6349,8 @@ static void draw_subpixel_glyph_32( const dib_info *dib, const RECT *rect, const
}
static void draw_subpixel_glyph_24( const dib_info *dib, const RECT *rect, const dib_info *glyph,
- const POINT *origin, DWORD text_pixel )
+ const POINT *origin, DWORD text_pixel,
+ const struct font_gamma_ramp *gamma_ramp )
{
BYTE *dst_ptr = get_pixel_ptr_24( dib, rect->left, rect->top );
const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6341,7 +6363,7 @@ static void draw_subpixel_glyph_24( const dib_info *dib, const RECT *rect, const
{
if (glyph_ptr[x] == 0) continue;
val = blend_subpixel( dst_ptr[x * 3 + 2], dst_ptr[x * 3 + 1], dst_ptr[x * 3],
- text_pixel, glyph_ptr[x] );
+ text_pixel, glyph_ptr[x], gamma_ramp );
dst_ptr[x * 3] = val;
dst_ptr[x * 3 + 1] = val >> 8;
dst_ptr[x * 3 + 2] = val >> 16;
@@ -6352,7 +6374,8 @@ static void draw_subpixel_glyph_24( const dib_info *dib, const RECT *rect, const
}
static void draw_subpixel_glyph_555( const dib_info *dib, const RECT *rect, const dib_info *glyph,
- const POINT *origin, DWORD text_pixel )
+ const POINT *origin, DWORD text_pixel,
+ const struct font_gamma_ramp *gamma_ramp )
{
WORD *dst_ptr = get_pixel_ptr_16( dib, rect->left, rect->top );
const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6371,7 +6394,7 @@ static void draw_subpixel_glyph_555( const dib_info *dib, const RECT *rect, cons
val = blend_subpixel( ((dst_ptr[x] >> 7) & 0xf8) | ((dst_ptr[x] >> 12) & 0x07),
((dst_ptr[x] >> 2) & 0xf8) | ((dst_ptr[x] >> 7) & 0x07),
((dst_ptr[x] << 3) & 0xf8) | ((dst_ptr[x] >> 2) & 0x07),
- text, glyph_ptr[x] );
+ text, glyph_ptr[x], NULL );
dst_ptr[x] = ((val >> 9) & 0x7c00) | ((val >> 6) & 0x03e0) | ((val >> 3) & 0x001f);
}
dst_ptr += dib->stride / 2;
@@ -6380,7 +6403,8 @@ static void draw_subpixel_glyph_555( const dib_info *dib, const RECT *rect, cons
}
static void draw_subpixel_glyph_16( const dib_info *dib, const RECT *rect, const dib_info *glyph,
- const POINT *origin, DWORD text_pixel )
+ const POINT *origin, DWORD text_pixel,
+ const struct font_gamma_ramp *gamma_ramp )
{
WORD *dst_ptr = get_pixel_ptr_16( dib, rect->left, rect->top );
const DWORD *glyph_ptr = get_pixel_ptr_32( glyph, origin->x, origin->y );
@@ -6399,7 +6423,7 @@ static void draw_subpixel_glyph_16( const dib_info *dib, const RECT *rect, const
val = blend_subpixel( get_field(dst_ptr[x], dib->red_shift, dib->red_len),
get_field(dst_ptr[x], dib->green_shift, dib->green_len),
get_field(dst_ptr[x], dib->blue_shift, dib->blue_len),
- text, glyph_ptr[x] );
+ text, glyph_ptr[x], NULL );
dst_ptr[x] = rgb_to_pixel_masks( dib, val >> 16, val >> 8, val );
}
dst_ptr += dib->stride / 2;
@@ -6408,7 +6432,8 @@ static void draw_subpixel_glyph_16( const dib_info *dib, const RECT *rect, const
}
static void draw_subpixel_glyph_null( const dib_info *dib, const RECT *rect, const dib_info *glyph,
- const POINT *origin, DWORD text_pixel )
+ const POINT *origin, DWORD text_pixel,
+ const struct font_gamma_ramp *gamma_ramp )
{
return;
}
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 5c67d5b518..59cb73bd9f 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -729,6 +729,47 @@ static void update_font_code_page( DC *dc, HANDLE font )
TRACE("charset %d => cp %d\n", charset, dc->font_code_page);
}
+static struct font_gamma_ramp *get_font_gamma_ramp( void )
+{
+ static const WCHAR desktopW[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
+ 'D','e','s','k','t','o','p',0 };
+ static const WCHAR smoothing_gamma[] = { 'F','o','n','t','S','m','o','o','t','h','i','n','g',
+ 'G','a','m','m','a',0 };
+ const DWORD gamma_default = 1400;
+ struct font_gamma_ramp *ramp;
+ DWORD i, gamma;
+ HKEY key;
+
+ ramp = HeapAlloc( GetProcessHeap(), 0, sizeof(*ramp) );
+ if ( ramp == NULL) return NULL;
+
+ gamma = gamma_default;
+ if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key ) == ERROR_SUCCESS)
+ {
+ if (get_key_value( key, smoothing_gamma, &gamma ) || gamma == 0)
+ gamma = gamma_default;
+ RegCloseKey( key );
+
+ gamma = min( max( gamma, 1000 ), 2200 );
+ }
+
+ /* Calibration the difference between the registry value and the Wine gamma value.
+ This shows a roughly similar looks to the Windows Native with the same registry value.
+ MS GDI seems to be rasterizing the outline at the different rate than FreeType. */
+ gamma = 1000 * gamma / 1400;
+
+ for (i = 0; i < 256; i++)
+ {
+ ramp->encode[i] = pow( i / 255., 1000. / gamma ) * 255. + .5;
+ ramp->decode[i] = pow( i / 255., gamma / 1000. ) * 255. + .5;
+ }
+
+ ramp->gamma = gamma;
+ TRACE("gamma %d\n", ramp->gamma);
+
+ return ramp;
+}
+
/***********************************************************************
* FONT_SelectObject
*/
@@ -754,6 +795,8 @@ static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
dc->hFont = handle;
dc->aa_flags = aa_flags ? aa_flags : GGO_BITMAP;
update_font_code_page( dc, handle );
+ if (dc->font_gamma_ramp == NULL)
+ dc->font_gamma_ramp = get_font_gamma_ramp();
GDI_dec_ref_count( ret );
}
else GDI_dec_ref_count( handle );
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 5b09b84846..920cd1e7bf 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -99,6 +99,8 @@ typedef struct tagDC
struct gdi_path *path;
+ struct font_gamma_ramp *font_gamma_ramp;
+
UINT font_code_page;
WORD ROPmode;
WORD polyFillMode;
@@ -270,6 +272,14 @@ extern BOOL DRIVER_GetDriverName( LPCWSTR device, LPWSTR driver, DWORD size ) DE
/* enhmetafile.c */
extern HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, DWORD filesize, BOOL on_disk ) DECLSPEC_HIDDEN;
+/* font.c */
+struct font_gamma_ramp
+{
+ DWORD gamma;
+ BYTE encode[256];
+ BYTE decode[256];
+};
+
/* freetype.c */
/* Undocumented structure filled in by GetFontRealizationInfo */
--
2.19.1
2
1
[PATCH 2/4] d3d11/tests: Add a test for D3D11_STANDARD_MULTISAMPLE_PATTERN.
by Henri Verbeet 22 Oct '18
by Henri Verbeet 22 Oct '18
22 Oct '18
From: Andrew Wesie <awesie(a)gmail.com>
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45197
Signed-off-by: Andrew Wesie <awesie(a)gmail.com>
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/d3d11/tests/d3d11.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 122 insertions(+)
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index 010139c7e0d..632ef4f3538 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -28529,6 +28529,127 @@ static void test_render_a8(void)
release_test_context(&test_context);
}
+static void test_standard_pattern(void)
+{
+ D3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc;
+ struct d3d11_test_context test_context;
+ struct swapchain_desc swapchain_desc;
+ D3D11_TEXTURE2D_DESC texture_desc;
+ ID3D11UnorderedAccessView *uav;
+ D3D11_BUFFER_DESC buffer_desc;
+ ID3D11ShaderResourceView *srv;
+ ID3D11DeviceContext *context;
+ struct resource_readback rb;
+ ID3D11Texture2D *texture;
+ ID3D11PixelShader *ps;
+ ID3D11Buffer *buffer;
+ ID3D11Device *device;
+ unsigned int i;
+ HRESULT hr;
+
+ static const DWORD ps_samplepos[] =
+ {
+#if 0
+ Texture2DMS<float> t;
+ RWByteAddressBuffer u;
+
+ float4 main() : SV_Target
+ {
+ u.Store2(0, asuint(t.GetSamplePosition(0)));
+ u.Store2(8, asuint(t.GetSamplePosition(1)));
+ u.Store2(16, asuint(t.GetSamplePosition(2)));
+ u.Store2(24, asuint(t.GetSamplePosition(3)));
+ return float4(0.0f, 1.0f, 0.0f, 1.0f);
+ }
+#endif
+ 0x43425844, 0xa1db77e8, 0x804d8862, 0x0e3c213d, 0x2703dec6, 0x00000001, 0x00000190, 0x00000003,
+ 0x0000002c, 0x0000003c, 0x00000070, 0x4e475349, 0x00000008, 0x00000000, 0x00000008, 0x4e47534f,
+ 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000,
+ 0x0000000f, 0x545f5653, 0x65677261, 0xabab0074, 0x58454853, 0x00000118, 0x00000050, 0x00000046,
+ 0x0100086a, 0x04002058, 0x00107000, 0x00000000, 0x00005555, 0x0300009d, 0x0011e000, 0x00000001,
+ 0x03000065, 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x0800006e, 0x00100032, 0x00000000,
+ 0x00107046, 0x00000000, 0x00004001, 0x00000000, 0x00000000, 0x0800006e, 0x001000c2, 0x00000000,
+ 0x00107406, 0x00000000, 0x00004001, 0x00000001, 0x00000000, 0x070000a6, 0x0011e0f2, 0x00000001,
+ 0x00004001, 0x00000000, 0x00100e46, 0x00000000, 0x0800006e, 0x00100032, 0x00000000, 0x00107046,
+ 0x00000000, 0x00004001, 0x00000002, 0x00000000, 0x0800006e, 0x001000c2, 0x00000000, 0x00107406,
+ 0x00000000, 0x00004001, 0x00000003, 0x00000000, 0x070000a6, 0x0011e0f2, 0x00000001, 0x00004001,
+ 0x00000010, 0x00100e46, 0x00000000, 0x08000036, 0x001020f2, 0x00000000, 0x00004002, 0x00000000,
+ 0x3f800000, 0x00000000, 0x3f800000, 0x0100003e
+ };
+ static const D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_11_0;
+ static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ static const unsigned int zero[4] = {0};
+ static const float standard_pos4[] =
+ {
+ -2 / 16.0f, -6 / 16.0f,
+ 6 / 16.0f, -2 / 16.0f,
+ -6 / 16.0f, 2 / 16.0f,
+ 2 / 16.0f, 6 / 16.0f,
+ };
+
+ swapchain_desc.windowed = TRUE;
+ swapchain_desc.buffer_count = 1;
+ swapchain_desc.width = 32;
+ swapchain_desc.height = 32;
+ swapchain_desc.swap_effect = DXGI_SWAP_EFFECT_DISCARD;
+ swapchain_desc.flags = 0;
+ if (!init_test_context_ext(&test_context, &feature_level, &swapchain_desc))
+ return;
+ device = test_context.device;
+ context = test_context.immediate_context;
+
+ ID3D11Texture2D_GetDesc(test_context.backbuffer, &texture_desc);
+ texture_desc.SampleDesc.Count = 4;
+ texture_desc.SampleDesc.Quality = D3D11_STANDARD_MULTISAMPLE_PATTERN;
+ texture_desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
+ hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &texture);
+ ok(hr == S_OK, "Failed to create texture, hr %#x.\n", hr);
+ hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)texture, NULL, &srv);
+ ok(hr == S_OK, "Failed to create shader resource view, hr %#x.\n", hr);
+
+ buffer_desc.ByteWidth = 1024;
+ buffer_desc.Usage = D3D11_USAGE_DEFAULT;
+ buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
+ buffer_desc.CPUAccessFlags = 0;
+ buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
+ hr = ID3D11Device_CreateBuffer(device, &buffer_desc, NULL, &buffer);
+ ok(hr == S_OK, "Failed to create buffer, hr %#x.\n", hr);
+ uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
+ uav_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
+ U(uav_desc).Buffer.FirstElement = 0;
+ U(uav_desc).Buffer.NumElements = 256;
+ U(uav_desc).Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
+ hr = ID3D11Device_CreateUnorderedAccessView(device, (ID3D11Resource *)buffer, &uav_desc, &uav);
+ ok(hr == S_OK, "Failed to create unordered access view, hr %#x.\n", hr);
+
+ hr = ID3D11Device_CreatePixelShader(device, ps_samplepos, sizeof(ps_samplepos), NULL, &ps);
+ ok(hr == S_OK, "Failed to create pixel shader, hr %#x.\n", hr);
+ ID3D11DeviceContext_PSSetShader(context, ps, NULL, 0);
+
+ ID3D11DeviceContext_ClearUnorderedAccessViewUint(context, uav, zero);
+ ID3D11DeviceContext_ClearRenderTargetView(context, test_context.backbuffer_rtv, white);
+ ID3D11DeviceContext_OMSetRenderTargetsAndUnorderedAccessViews(context,
+ 1, &test_context.backbuffer_rtv, NULL, 1, 1, &uav, NULL);
+ ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &srv);
+ draw_quad(&test_context);
+ check_texture_color(test_context.backbuffer, 0xff00ff00, 0);
+ get_buffer_readback(buffer, &rb);
+ for (i = 0; i < ARRAY_SIZE(standard_pos4); ++i)
+ {
+ float data = get_readback_float(&rb, i, 0);
+ /* Wine does not support GetSamplePosition. */
+ todo_wine ok(data == standard_pos4[i], "Got sample position %.8e, expected %.8e.\n", data, standard_pos4[i]);
+ }
+ release_resource_readback(&rb);
+
+ ID3D11PixelShader_Release(ps);
+ ID3D11Buffer_Release(buffer);
+ ID3D11UnorderedAccessView_Release(uav);
+ ID3D11ShaderResourceView_Release(srv);
+ ID3D11Texture2D_Release(texture);
+ release_test_context(&test_context);
+}
+
START_TEST(d3d11)
{
unsigned int argc, i;
@@ -28679,6 +28800,7 @@ START_TEST(d3d11)
queue_test(test_depth_clip);
queue_test(test_staging_buffers);
queue_test(test_render_a8);
+ queue_test(test_standard_pattern);
run_queued_tests();
}
--
2.11.0
2
1
22 Oct '18
From: Aaryaman Vasishta <jem456.vasishta(a)gmail.com>
Signed-off-by: Aaryaman Vasishta <jem456.vasishta(a)gmail.com>
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/d3drm/tests/d3drm.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/dlls/d3drm/tests/d3drm.c b/dlls/d3drm/tests/d3drm.c
index a2ea1827ee4..9bc9a84444a 100644
--- a/dlls/d3drm/tests/d3drm.c
+++ b/dlls/d3drm/tests/d3drm.c
@@ -5598,6 +5598,49 @@ static void test_load_texture(void)
ok(SUCCEEDED(hr), "Failed to get IDirect3DRM3 interface, hr %#x.\n", hr);
ref1 = get_refcount((IUnknown *)d3drm1);
+ /* Test all failures together. */
+ texture1 = (IDirect3DRMTexture *)0xdeadbeef;
+ hr = IDirect3DRM_LoadTexture(d3drm1, NULL, &texture1);
+ todo_wine ok(hr == D3DRMERR_BADVALUE, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!texture1, "Got unexpected texture %p.\n", texture1);
+ texture1 = (IDirect3DRMTexture *)0xdeadbeef;
+ hr = IDirect3DRM_LoadTexture(d3drm1, "", &texture1);
+ todo_wine ok(hr == D3DRMERR_FILENOTFOUND, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!texture1, "Got unexpected texture %p.\n", texture1);
+ if (hr == D3DRMERR_FILENOTFOUND)
+ {
+ hr = IDirect3DRM_LoadTexture(d3drm1, NULL, NULL);
+ ok(hr == D3DRMERR_BADVALUE, "Got unexpected hr %#x.\n", hr);
+ }
+
+ texture2 = (IDirect3DRMTexture2 *)0xdeadbeef;
+ hr = IDirect3DRM2_LoadTexture(d3drm2, NULL, &texture2);
+ todo_wine ok(hr == D3DRMERR_FILENOTFOUND, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!texture2, "Got unexpected texture %p.\n", texture2);
+ texture2 = (IDirect3DRMTexture2 *)0xdeadbeef;
+ hr = IDirect3DRM2_LoadTexture(d3drm2, "", &texture2);
+ todo_wine ok(hr == D3DRMERR_FILENOTFOUND, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!texture2, "Got unexpected texture %p.\n", texture2);
+ if (hr == D3DRMERR_FILENOTFOUND)
+ {
+ hr = IDirect3DRM2_LoadTexture(d3drm2, NULL, NULL);
+ ok(hr == D3DRMERR_BADVALUE, "Got unexpected hr %#x.\n", hr);
+ }
+
+ texture3 = (IDirect3DRMTexture3 *)0xdeadbeef;
+ hr = IDirect3DRM3_LoadTexture(d3drm3, NULL, &texture3);
+ todo_wine ok(hr == D3DRMERR_FILENOTFOUND, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!texture3, "Got unexpected texture %p.\n", texture3);
+ texture3 = (IDirect3DRMTexture3 *)0xdeadbeef;
+ hr = IDirect3DRM_LoadTexture(d3drm3, "", &texture3);
+ todo_wine ok(hr == D3DRMERR_FILENOTFOUND, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!texture3, "Got unexpected texture %p.\n", texture3);
+ if (hr == D3DRMERR_FILENOTFOUND)
+ {
+ hr = IDirect3DRM3_LoadTexture(d3drm3, NULL, NULL);
+ ok(hr == D3DRMERR_BADVALUE, "Got unexpected hr %#x.\n", hr);
+ }
+
for (i = 0; i < ARRAY_SIZE(tests); ++i)
{
filename = create_bitmap(tests[i].w, tests[i].h, tests[i].palettized);
--
2.11.0
1
0
[PATCH 3/4] d3drm/tests: Add tests for IDirect3DRMTexture*_InitFromFile().
by Henri Verbeet 22 Oct '18
by Henri Verbeet 22 Oct '18
22 Oct '18
From: Aaryaman Vasishta <jem456.vasishta(a)gmail.com>
Signed-off-by: Aaryaman Vasishta <jem456.vasishta(a)gmail.com>
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/d3drm/tests/d3drm.c | 83 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 78 insertions(+), 5 deletions(-)
diff --git a/dlls/d3drm/tests/d3drm.c b/dlls/d3drm/tests/d3drm.c
index f78e098fec0..a2ea1827ee4 100644
--- a/dlls/d3drm/tests/d3drm.c
+++ b/dlls/d3drm/tests/d3drm.c
@@ -5569,10 +5569,11 @@ static void test_load_texture(void)
IDirect3DRM3 *d3drm3;
IDirect3DRM2 *d3drm2;
IDirect3DRM *d3drm1;
+ ULONG ref1, ref2;
+ unsigned int i;
char *filename;
HRESULT hr;
BOOL ret;
- int i;
static const struct
{
@@ -5595,6 +5596,7 @@ static void test_load_texture(void)
ok(SUCCEEDED(hr), "Failed to get IDirect3DRM2 interface, hr %#x.\n", hr);
hr = IDirect3DRM_QueryInterface(d3drm1, &IID_IDirect3DRM3, (void **)&d3drm3);
ok(SUCCEEDED(hr), "Failed to get IDirect3DRM3 interface, hr %#x.\n", hr);
+ ref1 = get_refcount((IUnknown *)d3drm1);
for (i = 0; i < ARRAY_SIZE(tests); ++i)
{
@@ -5602,26 +5604,80 @@ static void test_load_texture(void)
hr = IDirect3DRM_LoadTexture(d3drm1, filename, &texture1);
ok(SUCCEEDED(hr), "Test %u: Failed to load texture, hr %#x.\n", i, hr);
+ ref2 = get_refcount((IUnknown *)d3drm1);
+ todo_wine ok(ref2 > ref1, "Test %u: expected ref2 > ref1, got ref1 = %u, ref2 = %u.\n", i, ref1, ref2);
+
+ hr = IDirect3DRMTexture_InitFromFile(texture1, filename);
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ /* InitFromFile() seems to AddRef() IDirect3DRM even if it fails. */
+ if (hr == D3DRMERR_BADOBJECT)
+ IDirect3DRM_Release(d3drm1);
d3drm_img = IDirect3DRMTexture_GetImage(texture1);
todo_wine ok(!!d3drm_img, "Test %u: Failed to get image.\n", i);
if (d3drm_img)
- test_bitmap_data(i * 4, d3drm_img, FALSE, tests[i].w, tests[i].h, tests[i].palettized);
+ test_bitmap_data(i * 7, d3drm_img, FALSE, tests[i].w, tests[i].h, tests[i].palettized);
+ IDirect3DRMTexture_Release(texture1);
+ ref2 = get_refcount((IUnknown *)d3drm1);
+ ok(ref1 == ref2, "Test %u: expected ref1 == ref2, got ref1 = %u, ref2 = %u.\n", i, ref1, ref2);
+ hr = IDirect3DRM_CreateObject(d3drm1, &CLSID_CDirect3DRMTexture,
+ NULL, &IID_IDirect3DRMTexture, (void **)&texture1);
+ ok(SUCCEEDED(hr), "Test %u: Failed to create texture, hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture_InitFromFile(texture1, NULL);
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture_InitFromFile(texture1, "");
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture_InitFromFile(texture1, filename);
+ todo_wine ok(SUCCEEDED(hr), "Test %u: Failed to initialise texture from file, hr %#x.\n", i, hr);
+ d3drm_img = IDirect3DRMTexture_GetImage(texture1);
+ todo_wine ok(!!d3drm_img, "Test %u: Failed to get image.\n", i);
+ if (d3drm_img)
+ test_bitmap_data(i * 7 + 1, d3drm_img, FALSE, tests[i].w, tests[i].h, tests[i].palettized);
IDirect3DRMTexture_Release(texture1);
hr = IDirect3DRM2_LoadTexture(d3drm2, filename, &texture2);
ok(SUCCEEDED(hr), "Test %u: Failed to load texture, hr %#x.\n", i, hr);
+ ref2 = get_refcount((IUnknown *)d3drm1);
+ todo_wine ok(ref2 > ref1, "Test %u: expected ref2 > ref1, got ref1 = %u, ref2 = %u.\n", i, ref1, ref2);
+
+ hr = IDirect3DRMTexture2_InitFromFile(texture2, filename);
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ if (hr == D3DRMERR_BADOBJECT)
+ IDirect3DRM_Release(d3drm1);
d3drm_img = IDirect3DRMTexture2_GetImage(texture2);
todo_wine ok(!!d3drm_img, "Test %u: Failed to get image.\n", i);
if (d3drm_img)
- test_bitmap_data(i * 4 + 1, d3drm_img, TRUE, tests[i].w, tests[i].h, tests[i].palettized);
+ test_bitmap_data(i * 7 + 2, d3drm_img, TRUE, tests[i].w, tests[i].h, tests[i].palettized);
+ IDirect3DRMTexture2_Release(texture2);
+ ref2 = get_refcount((IUnknown *)d3drm1);
+ ok(ref1 == ref2, "Test %u: expected ref1 == ref2, got ref1 = %u, ref2 = %u.\n", i, ref1, ref2);
+ hr = IDirect3DRM2_CreateObject(d3drm2, &CLSID_CDirect3DRMTexture,
+ NULL, &IID_IDirect3DRMTexture2, (void **)&texture2);
+ ok(SUCCEEDED(hr), "Test %u: Failed to create texture, hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture2_InitFromFile(texture2, NULL);
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture2_InitFromFile(texture2, "");
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture2_InitFromFile(texture2, filename);
+ todo_wine ok(SUCCEEDED(hr), "Test %u: Failed to initialise texture from file, hr %#x.\n", i, hr);
+ d3drm_img = IDirect3DRMTexture2_GetImage(texture2);
+ todo_wine ok(!!d3drm_img, "Test %u: Failed to get image.\n", i);
+ if (d3drm_img)
+ test_bitmap_data(i * 7 + 3, d3drm_img, TRUE, tests[i].w, tests[i].h, tests[i].palettized);
IDirect3DRMTexture2_Release(texture2);
hr = IDirect3DRM3_LoadTexture(d3drm3, filename, &texture3);
ok(SUCCEEDED(hr), "Test %u: Failed to load texture, hr %#x.\n", i, hr);
+ ref2 = get_refcount((IUnknown *)d3drm1);
+ todo_wine ok(ref2 > ref1, "Test %u: expected ref2 > ref1, got ref1 = %u, ref2 = %u.\n", i, ref1, ref2);
+
+ hr = IDirect3DRMTexture3_InitFromFile(texture3, filename);
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ if (hr == D3DRMERR_BADOBJECT)
+ IDirect3DRM_Release(d3drm1);
d3drm_img = IDirect3DRMTexture3_GetImage(texture3);
todo_wine ok(!!d3drm_img, "Test %u: Failed to get image.\n", i);
if (d3drm_img)
- test_bitmap_data(i * 4 + 2, d3drm_img, TRUE, tests[i].w, tests[i].h, tests[i].palettized);
+ test_bitmap_data(i * 7 + 4, d3drm_img, TRUE, tests[i].w, tests[i].h, tests[i].palettized);
/* Test whether querying a version 1 texture from version 3 causes a
* change in the loading behavior. */
hr = IDirect3DRMTexture3_QueryInterface(texture3, &IID_IDirect3DRMTexture, (void **)&texture1);
@@ -5629,9 +5685,26 @@ static void test_load_texture(void)
d3drm_img = IDirect3DRMTexture_GetImage(texture1);
todo_wine ok(!!d3drm_img, "Test %u: Failed to get image.\n", i);
if (d3drm_img)
- test_bitmap_data(i * 4 + 3, d3drm_img, TRUE, tests[i].w, tests[i].h, tests[i].palettized);
+ test_bitmap_data(i * 7 + 5, d3drm_img, TRUE, tests[i].w, tests[i].h, tests[i].palettized);
IDirect3DRMTexture_Release(texture1);
IDirect3DRMTexture3_Release(texture3);
+ ref2 = get_refcount((IUnknown *)d3drm1);
+ ok(ref1 == ref2, "Test %u: expected ref1 == ref2, got ref1 = %u, ref2 = %u.\n", i, ref1, ref2);
+
+ hr = IDirect3DRM3_CreateObject(d3drm3, &CLSID_CDirect3DRMTexture,
+ NULL, &IID_IDirect3DRMTexture3, (void **)&texture3);
+ ok(SUCCEEDED(hr), "Test %u: Failed to create texture, hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture3_InitFromFile(texture3, NULL);
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture3_InitFromFile(texture3, "");
+ todo_wine ok(hr == D3DRMERR_BADOBJECT, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ hr = IDirect3DRMTexture3_InitFromFile(texture3, filename);
+ todo_wine ok(SUCCEEDED(hr), "Test %u: Failed to initialize texture from file, hr %#x.\n", i, hr);
+ d3drm_img = IDirect3DRMTexture3_GetImage(texture3);
+ todo_wine ok(!!d3drm_img, "Test %u: Failed to get image.\n", i);
+ if (d3drm_img)
+ test_bitmap_data(i * 7 + 6, d3drm_img, TRUE, tests[i].w, tests[i].h, tests[i].palettized);
+ IDirect3DRMTexture3_Release(texture3);
ret = DeleteFileA(filename);
ok(ret, "Test %u: Failed to delete bitmap \"%s\".\n", i, filename);
--
2.11.0
1
0
22 Oct '18
From: Andrew Wesie <awesie(a)gmail.com>
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45197
Signed-off-by: Andrew Wesie <awesie(a)gmail.com>
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/texture.c | 8 +++++---
include/wine/wined3d.h | 2 ++
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index b8e7ef03489..15492cd86fe 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -627,6 +627,8 @@ static void wined3d_texture_allocate_gl_immutable_storage(struct wined3d_texture
unsigned int samples = wined3d_texture_get_gl_sample_count(texture);
GLsizei height = wined3d_texture_get_level_pow2_height(texture, 0);
GLsizei width = wined3d_texture_get_level_pow2_width(texture, 0);
+ GLboolean standard_pattern = texture->resource.multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
+ && texture->resource.multisample_quality == WINED3D_STANDARD_MULTISAMPLE_PATTERN;
switch (texture->target)
{
@@ -640,11 +642,11 @@ static void wined3d_texture_allocate_gl_immutable_storage(struct wined3d_texture
break;
case GL_TEXTURE_2D_MULTISAMPLE:
GL_EXTCALL(glTexStorage2DMultisample(texture->target, samples,
- gl_internal_format, width, height, GL_FALSE));
+ gl_internal_format, width, height, standard_pattern));
break;
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
GL_EXTCALL(glTexStorage3DMultisample(texture->target, samples,
- gl_internal_format, width, height, texture->layer_count, GL_FALSE));
+ gl_internal_format, width, height, texture->layer_count, standard_pattern));
break;
case GL_TEXTURE_1D_ARRAY:
GL_EXTCALL(glTexStorage2D(texture->target, texture->level_count,
@@ -3604,7 +3606,7 @@ HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct
}
if (desc->multisample_type != WINED3D_MULTISAMPLE_NON_MASKABLE
&& (!(format->multisample_types & 1u << (desc->multisample_type - 1))
- || desc->multisample_quality))
+ || (desc->multisample_quality && desc->multisample_quality != WINED3D_STANDARD_MULTISAMPLE_PATTERN)))
{
WARN("Unsupported multisample type %u quality %u requested.\n", desc->multisample_type,
desc->multisample_quality);
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 95549e96cb4..1b3a46e6567 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -1571,6 +1571,8 @@ enum wined3d_shader_type
#define WINED3D_TEXTURE_CREATE_GET_DC 0x00000008
#define WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS 0x00000010
+#define WINED3D_STANDARD_MULTISAMPLE_PATTERN 0xffffffff
+
#define WINED3D_APPEND_ALIGNED_ELEMENT 0xffffffff
#define WINED3D_OUTPUT_SLOT_SEMANTIC 0xffffffff
--
2.11.0
1
0
Missions allow the TestBot administrator to specify which tests a given
VM should perform for mailing list patches. For instance this can be
used to restrict a 64 bit Windows VM to 32 bit tests (useful when it
duplicates another VM with just a different locale).
Furthermore missions can get options. Currently only the 'nosubmit'
option is supported and it disables submitting the WineTest results
online.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
Eventually missions will make it possible to specify how much testing a
Wine VM should do, from running only patched tests to running every test
for every patch; against which Wine build; only in the English locale,
or in other locales too.
testbot/bin/CheckForWinetestUpdate.pl | 105 ++++++++++++++------
testbot/bin/WineRunTask.pl | 12 ++-
testbot/bin/WineRunWineTest.pl | 31 +++---
testbot/bin/build/WineTest.pl | 131 +++++++++++++------------
testbot/ddl/update41.sql | 48 +++++++++
testbot/ddl/winetestbot.sql | 2 +
testbot/doc/winetestbot-schema.dia | 46 +++++++++
testbot/lib/WineTestBot/Missions.pm | 99 +++++++++++++++++++
testbot/lib/WineTestBot/PatchUtils.pm | 8 +-
testbot/lib/WineTestBot/Patches.pm | 134 +++++++++++++++-----------
testbot/lib/WineTestBot/StepsTasks.pm | 55 +++++++----
testbot/lib/WineTestBot/Tasks.pm | 1 +
testbot/lib/WineTestBot/VMs.pm | 41 ++++++++
testbot/web/JobDetails.pl | 1 +
testbot/web/Submit.pl | 80 ++++++++-------
testbot/web/admin/VMDetails.pl | 16 +++
16 files changed, 587 insertions(+), 223 deletions(-)
create mode 100644 testbot/ddl/update41.sql
create mode 100644 testbot/lib/WineTestBot/Missions.pm
diff --git a/testbot/bin/CheckForWinetestUpdate.pl b/testbot/bin/CheckForWinetestUpdate.pl
index 29953642ef..95cb13d8ed 100755
--- a/testbot/bin/CheckForWinetestUpdate.pl
+++ b/testbot/bin/CheckForWinetestUpdate.pl
@@ -53,6 +53,7 @@ use WineTestBot::Config;
use WineTestBot::Engine::Notify;
use WineTestBot::Jobs;
use WineTestBot::Log;
+use WineTestBot::Missions;
use WineTestBot::PatchUtils;
use WineTestBot::Users;
use WineTestBot::Utils;
@@ -201,21 +202,38 @@ sub AddJob($$$)
$NewJob->Priority($BaseJob && $Build eq "exe32" ? 8 : 9);
$NewJob->Remarks($Remarks);
- # Add a step to the job
- my $Steps = $NewJob->Steps;
- my $NewStep = $Steps->Add();
- $NewStep->Type("suite");
- $NewStep->FileName($LatestBaseName);
- $NewStep->FileType($Build);
-
# Add a task for each VM
- my $Tasks = $NewStep->Tasks;
+ my $Tasks;
foreach my $VMKey (@{$VMs->SortKeysBySortOrder($VMs->GetKeys())})
{
- Debug(" $VMKey $Build\n");
- my $Task = $Tasks->Add();
- $Task->VM($VMs->GetItem($VMKey));
- $Task->Timeout(GetTestTimeout(undef, { $Build => 1 }));
+ my $VM = $VMs->GetItem($VMKey);
+ my ($ErrMessage, $Missions) = ParseMissionStatement($VM->Missions);
+ if (defined $ErrMessage)
+ {
+ Debug("$VMKey has an invalid mission statement: $!\n");
+ next;
+ }
+
+ foreach my $TaskMissions (@$Missions)
+ {
+ next if (!$TaskMissions->{Builds}->{$Build});
+
+ if (!$Tasks)
+ {
+ # Add a step to the job
+ my $TestStep = $NewJob->Steps->Add();
+ $TestStep->Type("suite");
+ $TestStep->FileName($LatestBaseName);
+ $TestStep->FileType($Build);
+ $Tasks = $TestStep->Tasks;
+ }
+
+ Debug(" $VMKey $Build\n");
+ my $Task = $Tasks->Add();
+ $Task->VM($VM);
+ $Task->Timeout($SuiteTimeout);
+ $Task->Missions($TaskMissions->{Statement});
+ }
}
# Save it all
@@ -246,9 +264,6 @@ sub AddJob($$$)
return 1;
}
-my @ExeBuilds = qw(exe32 exe64);
-my @WineBuilds = qw(win32 wow32 wow64);
-
sub AddReconfigJob($)
{
my ($VMType) = @_;
@@ -287,9 +302,23 @@ sub AddReconfigJob($)
Debug(" $VMKey $VMType reconfig\n");
my $Task = $BuildStep->Tasks->Add();
$Task->VM($VM);
- my $Builds;
- map { $Builds->{$_} = 1 } ($VMType eq "wine" ? @WineBuilds : @ExeBuilds);
- $Task->Timeout(GetBuildTimeout(undef, $Builds));
+
+ # Merge all the tasks into one so we only recreate the base snapshot once
+ my $MissionStatement = $VMType ne "wine" ? "exe32:exe64" :
+ MergeMissionStatementTasks($VM->Missions);
+ my ($ErrMessage, $Missions) = ParseMissionStatement($MissionStatement);
+ if (defined $ErrMessage)
+ {
+ Debug("$VMKey has an invalid mission statement: $!\n");
+ next;
+ }
+ if (@$Missions != 1)
+ {
+ Debug("Found no mission or too many task missions for $VMKey\n");
+ next;
+ }
+ $Task->Timeout(GetBuildTimeout(undef, $Missions->[0]));
+ $Task->Missions($Missions->[0]->{Statement});
}
# Save the build step so the others can reference it.
@@ -303,22 +332,38 @@ sub AddReconfigJob($)
if ($VMType eq "wine")
{
# Add steps to run WineTest on Wine
- foreach my $Build (@WineBuilds)
+ my $Tasks;
+ foreach my $VMKey (@$SortedKeys)
{
- # Add a step to the job
- my $NewStep = $Steps->Add();
- $NewStep->PreviousNo($BuildStep->No);
- $NewStep->Type("suite");
- $NewStep->FileType("none");
+ my $VM = $VMs->GetItem($VMKey);
+ # Move all the missions into separate tasks so we don't have one very
+ # long task hogging the VM forever. Note that this also ok because the
+ # WineTest tasks don't have to recompile Wine.
+ my $MissionStatement = SplitMissionStatementTasks($VM->Missions);
+ my ($ErrMessage, $Missions) = ParseMissionStatement($MissionStatement);
+ if (defined $ErrMessage)
+ {
+ Debug("$VMKey has an invalid mission statement: $!\n");
+ next;
+ }
- foreach my $VMKey (@$SortedKeys)
+ foreach my $TaskMissions (@$Missions)
{
- my $VM = $VMs->GetItem($VMKey);
- Debug(" $VMKey $Build\n");
- my $Task = $NewStep->Tasks->Add();
+ if (!$Tasks)
+ {
+ # Add a step to the job
+ my $TestStep = $Steps->Add();
+ $TestStep->PreviousNo($BuildStep->No);
+ $TestStep->Type("suite");
+ $TestStep->FileType("none");
+ $Tasks = $TestStep->Tasks;
+ }
+
+ Debug(" $VMKey $TaskMissions->{Statement}\n");
+ my $Task = $Tasks->Add();
$Task->VM($VM);
- $Task->CmdLineArg($Build);
- $Task->Timeout(GetTestTimeout(undef, { $Build => 1 }));
+ $Task->Timeout(GetTestTimeout(undef, $TaskMissions));
+ $Task->Missions($TaskMissions->{Statement});
}
}
}
diff --git a/testbot/bin/WineRunTask.pl b/testbot/bin/WineRunTask.pl
index 077426b232..fea8c03f5e 100755
--- a/testbot/bin/WineRunTask.pl
+++ b/testbot/bin/WineRunTask.pl
@@ -45,6 +45,7 @@ use WineTestBot::Engine::Notify;
use WineTestBot::Jobs;
use WineTestBot::Log;
use WineTestBot::LogUtils;
+use WineTestBot::Missions;
use WineTestBot::Utils;
use WineTestBot::VMs;
@@ -391,6 +392,13 @@ if ($Step->FileType ne "exe32" and $Step->FileType ne "exe64")
FatalError("Unexpected file type '". $Step->FileType ."' found for ". $Step->Type ." step\n");
}
+my ($ErrMessage, $Missions) = ParseMissionStatement($Task->Missions);
+FatalError "$ErrMessage\n" if (defined $ErrMessage);
+FatalError "Empty mission statement\n" if (!@$Missions);
+FatalError "Cannot specify missions for multiple tasks\n" if (@$Missions > 1);
+FatalError "Cannot specify multiple missions\n" if (@{$Missions->[0]->{Missions}} > 1);
+my $Mission = $Missions->[0]->{Missions}->[0];
+
#
# Setup the VM
@@ -477,8 +485,8 @@ elsif ($Step->Type eq "suite")
$Info =~ s/"/\\"/g;
$Info =~ s/%/%%/g;
$Info =~ s/%/%%/g;
- $Script .= "-q -o $RptFileName -t $Tag -m \"$EMail\" -i \"$Info\"\r\n".
- "$FileName -q -s $RptFileName\r\n";
+ $Script .= "-q -o $RptFileName -t $Tag -m \"$EMail\" -i \"$Info\"\r\n";
+ $Script .= "$FileName -q -s $RptFileName\r\n" if (!$Mission->{nosubmit});
}
Debug(Elapsed($Start), " Sending the script: [$Script]\n");
if (!$TA->SendFileFromString($Script, "script.bat", $TestAgent::SENDFILE_EXE))
diff --git a/testbot/bin/WineRunWineTest.pl b/testbot/bin/WineRunWineTest.pl
index 0e438f957c..f47a02413a 100755
--- a/testbot/bin/WineRunWineTest.pl
+++ b/testbot/bin/WineRunWineTest.pl
@@ -41,13 +41,14 @@ $Name0 =~ s+^.*/++;
use WineTestBot::Config;
+use WineTestBot::Engine::Notify;
use WineTestBot::Jobs;
+use WineTestBot::Missions;
use WineTestBot::PatchUtils;
-use WineTestBot::VMs;
use WineTestBot::Log;
use WineTestBot::LogUtils;
use WineTestBot::Utils;
-use WineTestBot::Engine::Notify;
+use WineTestBot::VMs;
#
@@ -220,6 +221,8 @@ sub LogTaskError($)
}
}
+my $TaskMissions;
+
sub WrapUpAndExit($;$$$)
{
my ($Status, $TestFailures, $Retry, $TimedOut) = @_;
@@ -287,9 +290,7 @@ sub WrapUpAndExit($;$$$)
if ($Step->Type eq 'suite' and $Status eq 'completed' and !$TimedOut)
{
- my $BuildList = $Task->CmdLineArg;
- $BuildList =~ s/ .*$//;
- foreach my $Build (split /,/, $BuildList)
+ foreach my $Build (keys %{$TaskMissions->{Builds}})
{
# Keep the old report if the new one is missing
my $RptFileName = "$Build.report";
@@ -392,6 +393,12 @@ if (($Step->Type eq "suite" and $Step->FileType ne "none") or
FatalError("Unexpected file type '". $Step->FileType ."' found for ". $Step->Type ." step\n");
}
+my ($ErrMessage, $Missions) = ParseMissionStatement($Task->Missions);
+FatalError "$ErrMessage\n" if (defined $ErrMessage);
+FatalError "Empty mission statement\n" if (!@$Missions);
+FatalError "Cannot specify missions for multiple tasks\n" if (@$Missions > 1);
+$TaskMissions = $Missions->[0];
+
#
# Setup the VM
@@ -431,7 +438,7 @@ $Script .= " ../bin/build/WineTest.pl ";
if ($Step->Type eq "suite")
{
my $BaseTag = BuildTag($VM->Name);
- $Script .= "--winetest ". $Task->CmdLineArg ." $BaseTag ";
+ $Script .= "--winetest ". $Task->Missions ." $BaseTag ";
if (defined $WebHostName)
{
my $StepTask = 100 * $StepNo + $TaskNo;
@@ -447,7 +454,7 @@ if ($Step->Type eq "suite")
}
else
{
- $Script .= "--testpatch ". $Task->CmdLineArg ." patch.diff";
+ $Script .= "--testpatch ". $Task->Missions ." patch.diff";
}
$Script .= "\n) >Task.log 2>&1\n";
Debug(Elapsed($Start), " Sending the script: [$Script]\n");
@@ -475,7 +482,7 @@ if (!$Pid)
#
my $NewStatus = 'completed';
-my ($TaskFailures, $TaskTimedOut, $ErrMessage, $TAError, $PossibleCrash);
+my ($TaskFailures, $TaskTimedOut, $TAError, $PossibleCrash);
Debug(Elapsed($Start), " Waiting for the script (", $Task->Timeout, "s timeout)\n");
if (!defined $TA->Wait($Pid, $Task->Timeout, 60))
{
@@ -542,9 +549,7 @@ elsif (!defined $TAError)
if ($Step->Type ne "build")
{
- my $BuildList = $Task->CmdLineArg;
- $BuildList =~ s/ .*$//;
- foreach my $Build (split /,/, $BuildList)
+ foreach my $Build (keys %{$TaskMissions->{Builds}})
{
my $RptFileName = "$Build.report";
Debug(Elapsed($Start), " Retrieving '$RptFileName'\n");
@@ -602,9 +607,7 @@ if ($NewStatus eq 'completed')
{
my $LatestDir = "$DataDir/latest";
my $StepDir = $Step->GetDir();
- my $BuildList = $Task->CmdLineArg;
- $BuildList =~ s/ .*$//;
- foreach my $Build (split /,/, $BuildList)
+ foreach my $Build (keys %{$TaskMissions->{Builds}})
{
my $RptFileName = "$Build.report";
my $RefReport = $Task->VM->Name ."_$RptFileName";
diff --git a/testbot/bin/build/WineTest.pl b/testbot/bin/build/WineTest.pl
index 712341b339..c5d38df9d4 100755
--- a/testbot/bin/build/WineTest.pl
+++ b/testbot/bin/build/WineTest.pl
@@ -43,6 +43,7 @@ sub BEGIN
use Build::Utils;
use WineTestBot::Config;
+use WineTestBot::Missions;
use WineTestBot::Utils;
@@ -52,9 +53,9 @@ use WineTestBot::Utils;
sub BuildWine($$)
{
- my ($Targets, $Build) = @_;
+ my ($TaskMissions, $Build) = @_;
- return 1 if (!$Targets->{$Build});
+ return 1 if (!$TaskMissions->{Builds}->{$Build});
InfoMsg "\nRebuilding the $Build Wine\n";
my $CPUCount = GetCPUCount();
@@ -74,44 +75,40 @@ sub BuildWine($$)
# Test helpers
#
-
-sub DailyWineTest($$$$$)
+sub DailyWineTest($$$$)
{
- my ($Targets, $Build, $NoSubmit, $BaseTag, $Args) = @_;
-
- return 1 if (!$Targets->{$Build});
+ my ($Mission, $NoSubmit, $BaseTag, $Args) = @_;
- InfoMsg "\nRunning WineTest in the $Build Wine\n";
- SetupWineEnvironment($Build);
+ InfoMsg "\nRunning WineTest in the $Mission->{Build} Wine\n";
+ SetupWineEnvironment($Mission->{Build});
# Run WineTest. Ignore the exit code since it returns non-zero whenever
# there are test failures.
- my $Tag = SanitizeTag("$BaseTag-$Build");
- RunWine($Build, "./programs/winetest/winetest.exe.so",
- "-c -o '../$Build.report' -t $Tag ". ShArgv2Cmd(@$Args));
- if (!-f "$Build.report")
+ my $Tag = SanitizeTag("$BaseTag-$Mission->{Build}");
+ RunWine($Mission->{Build}, "./programs/winetest/winetest.exe.so",
+ "-c -o '../$Mission->{Build}.report' -t $Tag ".
+ ShArgv2Cmd(@$Args));
+ if (!-f "$Mission->{Build}.report")
{
LogMsg "WineTest did not produce a report file\n";
return 0;
}
# Send the report to the website
- if (!$NoSubmit and
- RunWine($Build, "./programs/winetest/winetest.exe.so",
- "-c -s '../$Build.report'"))
+ if ((!$NoSubmit and !$Mission->{nosubmit}) and
+ RunWine($Mission->{Build}, "./programs/winetest/winetest.exe.so",
+ "-c -s '../$Mission->{Build}.report'"))
{
- LogMsg "WineTest failed to send the $Build report\n";
+ LogMsg "WineTest failed to send the $Mission->{Build} report\n";
# Soldier on in case it's just a network issue
}
return 1;
}
-sub TestPatch($$$)
+sub TestPatch($$)
{
- my ($Targets, $Build, $Impacts) = @_;
-
- return 1 if (!$Targets->{"test$Build"});
+ my ($Mission, $Impacts) = @_;
my @TestList;
foreach my $Module (sort keys %{$Impacts->{Tests}})
@@ -131,14 +128,15 @@ sub TestPatch($$$)
}
return 1 if (!@TestList);
- InfoMsg "\nRunning the tests in the $Build Wine\n";
- SetupWineEnvironment($Build);
+ InfoMsg "\nRunning the tests in the $Mission->{Build} Wine\n";
+ SetupWineEnvironment($Mission->{Build});
# Run WineTest. Ignore the exit code since it returns non-zero whenever
# there are test failures.
- RunWine($Build, "./programs/winetest/winetest.exe.so",
- "-c -o '../$Build.report' -t test-$Build ". join(" ", @TestList));
- if (!-f "$Build.report")
+ RunWine($Mission->{Build}, "./programs/winetest/winetest.exe.so",
+ "-c -o '../$Mission->{Build}.report' -t test-$Mission->{Build} ".
+ join(" ", @TestList));
+ if (!-f "$Mission->{Build}.report")
{
LogMsg "WineTest did not produce a report file\n";
return 0;
@@ -155,11 +153,8 @@ sub TestPatch($$$)
$ENV{PATH} = "/usr/lib/ccache:/usr/bin:/bin";
delete $ENV{ENV};
-my %AllTargets;
-map { $AllTargets{$_} = 1 } qw(win32 wow32 wow64);
-
my $Action = "";
-my ($Usage, $OptNoSubmit, $TargetList, $FileName, $BaseTag);
+my ($Usage, $OptNoSubmit, $MissionStatement, $FileName, $BaseTag);
while (@ARGV)
{
my $Arg = shift @ARGV;
@@ -186,9 +181,9 @@ while (@ARGV)
$Usage = 2;
last;
}
- elsif (!defined $TargetList)
+ elsif (!defined $MissionStatement)
{
- $TargetList = $Arg;
+ $MissionStatement = $Arg;
}
elsif ($Action eq "winetest")
{
@@ -223,24 +218,35 @@ while (@ARGV)
}
# Check and untaint parameters
-my $Targets;
+my $TaskMissions;
if (!defined $Usage)
{
- if (defined $TargetList)
+ if (defined $MissionStatement)
{
- foreach my $Target (split /[,:]/, $TargetList)
+ my ($ErrMessage, $Missions) = ParseMissionStatement($MissionStatement);
+ if (defined $ErrMessage)
{
- if (!$AllTargets{$Target})
- {
- Error "invalid target name $Target\n";
- $Usage = 2;
- }
- $Targets->{$Target} = 1;
+ Error "$ErrMessage\n";
+ $Usage = 2;
+ }
+ elsif (!@$Missions)
+ {
+ Error "empty mission statement\n";
+ $Usage = 2;
+ }
+ elsif (@$Missions > 1)
+ {
+ Error "cannot specify missions for multiple tasks\n";
+ $Usage = 2;
+ }
+ else
+ {
+ $TaskMissions = $Missions->[0];
}
}
else
{
- Error "specify at least one target\n";
+ Error "you must specify the mission statement\n";
$Usage = 2;
}
@@ -268,16 +274,13 @@ if (!defined $Usage)
}
else
{
- foreach my $Build ("win32", "wow32", "wow64")
- {
- $Targets->{"test$Build"} = 1 if ($Targets->{$Build});
- }
- if ($Targets->{"wow32"} or $Targets->{"wow64"})
+ my $Builds = $TaskMissions->{Builds};
+ if ($Builds->{"wow32"} or $Builds->{"wow64"})
{
# Always rebuild both WoW targets before running the tests to make sure
# we don't run into issues caused by the two Wine builds being out of
# sync.
- $Targets->{"wow32"} = $Targets->{"wow64"} = 1;
+ $Builds->{"wow32"} = $Builds->{"wow64"} = 1;
}
}
@@ -295,8 +298,8 @@ if (defined $Usage)
Error "try '$Name0 --help' for more information\n";
exit $Usage;
}
- print "Usage: $Name0 [--help] --testpatch TARGETS PATCH\n";
- print "or $Name0 [--help] --winetest [--no-submit] TARGETS BASETAG ARGS\n";
+ print "Usage: $Name0 [--help] --testpatch MISSIONS PATCH\n";
+ print "or $Name0 [--help] --winetest [--no-submit] MISSIONS BASETAG ARGS\n";
print "\n";
print "Tests the specified patch or runs WineTest in Wine.\n";
print "\n";
@@ -304,7 +307,7 @@ if (defined $Usage)
print " --testpatch Verify that the patch compiles and run the impacted tests.\n";
print " --winetest Run WineTest and submit the result to the website.\n";
print " --no-submit Do not submit the WineTest results to the website.\n";
- print " TARGETS Is a comma-separated list of targets for the specified action.\n";
+ print " MISSIONS Is a colon-separated list of missions for the specified action.\n";
print " - win32: The regular 32 bit Wine build.\n";
print " - wow32: The 32 bit WoW Wine build.\n";
print " - wow64: The 64 bit WoW Wine build.\n";
@@ -328,26 +331,26 @@ if ($DataDir =~ /'/)
#
# Clean up old reports
-map { unlink("$_.report") } keys %AllTargets;
+map { unlink("$_.report") } keys %{$TaskMissions->{Builds}};
+my $Impacts;
if ($Action eq "testpatch")
{
- my $Impacts = ApplyPatch("wine", $FileName);
+ $Impacts = ApplyPatch("wine", $FileName);
exit(1) if (!$Impacts or
- !BuildWine($Targets, "win32") or
- !BuildWine($Targets, "wow64") or
- !BuildWine($Targets, "wow32") or
- !TestPatch($Targets, "win32", $Impacts) or
- !TestPatch($Targets, "wow64", $Impacts) or
- !TestPatch($Targets, "wow32", $Impacts));
+ !BuildWine($TaskMissions, "win32") or
+ !BuildWine($TaskMissions, "wow64") or
+ !BuildWine($TaskMissions, "wow32"));
}
-elsif ($Action eq "winetest")
+foreach my $Mission (@{$TaskMissions->{Missions}})
{
- if (!DailyWineTest($Targets, "win32", $OptNoSubmit, $BaseTag, \@ARGV) or
- !DailyWineTest($Targets, "wow64", $OptNoSubmit, $BaseTag, \@ARGV) or
- !DailyWineTest($Targets, "wow32", $OptNoSubmit, $BaseTag, \@ARGV))
+ if ($Action eq "testpatch")
{
- exit(1);
+ exit(1) if (!TestPatch($Mission, $Impacts));
+ }
+ elsif ($Action eq "winetest")
+ {
+ exit(1) if (!DailyWineTest($Mission, $OptNoSubmit, $BaseTag, \@ARGV));
}
}
diff --git a/testbot/ddl/update41.sql b/testbot/ddl/update41.sql
new file mode 100644
index 0000000000..f1a5e1a240
--- /dev/null
+++ b/testbot/ddl/update41.sql
@@ -0,0 +1,48 @@
+USE winetestbot;
+
+ALTER TABLE Tasks
+ ADD Missions VARCHAR(256) NULL
+ AFTER Timeout;
+
+UPDATE Tasks, VMs
+ SET Tasks.Missions = 'build'
+ WHERE Tasks.Missions is NULL AND Tasks.VMName = VMs.Name AND VMs.Type = 'build';
+
+UPDATE Tasks, VMs
+ SET Tasks.Missions = 'exe32'
+ WHERE Tasks.Missions is NULL AND Tasks.VMName = VMs.Name AND VMs.Type = 'win32';
+
+UPDATE Tasks, VMs
+ SET Tasks.Missions = 'exe32|exe64'
+ WHERE Tasks.Missions is NULL AND Tasks.VMName = VMs.Name AND VMs.Type = 'win64';
+
+UPDATE Tasks, VMs
+ SET Tasks.Missions = 'win32:wow64'
+ WHERE Tasks.Missions is NULL AND Tasks.VMName = VMs.Name AND VMs.Type = 'wine';
+
+ALTER TABLE Tasks
+ MODIFY Missions VARCHAR(256) NOT NULL;
+
+
+ALTER TABLE VMs
+ ADD Missions VARCHAR(256) NULL
+ AFTER Role;
+
+UPDATE VMs
+ SET Missions = 'build'
+ WHERE Missions is NULL AND Type = 'build';
+
+UPDATE VMs
+ SET Missions = 'exe32'
+ WHERE Missions is NULL AND Type = 'win32';
+
+UPDATE VMs
+ SET Missions = 'exe32|exe64'
+ WHERE Missions is NULL AND Type = 'win64';
+
+UPDATE VMs
+ SET Missions = 'win32|wow64'
+ WHERE Missions is NULL AND Type = 'wine';
+
+ALTER TABLE VMs
+ MODIFY Missions VARCHAR(256) NOT NULL;
diff --git a/testbot/ddl/winetestbot.sql b/testbot/ddl/winetestbot.sql
index 8862c6c9dc..e6114e0917 100644
--- a/testbot/ddl/winetestbot.sql
+++ b/testbot/ddl/winetestbot.sql
@@ -48,6 +48,7 @@ CREATE TABLE VMs
SortOrder INT(3) NOT NULL,
Type ENUM('win32', 'win64', 'build', 'wine') NOT NULL,
Role ENUM('extra', 'base', 'winetest', 'retired', 'deleted') NOT NULL,
+ Missions VARCHAR(256) NOT NULL,
Status ENUM('dirty', 'reverting', 'sleeping', 'idle', 'running', 'off', 'offline', 'maintenance') NOT NULL,
Errors INT(2) NULL,
ChildPid INT(5) NULL,
@@ -149,6 +150,7 @@ CREATE TABLE Tasks
Status ENUM('queued', 'running', 'completed', 'badpatch', 'badbuild', 'boterror', 'canceled', 'skipped') NOT NULL,
VMName VARCHAR(20) NOT NULL,
Timeout INT(4) NOT NULL,
+ Missions VARCHAR(256) NOT NULL,
CmdLineArg VARCHAR(256) NULL,
Started DATETIME NULL,
Ended DATETIME NULL,
diff --git a/testbot/doc/winetestbot-schema.dia b/testbot/doc/winetestbot-schema.dia
index c54897a831..372d3bf006 100644
--- a/testbot/doc/winetestbot-schema.dia
+++ b/testbot/doc/winetestbot-schema.dia
@@ -2106,6 +2106,29 @@
<dia:string>##</dia:string>
</dia:attribute>
</dia:composite>
+ <dia:composite type="table_attribute">
+ <dia:attribute name="name">
+ <dia:string>#Missions#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#VARCHAR(256)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="comment">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="primary_key">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="nullable">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="unique">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="default_value">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ </dia:composite>
<dia:composite type="table_attribute">
<dia:attribute name="name">
<dia:string>#CmdLineArg#</dia:string>
@@ -2360,6 +2383,29 @@
<dia:string>##</dia:string>
</dia:attribute>
</dia:composite>
+ <dia:composite type="table_attribute">
+ <dia:attribute name="name">
+ <dia:string>#Missions#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#VARCHAR(256)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="comment">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="primary_key">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="nullable">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="unique">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="default_value">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ </dia:composite>
<dia:composite type="table_attribute">
<dia:attribute name="name">
<dia:string>#Status#</dia:string>
diff --git a/testbot/lib/WineTestBot/Missions.pm b/testbot/lib/WineTestBot/Missions.pm
new file mode 100644
index 0000000000..58b33403fb
--- /dev/null
+++ b/testbot/lib/WineTestBot/Missions.pm
@@ -0,0 +1,99 @@
+# -*- Mode: Perl; perl-indent-level: 2; indent-tabs-mode: nil -*-
+# Copyright 2018 Francois Gouget
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+use strict;
+
+package WineTestBot::Missions;
+
+=head1 NAME
+
+WineTestBot::Missions - Missions parser and helper functions
+
+=cut
+
+use Exporter 'import';
+our @EXPORT = qw(DumpMissions ParseMissionStatement
+ MergeMissionStatementTasks SplitMissionStatementTasks);
+
+
+sub DumpMissions($$)
+{
+ my ($Label, $Missions) = @_;
+
+ print STDERR "$Label:\n";
+ foreach my $TaskMissions (@$Missions)
+ {
+ print STDERR "Builds=", join(",", sort keys %{$TaskMissions->{Builds}}), "\n";
+ foreach my $Mission (@{$TaskMissions->{Missions}})
+ {
+ print STDERR " [$Mission->{Build}]\n";
+ print STDERR " \"$_\"=\"$Mission->{$_}\"\n" for (sort grep(!/^Build$/,keys %$Mission));
+ }
+ }
+}
+
+sub ParseMissionStatement($)
+{
+ my ($MissionStatement) = @_;
+
+ my @Missions;
+ foreach my $TaskStatement (split /[|]/, $MissionStatement)
+ {
+ my $TaskMissions = { Statement => $TaskStatement };
+ push @Missions, $TaskMissions;
+ foreach my $Statement (split /:/, $TaskStatement)
+ {
+ my ($Build, @Options) = split /,/, $Statement;
+ if ($Build !~ /^([a-z0-9]+)$/)
+ {
+ return ("Invalid mission name '$Build'", undef);
+ }
+ $Build = $1; # untaint
+ $TaskMissions->{Builds}->{$Build} = 1;
+ my $Mission = { Build => $Build, Statement => $Statement };
+ push @{$TaskMissions->{Missions}}, $Mission;
+
+ foreach my $Option (@Options)
+ {
+ if ($Option !~ s/^([a-z0-9_]+)//)
+ {
+ return ("Invalid option name '$Option'", undef);
+ }
+ my $Name = $1; # untaint
+ # do not untaint the value
+ $Mission->{$Name} = ($Option =~ s/^=//) ? $Option : 1;
+ }
+ }
+ }
+ return (undef, \@Missions);
+}
+
+sub MergeMissionStatementTasks($)
+{
+ my ($MissionStatement) = @_;
+ $MissionStatement =~ s/\|/:/g;
+ return $MissionStatement;
+}
+
+sub SplitMissionStatementTasks($)
+{
+ my ($MissionStatement) = @_;
+ $MissionStatement =~ s/:/|/g;
+ return $MissionStatement;
+}
+
+1;
diff --git a/testbot/lib/WineTestBot/PatchUtils.pm b/testbot/lib/WineTestBot/PatchUtils.pm
index 7df50f9b21..444ffaf491 100644
--- a/testbot/lib/WineTestBot/PatchUtils.pm
+++ b/testbot/lib/WineTestBot/PatchUtils.pm
@@ -457,10 +457,10 @@ sub GetPatchImpacts($)
sub GetBuildTimeout($$)
{
- my ($Impacts, $Builds) = @_;
+ my ($Impacts, $TaskMissions) = @_;
my ($ExeCount, $WineCount);
- map {$_ =~ /^exe/ ? $ExeCount++ : $WineCount++ } keys %$Builds;
+ map {$_ =~ /^exe/ ? $ExeCount++ : $WineCount++ } keys %{$TaskMissions->{Builds}};
# Set $ModuleCount to 0 if a full rebuild is needed
my $ModuleCount = (!$Impacts or $Impacts->{RebuildRoot}) ? 0 :
@@ -486,7 +486,7 @@ sub GetBuildTimeout($$)
sub GetTestTimeout($$)
{
- my ($Impacts, $Builds) = @_;
+ my ($Impacts, $TaskMissions) = @_;
my $Timeout = $SuiteTimeout;
if ($Impacts)
@@ -496,7 +496,7 @@ sub GetTestTimeout($$)
max(0, $UnitCount - 2) * $SingleAvgTime;
$Timeout = min($SuiteTimeout, $TestsTimeout);
}
- return scalar(keys %$Builds) * $Timeout;
+ return @{$TaskMissions->{Missions}} * $Timeout;
}
1;
diff --git a/testbot/lib/WineTestBot/Patches.pm b/testbot/lib/WineTestBot/Patches.pm
index f685e86b32..e621e8845d 100644
--- a/testbot/lib/WineTestBot/Patches.pm
+++ b/testbot/lib/WineTestBot/Patches.pm
@@ -40,12 +40,13 @@ use Encode qw/decode/;
use File::Basename;
use WineTestBot::Config;
+use WineTestBot::Engine::Notify;
use WineTestBot::Jobs;
+use WineTestBot::Missions;
use WineTestBot::PatchUtils;
use WineTestBot::Users;
use WineTestBot::Utils;
use WineTestBot::VMs;
-use WineTestBot::Engine::Notify;
sub InitializeNew($$)
@@ -175,23 +176,8 @@ sub Submit($$$)
$BuildVMs->AddFilter("Role", ["base"]);
if ($Impacts->{TestUnitCount} and !$BuildVMs->IsEmpty())
{
- # Create the Build Step
- my $BuildStep = $NewJob->Steps->Add();
- $BuildStep->FileName("patch.diff");
- $BuildStep->FileType("patch");
- $BuildStep->Type("build");
- $BuildStep->DebugLevel(0);
-
- # Save the build step so the others can reference it.
- my ($ErrKey, $ErrProperty, $ErrMessage) = $Jobs->Save();
- if (defined($ErrMessage))
- {
- $self->Disposition("Failed to submit build step");
- return $ErrMessage;
- }
-
# Create steps for the Windows tests
- my $Builds;
+ my ($BuildStep, $BuildMissions);
foreach my $Module (sort keys %{$Impacts->{Tests}})
{
my $TestInfo = $Impacts->{Tests}->{$Module};
@@ -202,26 +188,54 @@ sub Submit($$$)
my $WinVMs = CreateVMs();
$WinVMs->AddFilter("Type", $Bits eq "32" ? ["win32", "win64"] : ["win64"]);
$WinVMs->AddFilter("Role", ["base"]);
- if (!$WinVMs->IsEmpty())
+ my $SortedKeys = $WinVMs->SortKeysBySortOrder($WinVMs->GetKeys());
+
+ my $Tasks;
+ foreach my $VMKey (@$SortedKeys)
{
- # Create one Step per (module, unit, bitness) combination
- my $NewStep = $NewJob->Steps->Add();
- $NewStep->PreviousNo($BuildStep->No);
- my $FileName = $TestInfo->{ExeBase};
- $FileName .= "64" if ($Bits eq "64");
- $NewStep->FileName("$FileName.exe");
- $NewStep->FileType("exe$Bits");
- $Builds->{"exe$Bits"} = 1;
-
- # And a task for each VM
- my $Tasks = $NewStep->Tasks;
- my $SortedKeys = $WinVMs->SortKeysBySortOrder($WinVMs->GetKeys());
- foreach my $VMKey (@$SortedKeys)
+ my $VM = $WinVMs->GetItem($VMKey);
+ my ($ErrMessage, $Missions) = ParseMissionStatement($VM->Missions);
+ next if (defined $ErrMessage);
+
+ foreach my $TaskMissions (@$Missions)
{
- my $VM = $WinVMs->GetItem($VMKey);
+ next if (!$TaskMissions->{Builds}->{"exe$Bits"});
+
+ if (!$BuildStep)
+ {
+ # Create the Build Step
+ $BuildStep = $NewJob->Steps->Add();
+ $BuildStep->FileName("patch.diff");
+ $BuildStep->FileType("patch");
+ $BuildStep->Type("build");
+ $BuildStep->DebugLevel(0);
+
+ # Save the build step so the others can reference it.
+ my ($ErrKey, $ErrProperty, $ErrMessage) = $Jobs->Save();
+ if (defined($ErrMessage))
+ {
+ $self->Disposition("Failed to submit build step");
+ return $ErrMessage;
+ }
+ }
+
+ if (!$Tasks)
+ {
+ # Create one Step per (module, unit, bitness) combination
+ my $NewStep = $NewJob->Steps->Add();
+ $NewStep->PreviousNo($BuildStep->No);
+ my $FileName = $TestInfo->{ExeBase};
+ $FileName .= "64" if ($Bits eq "64");
+ $NewStep->FileName("$FileName.exe");
+ $NewStep->FileType("exe$Bits");
+ $BuildMissions->{Builds}->{"exe$Bits"} = 1;
+ $Tasks = $NewStep->Tasks;
+ }
+
my $Task = $Tasks->Add();
$Task->VM($VM);
$Task->Timeout($SingleTimeout);
+ $Task->Missions($TaskMissions->{Statement});
$Task->CmdLineArg($Unit);
}
}
@@ -229,38 +243,48 @@ sub Submit($$$)
}
}
- # Add the build task
- my $BuildVM = ${$BuildVMs->GetItems()}[0];
- my $BuildTask = $BuildStep->Tasks->Add();
- $BuildTask->VM($BuildVM);
- $BuildTask->Timeout(GetBuildTimeout($Impacts, $Builds));
+ if ($BuildStep)
+ {
+ # Add the build task
+ my $BuildVM = ${$BuildVMs->GetItems()}[0];
+ my $BuildTask = $BuildStep->Tasks->Add();
+ $BuildTask->VM($BuildVM);
+ $BuildMissions->{Statement} = join(":", keys %{$BuildMissions->{Builds}});
+ $BuildTask->Timeout(GetBuildTimeout($Impacts, $BuildMissions));
+ $BuildTask->Missions($BuildMissions->{Statement});
+ }
}
my $WineVMs = CreateVMs();
$WineVMs->AddFilter("Type", ["wine"]);
$WineVMs->AddFilter("Role", ["base"]);
- if (!$WineVMs->IsEmpty())
+ my $SortedKeys = $WineVMs->SortKeysBySortOrder($WineVMs->GetKeys());
+
+ my $Tasks;
+ foreach my $VMKey (@$SortedKeys)
{
- # Add a Wine step to the job
- my $NewStep = $NewJob->Steps->Add();
- $NewStep->FileName("patch.diff");
- $NewStep->FileType("patch");
- $NewStep->Type("single");
- $NewStep->DebugLevel(0);
-
- # And a task for each VM
- my $Tasks = $NewStep->Tasks;
- my $SortedKeys = $WineVMs->SortKeysBySortOrder($WineVMs->GetKeys());
- foreach my $VMKey (@$SortedKeys)
+ my $VM = $WineVMs->GetItem($VMKey);
+ my ($ErrMessage, $Missions) = ParseMissionStatement($VM->Missions);
+ next if (defined $ErrMessage);
+
+ foreach my $TaskMissions (@$Missions)
{
- my $VM = $WineVMs->GetItem($VMKey);
+ if (!$Tasks)
+ {
+ # Add a Wine step to the job
+ my $TestStep = $NewJob->Steps->Add();
+ $TestStep->FileName("patch.diff");
+ $TestStep->FileType("patch");
+ $TestStep->Type("single");
+ $TestStep->DebugLevel(0);
+ $Tasks = $TestStep->Tasks;
+ }
+
my $Task = $Tasks->Add();
$Task->VM($VM);
- # Only verify that the win32 version compiles
- my $Builds = { "win32" => 1 };
- $Task->Timeout(GetBuildTimeout($Impacts, $Builds) +
- GetTestTimeout($Impacts, $Builds));
- $Task->CmdLineArg(join(",", keys %$Builds));
+ $Task->Timeout(GetBuildTimeout($Impacts, $TaskMissions) +
+ GetTestTimeout($Impacts, $TaskMissions));
+ $Task->Missions($TaskMissions->{Statement});
}
}
diff --git a/testbot/lib/WineTestBot/StepsTasks.pm b/testbot/lib/WineTestBot/StepsTasks.pm
index a50f61ada3..cfd78e52e2 100644
--- a/testbot/lib/WineTestBot/StepsTasks.pm
+++ b/testbot/lib/WineTestBot/StepsTasks.pm
@@ -30,6 +30,7 @@ use WineTestBot::WineTestBotObjects;
our @ISA = qw(WineTestBot::WineTestBotItem);
use WineTestBot::Config;
+use WineTestBot::Missions;
sub GetStepDir($)
@@ -68,34 +69,50 @@ sub GetTitle($)
{
my ($self) = @_;
- my $Title = "";
- if ($self->Type eq "single")
+ my @TitleParts;
+ if ($self->Type eq "build")
{
- if ($self->FileType eq "exe32")
- {
- $Title .= "32 bit ";
- }
- elsif ($self->FileType eq "exe64")
- {
- $Title .= "64 bit ";
- }
- $Title .= $self->CmdLineArg || "";
+ push @TitleParts, "build";
}
- elsif ($self->Type eq "build")
+ elsif ($self->FileType eq "exe32")
{
- $Title = "build";
+ push @TitleParts, "32 bit";
}
- $Title =~ s/\s*$//;
-
- if ($Title)
+ elsif ($self->FileType eq "exe64")
{
- $Title = $self->VM->Name . " (" . $Title . ")";
+ push @TitleParts, "64 bit";
}
else
{
- $Title = $self->VM->Name;
+ my ($ErrMessage, $Missions) = ParseMissionStatement($self->Missions);
+ if (!defined $ErrMessage and @$Missions == 1)
+ {
+ my $Builds = $Missions->[0]->{Builds};
+ if ($Builds->{build})
+ {
+ push @TitleParts, "build";
+ }
+ elsif ($Builds->{wow64} and ($Builds->{win32} or $Builds->{wow32}))
+ {
+ push @TitleParts, "32 & 64 bit";
+ }
+ elsif ($Builds->{win32} or $Builds->{wow32})
+ {
+ push @TitleParts, "32 bit";
+ }
+ elsif ($Builds->{wow64})
+ {
+ push @TitleParts, "64 bit";
+ }
+ }
+ }
+ if ($self->Type ne "suite" and $self->CmdLineArg)
+ {
+ push @TitleParts, $self->CmdLineArg;
}
+ my $Title = $self->VM->Name;
+ $Title .= " (@TitleParts)" if (@TitleParts);
return $Title;
}
@@ -148,6 +165,7 @@ sub _initialize($$)
$StepTask->Timeout($Task->Timeout);
$StepTask->FileName($Step->FileName);
$StepTask->FileType($Step->FileType);
+ $StepTask->Missions($Task->Missions);
$StepTask->CmdLineArg($Task->CmdLineArg);
$StepTask->Started($Task->Started);
$StepTask->Ended($Task->Ended);
@@ -179,6 +197,7 @@ my @PropertyDescriptors = (
CreateBasicPropertyDescriptor("Timeout", "Timeout", !1, 1, "N", 4),
CreateBasicPropertyDescriptor("FileName", "File name", !1, !1, "A", 100),
CreateBasicPropertyDescriptor("FileType", "File Type", !1, 1, "A", 32),
+ CreateBasicPropertyDescriptor("Missions", "Missions", !1, 1, "A", 256),
CreateBasicPropertyDescriptor("CmdLineArg", "Command line args", !1, !1, "A", 256),
CreateBasicPropertyDescriptor("Started", "Execution started", !1, !1, "DT", 19),
CreateBasicPropertyDescriptor("Ended", "Execution ended", !1, !1, "DT", 19),
diff --git a/testbot/lib/WineTestBot/Tasks.pm b/testbot/lib/WineTestBot/Tasks.pm
index 084784a3ba..f9e84d471b 100644
--- a/testbot/lib/WineTestBot/Tasks.pm
+++ b/testbot/lib/WineTestBot/Tasks.pm
@@ -298,6 +298,7 @@ my @PropertyDescriptors = (
CreateEnumPropertyDescriptor("Status", "Status", !1, 1, ['queued', 'running', 'completed', 'badpatch', 'badbuild', 'boterror', 'canceled', 'skipped']),
CreateItemrefPropertyDescriptor("VM", "VM", !1, 1, \&CreateVMs, ["VMName"]),
CreateBasicPropertyDescriptor("Timeout", "Timeout", !1, 1, "N", 4),
+ CreateBasicPropertyDescriptor("Missions", "Missions", !1, 1, "A", 256),
CreateBasicPropertyDescriptor("CmdLineArg", "Command line args", !1, !1, "A", 256),
CreateBasicPropertyDescriptor("Started", "Execution started", !1, !1, "DT", 19),
CreateBasicPropertyDescriptor("Ended", "Execution ended", !1, !1, "DT", 19),
diff --git a/testbot/lib/WineTestBot/VMs.pm b/testbot/lib/WineTestBot/VMs.pm
index cf7bd5ab75..e7cd277494 100644
--- a/testbot/lib/WineTestBot/VMs.pm
+++ b/testbot/lib/WineTestBot/VMs.pm
@@ -151,6 +151,7 @@ use ObjectModel::BackEnd;
use WineTestBot::Config;
use WineTestBot::Engine::Notify;
use WineTestBot::LibvirtDomain;
+use WineTestBot::Missions;
use WineTestBot::RecordGroups;
use WineTestBot::TestAgent;
@@ -302,6 +303,24 @@ sub KillChild($)
$self->ChildPid(undef);
}
+sub PutColValue($$$)
+{
+ my ($self, $ColName, $Value) = @_;
+
+ $self->SUPER::PutColValue($ColName, $Value);
+ if ($self->{IsModified} and ($ColName eq "Type" or $ColName eq "Missions"))
+ {
+ $self->{ValidateMissions} = 1;
+ }
+}
+
+my $_SupportedMissions = {
+ "build" => { "build" => 1 },
+ "win32" => { "exe32" => 1 },
+ "win64" => { "exe32" => 1, "exe64" => 1 },
+ "wine" => { "win32" => 1, "wow32" => 1, "wow64" => 1 },
+};
+
sub Validate($)
{
my ($self) = @_;
@@ -311,6 +330,27 @@ sub Validate($)
{
return ("Role", "Only win32, win64 and wine VMs can have a role of '" . $self->Role . "'");
}
+ if ($self->{ValidateMissions})
+ {
+ my ($ErrMessage, $Missions) = ParseMissionStatement($self->Missions);
+ return ("Missions", $ErrMessage) if (defined $ErrMessage);
+ foreach my $TaskMissions (@$Missions)
+ {
+ if ($self->Type ne "wine" and @{$TaskMissions->{Missions}} > 1)
+ {
+ return ("Missions", "Only wine VMs can handle more than one mission per task");
+ }
+ foreach my $Mission (@{$TaskMissions->{Missions}})
+ {
+ if (!$_SupportedMissions->{$self->Type}->{$Mission->{Build}})
+ {
+ return ("Missions", ucfirst($self->Type) ." VMs only support ". join(", ", sort keys %{$_SupportedMissions->{$self->Type}}) ." missions");
+ }
+ }
+ }
+ delete $self->{ValidateMissions};
+ }
+
return $self->SUPER::Validate();
}
@@ -666,6 +706,7 @@ my @PropertyDescriptors = (
CreateBasicPropertyDescriptor("SortOrder", "Display order", !1, 1, "N", 3),
CreateEnumPropertyDescriptor("Type", "Type of VM", !1, 1, ['win32', 'win64', 'build', 'wine']),
CreateEnumPropertyDescriptor("Role", "VM Role", !1, 1, ['extra', 'base', 'winetest', 'retired', 'deleted']),
+ CreateBasicPropertyDescriptor("Missions", "Missions", !1, 1, "A", 256),
CreateEnumPropertyDescriptor("Status", "Current status", !1, 1, ['dirty', 'reverting', 'sleeping', 'idle', 'running', 'off', 'offline', 'maintenance']),
CreateBasicPropertyDescriptor("Errors", "Errors", !1, !1, "N", 2),
CreateBasicPropertyDescriptor("ChildPid", "Child process id", !1, !1, "N", 5),
diff --git a/testbot/web/JobDetails.pl b/testbot/web/JobDetails.pl
index 8efe5eefcf..de2f9ccb40 100644
--- a/testbot/web/JobDetails.pl
+++ b/testbot/web/JobDetails.pl
@@ -398,6 +398,7 @@ EOF
print "<details><summary>",
$self->CGI->escapeHTML($VM->Description || $VM->Name), "</summary>",
$self->CGI->escapeHTML($VM->Details || "No details!"),
+ ($StepTask->Missions ? "<br>Missions: ". $StepTask->Missions : ""),
"</details>\n";
my $MoreInfo = $self->{More}->{$Key};
diff --git a/testbot/web/Submit.pl b/testbot/web/Submit.pl
index c10a267909..bcb5458ad5 100644
--- a/testbot/web/Submit.pl
+++ b/testbot/web/Submit.pl
@@ -36,6 +36,7 @@ use WineTestBot::Branches;
use WineTestBot::Config;
use WineTestBot::Engine::Notify;
use WineTestBot::Jobs;
+use WineTestBot::Missions;
use WineTestBot::PatchUtils;
use WineTestBot::Steps;
use WineTestBot::Utils;
@@ -814,13 +815,18 @@ sub SubmitJob($$$)
my $Task = $BuildStep->Tasks->Add();
$Task->VM($BuildVM);
- my $Builds = { "exe32" => 1 };
- $Builds->{"exe64"} = 1 if defined $self->GetParam("Run64");
- $Task->Timeout(GetBuildTimeout($Impacts, $Builds));
+ my $MissionStatement = "exe32";
+ $MissionStatement .= ":exe64" if (defined $self->GetParam("Run64"));
+ my ($ErrMessage, $Missions) = ParseMissionStatement($MissionStatement);
+ if (!defined $ErrMessage)
+ {
+ $Task->Timeout(GetBuildTimeout($Impacts, $Missions->[0]));
+ $Task->Missions($Missions->[0]);
- # Save the build step so the others can reference it
- my ($ErrKey, $ErrProperty, $ErrMessage) = $Jobs->Save();
- if (defined($ErrMessage))
+ # Save the build step so the others can reference it
+ (my $ErrKey, my $ErrProperty, $ErrMessage) = $Jobs->Save();
+ }
+ if (defined $ErrMessage)
{
$self->{ErrMessage} = $ErrMessage;
return !1;
@@ -851,51 +857,53 @@ sub SubmitJob($$$)
my $Task = $Tasks->Add();
$Task->VM($VM);
$Task->Timeout($SingleTimeout);
+ $Task->Missions("exe$Bits");
$Task->CmdLineArg($self->GetParam("CmdLineArg"));
}
}
if ($FileType eq "patch")
{
- my $Tasks;
+ my ($Tasks, $MissionStatement, $Timeout);
my $VMs = CreateVMs();
$VMs->AddFilter("Type", ["wine"]);
my $SortedKeys = $VMs->SortKeysBySortOrder($VMs->GetKeys());
- foreach my $Build ("win32", "wow64")
+ foreach my $VMKey (@$SortedKeys)
{
- next if ($Build eq "wow64" and !defined($self->GetParam("Run64")));
+ my $VM = $VMs->GetItem($VMKey);
+ my $FieldName = "vm_" . $self->CGI->escapeHTML($VMKey);
+ next if (!$self->GetParam($FieldName)); # skip unselected VMs
- my $Timeout;
- foreach my $VMKey (@$SortedKeys)
+ if (!$Tasks)
{
- my $VM = $VMs->GetItem($VMKey);
- my $FieldName = "vm_" . $self->CGI->escapeHTML($VMKey);
- next if (!$self->GetParam($FieldName)); # skip unselected VMs
-
- if (!$Tasks)
+ # First create the Wine test step
+ my $WineStep = $Steps->Add();
+ $WineStep->FileName($BaseName);
+ $WineStep->FileType($FileType);
+ $WineStep->Type("single");
+ $WineStep->DebugLevel($self->GetParam("DebugLevel"));
+ $WineStep->ReportSuccessfulTests(defined($self->GetParam("ReportSuccessfulTests")));
+ $Tasks = $WineStep->Tasks;
+
+ $MissionStatement = "win32";
+ $MissionStatement.= ":wow64" if (defined $self->GetParam("Run64"));
+
+ my ($ErrMessage, $Missions) = ParseMissionStatement($MissionStatement);
+ if (defined $ErrMessage)
{
- # First create the Wine test step
- my $WineStep = $Steps->Add();
- $WineStep->FileName($BaseName);
- $WineStep->FileType($FileType);
- $WineStep->Type("single");
- $WineStep->DebugLevel($self->GetParam("DebugLevel"));
- $WineStep->ReportSuccessfulTests(defined($self->GetParam("ReportSuccessfulTests")));
- $Tasks = $WineStep->Tasks;
+ $self->{ErrMessage} = $ErrMessage;
+ return !1;
}
- if (!defined $Timeout)
- {
- my $Builds = { $Build => 1 };
- $Timeout = GetBuildTimeout($Impacts, $Builds) +
- GetTestTimeout($Impacts, $Builds);
- }
-
- # Then add a task for this VM
- my $Task = $Tasks->Add();
- $Task->VM($VM);
- $Task->CmdLineArg($Build);
- $Task->Timeout($Timeout);
+ $Missions = $Missions->[0];
+ $Timeout = GetBuildTimeout($Impacts, $Missions) +
+ GetTestTimeout($Impacts, $Missions);
}
+
+ # Then add a task for this VM
+ my $Task = $Tasks->Add();
+ $Task->VM($VM);
+ $Task->Timeout($Timeout);
+ $Task->Missions($MissionStatement);
}
}
diff --git a/testbot/web/admin/VMDetails.pl b/testbot/web/admin/VMDetails.pl
index 9603e346a8..5f49c684d8 100644
--- a/testbot/web/admin/VMDetails.pl
+++ b/testbot/web/admin/VMDetails.pl
@@ -67,6 +67,22 @@ sub Save($)
return ! defined($self->{ErrMessage});
}
+sub GenerateFooter($)
+{
+ my ($self) = @_;
+ print "<p></p><div class='CollectionBlock'><table>\n";
+ print "<thead><tr><th class='Record'>Legend</th></tr></thead>\n";
+ print "<tbody><tr><td class='Record'>\n";
+
+ print "<p>The Missions syntax is <i>mission1:mission2:...|mission3|...</i> where <i>mission1</i> and <i>mission2</i> will be run in the same task, and <i>mission3</i> in a separate task.<br>\n";
+ print "Each mission is composed of a build and options separated by commas: <i>build,option1=value,option2,...</i>. The value can be omitted for boolean options and defaults to true.<br>\n";
+ print "The supported builds are <i>build</i> for build VMs; <i>exe32</i> and <i>exe64</i> for Windows VMs;<i> win32</i>, <i>wow32</i> and <i>wow64</i> for Wine VMs.</p>\n";
+ print "<p>On Wine VMs:<br>\n";
+ print "If set, the <i>nosubmit</i> option specifies that the WineTest results should not be published online.</p>\n";
+ print "</td></tr></tbody>\n";
+ print "</table></div>\n";
+ $self->SUPER::GenerateFooter();
+}
package main;
--
2.19.1
1
4
Signed-off-by: Alistair Leslie-Hughes <leslie_alistair(a)hotmail.com>
---
dlls/odbccp32/odbccp32.c | 156 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 132 insertions(+), 24 deletions(-)
diff --git a/dlls/odbccp32/odbccp32.c b/dlls/odbccp32/odbccp32.c
index 694a90c..ed0bf10 100644
--- a/dlls/odbccp32/odbccp32.c
+++ b/dlls/odbccp32/odbccp32.c
@@ -102,6 +102,33 @@ static inline WCHAR *heap_strdupAtoW(const char *str)
return ret;
}
+static inline WCHAR *heap_attrdupAtoW(const char *str)
+{
+ LPWSTR ret = NULL;
+
+ if(str)
+ {
+ DWORD size = 0, len;
+ const char *p;
+ LPWSTR current = NULL;
+
+ for (p = str; *p; p += lstrlenA(p) + 1)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
+ size += len;
+ }
+
+ current = ret = heap_alloc_zero( (size+1)*sizeof(WCHAR));
+ for (p = str; *p; p += lstrlenA(p) + 1)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, p, -1, current, size);
+ current += len;
+ size -= len;
+ }
+ }
+ return ret;
+}
+
BOOL WINAPI ODBCCPlApplet( LONG i, LONG j, LONG * p1, LONG * p2)
{
@@ -220,30 +247,6 @@ static BOOL SQLInstall_narrow(int mode, LPSTR buffer, LPCWSTR str, WORD str_leng
return success;
}
-BOOL WINAPI SQLConfigDataSourceW(HWND hwndParent, WORD fRequest,
- LPCWSTR lpszDriver, LPCWSTR lpszAttributes)
-{
- LPCWSTR p;
-
- clear_errors();
- FIXME("%p %d %s %s\n", hwndParent, fRequest, debugstr_w(lpszDriver),
- debugstr_w(lpszAttributes));
-
- for (p = lpszAttributes; *p; p += lstrlenW(p) + 1)
- FIXME("%s\n", debugstr_w(p));
-
- return TRUE;
-}
-
-BOOL WINAPI SQLConfigDataSource(HWND hwndParent, WORD fRequest,
- LPCSTR lpszDriver, LPCSTR lpszAttributes)
-{
- FIXME("%p %d %s %s\n", hwndParent, fRequest, debugstr_a(lpszDriver),
- debugstr_a(lpszAttributes));
- clear_errors();
- return TRUE;
-}
-
static HMODULE load_config_driver(const WCHAR *driver)
{
static WCHAR reg_driver[] = {'d','r','i','v','e','r',0};
@@ -360,6 +363,111 @@ fail:
return FALSE;
}
+static BOOL call_ConfigDNS(HANDLE mod, HWND hwnd, WORD request, LPCSTR driverA, LPCSTR attributesA, LPCWSTR driverW, LPCWSTR attributesW)
+{
+ BOOL (WINAPI *pConfigDSN)(HWND hwnd, WORD request, const char *driver, const char *attr);
+ BOOL (WINAPI *pConfigDSNW)(HWND hwnd, WORD request, const WCHAR *driver, const WCHAR *attr);
+ BOOL ret = FALSE;
+
+ TRACE("%p, %p, %d, %p, %p, %p %p\n", mod, hwnd, request, driverA, attributesA, driverW, attributesW);
+
+ pConfigDSN = (void*)GetProcAddress(mod, "ConfigDSN");
+ pConfigDSNW = (void*)GetProcAddress(mod, "ConfigDSNW");
+
+ if(pConfigDSNW)
+ {
+ const WCHAR *attr = attributesW;
+ if(!attr)
+ attr = heap_attrdupAtoW(attributesA);
+
+ TRACE("Calling ConfigDSNW (%p)\n", pConfigDSNW);
+
+ ret = pConfigDSNW(hwnd, request, driverW, attr);
+
+ if(attr != attributesW)
+ heap_free((WCHAR *)attr);
+ }
+ else if(pConfigDSN)
+ {
+ TRACE("Calling pConfigDSN (%p)\n", pConfigDSN);
+ ret = pConfigDSN(hwnd, request, driverA, attributesA);
+ }
+ else
+ ERR("Neither ConfigDSN or ConfigDSNW found.\n");
+
+ if(!ret)
+ push_error(ODBC_ERROR_REQUEST_FAILED, odbc_error_request_failed);
+
+ return ret;
+}
+
+BOOL WINAPI SQLConfigDataSourceW(HWND hwndParent, WORD fRequest,
+ LPCWSTR lpszDriver, LPCWSTR lpszAttributes)
+{
+ HMODULE hmod;
+ BOOL ret = FALSE;
+
+ TRACE("%p, %d, %s, %s\n", hwndParent, fRequest, debugstr_w(lpszDriver), debugstr_w(lpszAttributes));
+ if(TRACE_ON(odbc))
+ {
+ const WCHAR *p;
+ for (p = lpszAttributes; *p; p += lstrlenW(p) + 1)
+ TRACE("%s\n", debugstr_w(p));
+ }
+
+ clear_errors();
+
+ hmod = load_config_driver(lpszDriver);
+ if(!hmod)
+ return FALSE;
+
+ ret = call_ConfigDNS (hmod, hwndParent, fRequest, NULL, NULL, lpszDriver, lpszAttributes);
+
+ FreeLibrary(hmod);
+
+ return ret;
+}
+
+BOOL WINAPI SQLConfigDataSource(HWND hwndParent, WORD fRequest,
+ LPCSTR lpszDriver, LPCSTR lpszAttributes)
+{
+ HMODULE hmod;
+ BOOL ret = FALSE;
+ WCHAR *driverW;
+
+ TRACE("%p, %d, %s, %s\n", hwndParent, fRequest, debugstr_a(lpszDriver), debugstr_a(lpszAttributes));
+
+ if(TRACE_ON(odbc))
+ {
+ const char *p;
+ for (p = lpszAttributes; *p; p += lstrlenA(p) + 1)
+ TRACE("%s\n", debugstr_a(p));
+ }
+
+ clear_errors();
+
+ driverW = heap_strdupAtoW(lpszDriver);
+ if(!driverW)
+ {
+ push_error(ODBC_ERROR_OUT_OF_MEM, odbc_error_out_of_mem);
+ return FALSE;
+ }
+
+ hmod = load_config_driver(driverW);
+ if(!hmod)
+ {
+ heap_free(driverW);
+ return FALSE;
+ }
+
+ ret = call_ConfigDNS (hmod, hwndParent, fRequest, lpszDriver, lpszAttributes, driverW, NULL);
+ heap_free(driverW);
+
+ FreeLibrary(hmod);
+
+ return ret;
+}
+
BOOL WINAPI SQLConfigDriverW(HWND hwnd, WORD request, LPCWSTR driver,
LPCWSTR args, LPWSTR msg, WORD msgmax, WORD *msgout)
{
--
1.9.1
2
2