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
September 2018
- 70 participants
- 627 discussions
05 Sep '18
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45727
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/button.c | 421 +++++++++++++++++++++++++++++------------
1 file changed, 295 insertions(+), 126 deletions(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c
index 6f9bc39de5..653586a748 100644
--- a/dlls/comctl32/button.c
+++ b/dlls/comctl32/button.c
@@ -98,7 +98,7 @@ typedef struct _BUTTON_INFO
} u;
} BUTTON_INFO;
-static UINT BUTTON_CalcLabelRect( const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc );
+static UINT BUTTON_CalcLayoutRects( const BUTTON_INFO *infoPtr, HDC hdc, RECT *labelRc, RECT *imageRc, RECT *textRc );
static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
@@ -615,7 +615,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
/* FIXME: check other BS_* handlers */
if (btn_type == BS_GROUPBOX)
InflateRect(&rc, -7, 1); /* GB_Paint does this */
- BUTTON_CalcLabelRect(infoPtr, hdc, &rc);
+ BUTTON_CalcLayoutRects(infoPtr, hdc, &rc, NULL, NULL);
/* Clip by client rect bounds */
if (rc.right > client.right) rc.right = client.right;
if (rc.bottom > client.bottom) rc.bottom = client.bottom;
@@ -855,95 +855,257 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
return 0;
}
+/* If maxWidth is zero, rectangle width is unlimited */
+static RECT BUTTON_GetTextRect(const BUTTON_INFO *infoPtr, HDC hdc, const WCHAR *text, LONG maxWidth)
+{
+ LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
+ LONG exStyle = GetWindowLongW(infoPtr->hwnd, GWL_EXSTYLE);
+ UINT dtStyle = BUTTON_BStoDT(style, exStyle);
+ HFONT hPrevFont;
+ RECT rect = {0};
+
+ rect.right = maxWidth;
+ hPrevFont = SelectObject(hdc, infoPtr->font);
+ /* Calculate height without DT_VCENTER and DT_BOTTOM to get the correct height */
+ DrawTextW(hdc, text, -1, &rect, (dtStyle & ~(DT_VCENTER | DT_BOTTOM)) | DT_CALCRECT);
+ if (hPrevFont) SelectObject(hdc, hPrevFont);
+
+ return rect;
+}
+
+static BOOL show_image_only(const BUTTON_INFO *infoPtr)
+{
+ LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
+ return (style & (BS_ICON | BS_BITMAP)) && infoPtr->u.image;
+}
+
+static BOOL show_image_and_text(const BUTTON_INFO *infoPtr)
+{
+ LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
+ UINT type = get_button_type(style);
+ return !(style & (BS_ICON | BS_BITMAP)) && infoPtr->u.image
+ && (type == BS_PUSHBUTTON || type == BS_DEFPUSHBUTTON || type == BS_USERBUTTON || type == BS_SPLITBUTTON
+ || type == BS_DEFSPLITBUTTON || type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK);
+}
+
+static BOOL show_image(const BUTTON_INFO *infoPtr)
+{
+ return show_image_only(infoPtr) || show_image_and_text(infoPtr);
+}
+
+/* Get a bounding rectangle that is large enough to contain a image and a text side by side.
+ * Note: (left,top) of the result rectangle may not be (0,0), offset it by yourself if needed */
+static RECT BUTTON_GetBoundingLabelRect(LONG style, const RECT *textRect, const RECT *imageRect)
+{
+ RECT labelRect;
+ RECT rect = *imageRect;
+ INT textWidth = textRect->right - textRect->left;
+ INT textHeight = textRect->bottom - textRect->top;
+ INT imageWidth = imageRect->right - imageRect->left;
+ INT imageHeight = imageRect->bottom - imageRect->top;
+
+ if ((style & BS_CENTER) == BS_RIGHT)
+ OffsetRect(&rect, textWidth, 0);
+ else if ((style & BS_CENTER) == BS_LEFT)
+ OffsetRect(&rect, -imageWidth, 0);
+ else if ((style & BS_VCENTER) == BS_BOTTOM)
+ OffsetRect(&rect, 0, textHeight);
+ else if ((style & BS_VCENTER) == BS_TOP)
+ OffsetRect(&rect, 0, -imageHeight);
+ else
+ OffsetRect(&rect, -imageWidth, 0);
+
+ UnionRect(&labelRect, textRect, &rect);
+ return labelRect;
+}
+
+/* Position a rectangle inside a bounding rectangle according to button alignment flags */
+static void BUTTON_PositionRect(LONG style, const RECT *outerRect, RECT *innerRect, const RECT *margin)
+{
+ INT width = innerRect->right - innerRect->left;
+ INT height = innerRect->bottom - innerRect->top;
+
+ if ((style & WS_EX_RIGHT) && !(style & BS_CENTER)) style |= BS_CENTER;
+
+ if (!(style & BS_CENTER))
+ {
+ /* Push button's text is centered by default, all other types have left aligned text */
+ if (get_button_type(style) <= BS_DEFPUSHBUTTON)
+ style |= BS_CENTER;
+ else
+ style |= BS_LEFT;
+ }
+
+ if (!(style & BS_VCENTER))
+ {
+ /* Group box's text is top aligned by default */
+ if (get_button_type(style) == BS_GROUPBOX)
+ style |= BS_TOP;
+ }
+
+ switch (style & BS_CENTER)
+ {
+ case BS_CENTER:
+ innerRect->left = outerRect->left + (outerRect->right - outerRect->left - width) / 2;
+ innerRect->right = innerRect->left + width;
+ break;
+ case BS_RIGHT:
+ innerRect->right = outerRect->right - margin->right;
+ innerRect->left = innerRect->right - width;
+ break;
+ case BS_LEFT:
+ default:
+ innerRect->left = outerRect->left + margin->left;
+ innerRect->right = innerRect->left + width;
+ break;
+ }
+
+ switch (style & BS_VCENTER)
+ {
+ case BS_TOP:
+ innerRect->top = outerRect->top + margin->top;
+ innerRect->bottom = innerRect->top + height;
+ break;
+ case BS_BOTTOM:
+ innerRect->bottom = outerRect->bottom - margin->bottom;
+ innerRect->top = innerRect->bottom - height;
+ break;
+ case BS_VCENTER:
+ default:
+ innerRect->top = outerRect->top + (outerRect->bottom - outerRect->top - height) / 2;
+ innerRect->bottom = innerRect->top + height;
+ break;
+ }
+}
+
+static SIZE BUTTON_GetImageSize(const BUTTON_INFO *infoPtr)
+{
+ ICONINFO iconInfo;
+ BITMAP bm = {0};
+ SIZE size = {0};
+
+ if (infoPtr->u.image)
+ {
+ if (infoPtr->image_type == IMAGE_ICON)
+ {
+ GetIconInfo(infoPtr->u.icon, &iconInfo);
+ GetObjectW(iconInfo.hbmColor, sizeof(bm), &bm);
+ DeleteObject(iconInfo.hbmColor);
+ DeleteObject(iconInfo.hbmMask);
+ }
+ else if (infoPtr->image_type == IMAGE_BITMAP)
+ GetObjectW(infoPtr->u.bitmap, sizeof(bm), &bm);
+
+ size.cx = bm.bmWidth;
+ size.cy = bm.bmHeight;
+ }
+
+ return size;
+}
+
/**********************************************************************
- * BUTTON_CalcLabelRect
+ * BUTTON_CalcLayoutRects
*
- * Calculates label's rectangle depending on button style.
+ * Calculates the rectangles of the button label(image and text) and its parts depending on a button's style.
*
* Returns flags to be passed to DrawText.
* Calculated rectangle doesn't take into account button state
* (pushed, etc.). If there is nothing to draw (no text/image) output
* rectangle is empty, and return value is (UINT)-1.
+ *
+ * PARAMS:
+ * infoPtr [I] Button pointer
+ * hdc [I] Handle to device context to draw to
+ * labelRc [I/O] Input the rect the label to be positioned in, and output the label rect
+ * imageRc [O] Optional, output the image rect
+ * textRc [O] Optional, output the text rect
*/
-static UINT BUTTON_CalcLabelRect(const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc)
+static UINT BUTTON_CalcLayoutRects(const BUTTON_INFO *infoPtr, HDC hdc, RECT *labelRc, RECT *imageRc, RECT *textRc)
{
LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
LONG ex_style = GetWindowLongW( infoPtr->hwnd, GWL_EXSTYLE );
WCHAR *text = get_button_text(infoPtr);
- ICONINFO iconInfo;
- BITMAP bm = { 0 };
- UINT dtStyle = BUTTON_BStoDT( style, ex_style );
- RECT r = *rc;
- INT n;
+ SIZE imageSize = BUTTON_GetImageSize(infoPtr);
+ UINT dtStyle = BUTTON_BStoDT(style, ex_style);
+ RECT labelRect, imageRect, textRect;
+ RECT emptyMargin = {0}, oneMargin = {1, 1, 1, 1};
+ LONG maxTextWidth;
/* Calculate label rectangle according to label type */
- /* FIXME: Doesn't support showing both image and text yet */
- if (infoPtr->u.image)
- {
- if (infoPtr->image_type == IMAGE_ICON)
- {
- GetIconInfo(infoPtr->u.icon, &iconInfo);
- GetObjectW(iconInfo.hbmColor, sizeof(bm), &bm);
- DeleteObject(iconInfo.hbmColor);
- DeleteObject(iconInfo.hbmMask);
- }
- else if (infoPtr->image_type == IMAGE_BITMAP)
- {
- GetObjectW(infoPtr->u.bitmap, sizeof(bm), &bm);
- }
-
- r.right = r.left + bm.bmWidth;
- r.bottom = r.top + bm.bmHeight;
- }
- else if (text && text[0])
+ if ((imageSize.cx == 0 && imageSize.cy == 0) && (text == NULL || text[0] == '\0'))
{
- HFONT hFont, hPrevFont = 0;
-
- if ((hFont = infoPtr->font)) hPrevFont = SelectObject(hdc, hFont);
- DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT);
- if (hPrevFont) SelectObject(hdc, hPrevFont);
- }
-
- if ((infoPtr->u.image && bm.bmWidth == 0 && bm.bmHeight == 0)
- || (text == NULL || text[0] == '\0'))
- {
- rc->right = r.left;
- rc->bottom = r.top;
+ SetRectEmpty(labelRc);
+ SetRectEmpty(imageRc);
+ SetRectEmpty(textRc);
heap_free(text);
return (UINT)-1;
}
- heap_free(text);
- /* Position label inside bounding rectangle according to
- * alignment flags. (calculated rect is always left-top aligned).
- * If label is aligned to any side - shift label in opposite
- * direction to leave extra space for focus rectangle.
- */
- switch (dtStyle & (DT_CENTER|DT_RIGHT))
+ SetRect(&imageRect, 0, 0, imageSize.cx, imageSize.cy);
+
+ /* Show image only */
+ if (show_image_only(infoPtr))
{
- case DT_LEFT: r.left++; r.right++; break;
- case DT_CENTER: n = r.right - r.left;
- r.left = rc->left + ((rc->right - rc->left) - n) / 2;
- r.right = r.left + n; break;
- case DT_RIGHT: n = r.right - r.left;
- r.right = rc->right - 1;
- r.left = r.right - n;
- break;
+ BUTTON_PositionRect(style, labelRc, &imageRect,
+ infoPtr->imagelist.himl ? &infoPtr->imagelist.margin : &emptyMargin);
+ labelRect = imageRect;
+ SetRectEmpty(&textRect);
}
-
- switch (dtStyle & (DT_VCENTER|DT_BOTTOM))
+ else
{
- case DT_TOP: r.top++; r.bottom++; break;
- case DT_VCENTER: n = r.bottom - r.top;
- r.top = rc->top + ((rc->bottom - rc->top) - n) / 2;
- r.bottom = r.top + n; break;
- case DT_BOTTOM: n = r.bottom - r.top;
- r.bottom = rc->bottom - 1;
- r.top = r.bottom - n;
- break;
+ /* Get text rect */
+ maxTextWidth = labelRc->right - labelRc->left;
+ textRect = BUTTON_GetTextRect(infoPtr, hdc, text, maxTextWidth);
+ heap_free(text);
+
+ /* Show image and text */
+ if (show_image_and_text(infoPtr))
+ {
+ RECT boundingLabelRect, boundingImageRect, boundingTextRect;
+
+ /* Get label rect */
+ /* Get a label bounding rect to position the label in the user specified label rect because text and
+ * image need to align together. */
+ boundingLabelRect = BUTTON_GetBoundingLabelRect(style, &textRect, &imageRect);
+ BUTTON_PositionRect(style, labelRc, &boundingLabelRect, &emptyMargin);
+ labelRect = boundingLabelRect;
+
+ /* Get image rect */
+ /* Split the label rect to two halves as two bounding rects for image and text */
+ boundingImageRect = labelRect;
+ if ((style & BS_CENTER) == BS_RIGHT)
+ boundingImageRect.left = boundingImageRect.right - imageSize.cx;
+ else if ((style & BS_CENTER) == BS_LEFT)
+ boundingImageRect.right = boundingImageRect.left + imageSize.cx;
+ else if ((style & BS_VCENTER) == BS_BOTTOM)
+ boundingImageRect.top = boundingImageRect.bottom - imageSize.cy;
+ else if ((style & BS_VCENTER) == BS_TOP)
+ boundingImageRect.bottom = boundingImageRect.top + imageSize.cy;
+ else
+ boundingImageRect.right = boundingImageRect.left + imageSize.cx;
+ BUTTON_PositionRect(style, &boundingImageRect, &imageRect, &emptyMargin);
+
+ /* Get text rect */
+ SubtractRect(&boundingTextRect, &labelRect, &boundingImageRect);
+ BUTTON_PositionRect(style, &boundingTextRect, &textRect, &oneMargin);
+ }
+ /* Show text only */
+ else
+ {
+ if (get_button_type(style) != BS_GROUPBOX)
+ BUTTON_PositionRect(style, labelRc, &textRect, &oneMargin);
+ else
+ /* GroupBox is always top aligned */
+ BUTTON_PositionRect((style & ~BS_VCENTER) | BS_TOP, labelRc, &textRect, &oneMargin);
+ labelRect = textRect;
+ SetRectEmpty(&imageRect);
+ }
}
- *rc = r;
+ CopyRect(labelRc, &labelRect);
+ CopyRect(imageRc, &imageRect);
+ CopyRect(textRc, &textRect);
+
return dtStyle;
}
@@ -962,19 +1124,25 @@ static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int
return TRUE;
}
-
/**********************************************************************
* BUTTON_DrawLabel
*
* Common function for drawing button label.
+ *
+ * FIXME:
+ * 1. When BS_SINGLELINE is specified and text contains '\t', '\n' or '\r' in the middle, they are rendered as
+ * squares now whereas they should be ignored.
+ * 2. When BS_MULTILINE is specified and text contains space in the middle, the space mistakenly be rendered as newline.
*/
-static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, const RECT *rc)
+static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, const RECT *imageRect,
+ const RECT *textRect)
{
DRAWSTATEPROC lpOutputProc = NULL;
LPARAM lp;
WPARAM wp = 0;
HBRUSH hbr = 0;
UINT flags = IsWindowEnabled(infoPtr->hwnd) ? DSS_NORMAL : DSS_DISABLED;
+ UINT imageFlags;
LONG state = infoPtr->state;
LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
WCHAR *text = NULL;
@@ -990,35 +1158,34 @@ static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags,
flags |= DSS_MONO;
}
- /* FIXME: Support drawing label with both image and text */
- if (infoPtr->u.image != 0)
+ switch (infoPtr->image_type)
{
- switch (infoPtr->image_type)
- {
- case IMAGE_ICON:
- flags |= DST_ICON;
- lp = (LPARAM)infoPtr->u.icon;
- break;
- case IMAGE_BITMAP:
- flags |= DST_BITMAP;
- lp = (LPARAM)infoPtr->u.bitmap;
- break;
- default:
- return;
- }
- }
- else
- {
- /* DST_COMPLEX -- is 0 */
- lpOutputProc = BUTTON_DrawTextCallback;
- if (!(text = get_button_text(infoPtr))) return;
- lp = (LPARAM)text;
- wp = dtFlags;
+ case IMAGE_ICON:
+ imageFlags = flags | DST_ICON;
+ lp = (LPARAM)infoPtr->u.icon;
+ break;
+ case IMAGE_BITMAP:
+ imageFlags = flags | DST_BITMAP;
+ lp = (LPARAM)infoPtr->u.bitmap;
+ break;
+ default:
+ return;
}
- DrawStateW(hdc, hbr, lpOutputProc, lp, wp, rc->left, rc->top,
- rc->right - rc->left, rc->bottom - rc->top, flags);
- heap_free( text );
+ if (show_image(infoPtr))
+ DrawStateW(hdc, hbr, lpOutputProc, lp, wp, imageRect->left, imageRect->top,
+ imageRect->right - imageRect->left, imageRect->bottom - imageRect->top, imageFlags);
+
+ if (show_image_only(infoPtr)) return;
+
+ /* DST_COMPLEX -- is 0 */
+ lpOutputProc = BUTTON_DrawTextCallback;
+ if (!(text = get_button_text(infoPtr))) return;
+ lp = (LPARAM)text;
+ wp = dtFlags;
+ DrawStateW(hdc, hbr, lpOutputProc, lp, wp, textRect->left, textRect->top, textRect->right - textRect->left,
+ textRect->bottom - textRect->top, flags);
+ heap_free(text);
}
/**********************************************************************
@@ -1026,7 +1193,7 @@ static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags,
*/
static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
- RECT rc, r;
+ RECT rc, labelRect, imageRect, textRect;
UINT dtFlags, uState;
HPEN hOldPen, hpen;
HBRUSH hOldBrush;
@@ -1082,18 +1249,17 @@ static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
DrawFrameControl( hDC, &rc, DFC_BUTTON, uState );
/* draw button label */
- r = rc;
- dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &r);
+ labelRect = rc;
+ dtFlags = BUTTON_CalcLayoutRects(infoPtr, hDC, &labelRect, &imageRect, &textRect);
if (dtFlags == (UINT)-1L)
goto cleanup;
- if (pushedState)
- OffsetRect(&r, 1, 1);
+ if (pushedState) OffsetRect(&labelRect, 1, 1);
oldTxtColor = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
- BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &r);
+ BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &imageRect, &textRect);
SetTextColor( hDC, oldTxtColor );
@@ -1119,7 +1285,7 @@ draw_focus:
static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
- RECT rbox, rtext, client;
+ RECT rbox, labelRect, imageRect, textRect, client;
HBRUSH hBrush;
int delta, text_offset, checkBoxWidth, checkBoxHeight;
UINT dtFlags;
@@ -1137,7 +1303,7 @@ static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
}
GetClientRect(infoPtr->hwnd, &client);
- rbox = rtext = client;
+ rbox = labelRect = client;
checkBoxWidth = 12 * GetDpiForWindow( infoPtr->hwnd ) / 96 + 1;
checkBoxHeight = 12 * GetDpiForWindow( infoPtr->hwnd ) / 96 + 1;
@@ -1155,12 +1321,12 @@ static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
if (style & BS_LEFTTEXT || ex_style & WS_EX_RIGHT)
{
- rtext.right -= checkBoxWidth + text_offset;
+ labelRect.right -= checkBoxWidth + text_offset;
rbox.left = rbox.right - checkBoxWidth;
}
else
{
- rtext.left += checkBoxWidth + text_offset;
+ labelRect.left += checkBoxWidth + text_offset;
rbox.right = checkBoxWidth;
}
@@ -1169,14 +1335,14 @@ static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
if (action == ODA_DRAWENTIRE) FillRect( hDC, &client, hBrush );
/* Draw label */
- client = rtext;
- dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &rtext);
+ client = labelRect;
+ dtFlags = BUTTON_CalcLayoutRects(infoPtr, hDC, &labelRect, &imageRect, &textRect);
/* Only adjust rbox when rtext is valid */
if (dtFlags != (UINT)-1L)
{
- rbox.top = rtext.top;
- rbox.bottom = rtext.bottom;
+ rbox.top = labelRect.top;
+ rbox.bottom = labelRect.bottom;
}
/* Draw the check-box bitmap */
@@ -1229,16 +1395,15 @@ static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
if (dtFlags == (UINT)-1L) /* Noting to draw */
return;
- if (action == ODA_DRAWENTIRE)
- BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &rtext);
+ if (action == ODA_DRAWENTIRE) BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &imageRect, &textRect);
/* ... and focus */
if (action == ODA_FOCUS || (state & BST_FOCUS))
{
- rtext.left--;
- rtext.right++;
- IntersectRect(&rtext, &rtext, &client);
- DrawFocusRect( hDC, &rtext );
+ labelRect.left--;
+ labelRect.right++;
+ IntersectRect(&labelRect, &labelRect, &client);
+ DrawFocusRect(hDC, &labelRect);
}
SelectClipRgn( hDC, hrgn );
if (hrgn) DeleteObject( hrgn );
@@ -1274,7 +1439,7 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd )
static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
- RECT rc, rcFrame;
+ RECT labelRect, imageRect, textRect, rcFrame;
HBRUSH hbr;
HFONT hFont;
UINT dtFlags;
@@ -1290,16 +1455,16 @@ static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
hbr = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
if (!hbr) /* did the app forget to call defwindowproc ? */
hbr = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
- GetClientRect( infoPtr->hwnd, &rc);
- rcFrame = rc;
- hrgn = set_control_clipping( hDC, &rc );
+ GetClientRect(infoPtr->hwnd, &labelRect);
+ rcFrame = labelRect;
+ hrgn = set_control_clipping(hDC, &labelRect);
GetTextMetricsW (hDC, &tm);
rcFrame.top += (tm.tmHeight / 2) - 1;
DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT | ((style & BS_FLAT) ? BF_FLAT : 0));
- InflateRect(&rc, -7, 1);
- dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &rc);
+ InflateRect(&labelRect, -7, 1);
+ dtFlags = BUTTON_CalcLayoutRects(infoPtr, hDC, &labelRect, &imageRect, &textRect);
if (dtFlags != (UINT)-1)
{
@@ -1309,11 +1474,15 @@ static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
*/
/* There is 1-pixel margin at the left, right, and bottom */
- rc.left--; rc.right++; rc.bottom++;
- FillRect(hDC, &rc, hbr);
- rc.left++; rc.right--; rc.bottom--;
-
- BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &rc);
+ labelRect.left--;
+ labelRect.right++;
+ labelRect.bottom++;
+ FillRect(hDC, &labelRect, hbr);
+ labelRect.left++;
+ labelRect.right--;
+ labelRect.bottom--;
+
+ BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &imageRect, &textRect);
}
SelectClipRgn( hDC, hrgn );
if (hrgn) DeleteObject( hrgn );
--
2.18.0
2
1
Use a helper so that the get draw state routine can be shared
by later code.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/button.c | 118 +++++++++++++++++++++++++----------------
1 file changed, 71 insertions(+), 47 deletions(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c
index 56968f99e3..6f9bc39de5 100644
--- a/dlls/comctl32/button.c
+++ b/dlls/comctl32/button.c
@@ -128,15 +128,16 @@ static const WORD maxCheckState[MAX_BTN_TYPE] =
BST_UNCHECKED /* BS_DEFCOMMANDLINK */
};
-/* These are indices into a states array to determine the theme state for a given theme part. */
-typedef enum
+/* Generic draw states, use get_draw_state() to get specific state for button type */
+enum draw_state
{
STATE_NORMAL,
STATE_DISABLED,
STATE_HOT,
STATE_PRESSED,
- STATE_DEFAULTED
-} ButtonState;
+ STATE_DEFAULTED,
+ DRAW_STATE_COUNT
+};
typedef void (*pfPaint)( const BUTTON_INFO *infoPtr, HDC hdc, UINT action );
@@ -160,11 +161,11 @@ static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
PB_Paint /* BS_DEFCOMMANDLINK */
};
-typedef void (*pfThemedPaint)( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
+typedef void (*pfThemedPaint)( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused);
-static void PB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
-static void CB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
-static void GB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
+static void PB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused);
+static void CB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused);
+static void GB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused);
static const pfThemedPaint btnThemedPaintFunc[MAX_BTN_TYPE] =
{
@@ -286,6 +287,63 @@ static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style )
return dtStyle;
}
+static int get_draw_state(const BUTTON_INFO *infoPtr)
+{
+ static const int pb_states[DRAW_STATE_COUNT] = { PBS_NORMAL, PBS_DISABLED, PBS_HOT, PBS_PRESSED, PBS_DEFAULTED };
+ static const int cb_states[3][DRAW_STATE_COUNT] =
+ {
+ { CBS_UNCHECKEDNORMAL, CBS_UNCHECKEDDISABLED, CBS_UNCHECKEDHOT, CBS_UNCHECKEDPRESSED, CBS_UNCHECKEDNORMAL },
+ { CBS_CHECKEDNORMAL, CBS_CHECKEDDISABLED, CBS_CHECKEDHOT, CBS_CHECKEDPRESSED, CBS_CHECKEDNORMAL },
+ { CBS_MIXEDNORMAL, CBS_MIXEDDISABLED, CBS_MIXEDHOT, CBS_MIXEDPRESSED, CBS_MIXEDNORMAL }
+ };
+ static const int rb_states[2][DRAW_STATE_COUNT] =
+ {
+ { RBS_UNCHECKEDNORMAL, RBS_UNCHECKEDDISABLED, RBS_UNCHECKEDHOT, RBS_UNCHECKEDPRESSED, RBS_UNCHECKEDNORMAL },
+ { RBS_CHECKEDNORMAL, RBS_CHECKEDDISABLED, RBS_CHECKEDHOT, RBS_CHECKEDPRESSED, RBS_CHECKEDNORMAL }
+ };
+ static const int gb_states[DRAW_STATE_COUNT] = { GBS_NORMAL, GBS_DISABLED, GBS_NORMAL, GBS_NORMAL, GBS_NORMAL };
+ LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
+ UINT type = get_button_type(style);
+ int check_state = infoPtr->state & 3;
+ enum draw_state state;
+
+ if (!IsWindowEnabled(infoPtr->hwnd))
+ state = STATE_DISABLED;
+ else if (infoPtr->state & BST_PUSHED)
+ state = STATE_PRESSED;
+ else if (infoPtr->state & BST_HOT)
+ state = STATE_HOT;
+ else if (infoPtr->state & BST_FOCUS)
+ state = STATE_DEFAULTED;
+ else
+ state = STATE_NORMAL;
+
+ switch (type)
+ {
+ case BS_PUSHBUTTON:
+ case BS_DEFPUSHBUTTON:
+ case BS_USERBUTTON:
+ case BS_SPLITBUTTON:
+ case BS_DEFSPLITBUTTON:
+ case BS_COMMANDLINK:
+ case BS_DEFCOMMANDLINK:
+ return pb_states[state];
+ case BS_CHECKBOX:
+ case BS_AUTOCHECKBOX:
+ return cb_states[check_state][state];
+ case BS_RADIOBUTTON:
+ case BS_3STATE:
+ case BS_AUTO3STATE:
+ case BS_AUTORADIOBUTTON:
+ return rb_states[check_state][state];
+ case BS_GROUPBOX:
+ return gb_states[state];
+ default:
+ WARN("Unsupported button type 0x%08x\n", type);
+ return PBS_NORMAL;
+ }
+}
+
static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BUTTON_INFO *infoPtr = (BUTTON_INFO *)GetWindowLongPtrW(hWnd, 0);
@@ -402,20 +460,9 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
if (theme && btnThemedPaintFunc[btn_type])
{
- ButtonState drawState;
- UINT dtflags;
+ int drawState = get_draw_state(infoPtr);
+ UINT dtflags = BUTTON_BStoDT(style, GetWindowLongW(hWnd, GWL_EXSTYLE));
- if (IsWindowEnabled( hWnd ))
- {
- if (infoPtr->state & BST_PUSHED) drawState = STATE_PRESSED;
- else if (infoPtr->state & BST_HOT) drawState = STATE_HOT;
- else if (infoPtr->state & BST_FOCUS) drawState = STATE_DEFAULTED;
- else drawState = STATE_NORMAL;
- }
- else
- drawState = STATE_DISABLED;
-
- dtflags = BUTTON_BStoDT(style, GetWindowLongW(hWnd, GWL_EXSTYLE));
btnThemedPaintFunc[btn_type](theme, infoPtr, hdc, drawState, dtflags, infoPtr->state & BST_FOCUS);
}
else if (btnPaintFunc[btn_type])
@@ -1352,14 +1399,11 @@ static void OB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
if (hrgn) DeleteObject( hrgn );
}
-static void PB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
+static void PB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, int state, UINT dtFlags, BOOL focused)
{
- static const int states[] = { PBS_NORMAL, PBS_DISABLED, PBS_HOT, PBS_PRESSED, PBS_DEFAULTED };
-
RECT bgRect, textRect;
HFONT font = infoPtr->font;
HFONT hPrevFont = font ? SelectObject(hDC, font) : NULL;
- int state = states[ drawState ];
WCHAR *text = get_button_text(infoPtr);
GetClientRect(infoPtr->hwnd, &bgRect);
@@ -1392,31 +1436,14 @@ static void PB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, Bu
if (hPrevFont) SelectObject(hDC, hPrevFont);
}
-static void CB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
+static void CB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, int state, UINT dtFlags, BOOL focused)
{
- static const int cb_states[3][5] =
- {
- { CBS_UNCHECKEDNORMAL, CBS_UNCHECKEDDISABLED, CBS_UNCHECKEDHOT, CBS_UNCHECKEDPRESSED, CBS_UNCHECKEDNORMAL },
- { CBS_CHECKEDNORMAL, CBS_CHECKEDDISABLED, CBS_CHECKEDHOT, CBS_CHECKEDPRESSED, CBS_CHECKEDNORMAL },
- { CBS_MIXEDNORMAL, CBS_MIXEDDISABLED, CBS_MIXEDHOT, CBS_MIXEDPRESSED, CBS_MIXEDNORMAL }
- };
-
- static const int rb_states[2][5] =
- {
- { RBS_UNCHECKEDNORMAL, RBS_UNCHECKEDDISABLED, RBS_UNCHECKEDHOT, RBS_UNCHECKEDPRESSED, RBS_UNCHECKEDNORMAL },
- { RBS_CHECKEDNORMAL, RBS_CHECKEDDISABLED, RBS_CHECKEDHOT, RBS_CHECKEDPRESSED, RBS_CHECKEDNORMAL }
- };
-
SIZE sz;
RECT bgRect, textRect;
HFONT font, hPrevFont = NULL;
- int checkState = infoPtr->state & 3;
DWORD dwStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
UINT btn_type = get_button_type( dwStyle );
int part = (btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON) ? BP_RADIOBUTTON : BP_CHECKBOX;
- int state = (part == BP_CHECKBOX)
- ? cb_states[ checkState ][ drawState ]
- : rb_states[ checkState ][ drawState ];
WCHAR *text = get_button_text(infoPtr);
LOGFONTW lf;
BOOL created_font = FALSE;
@@ -1478,12 +1505,9 @@ static void CB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, Bu
if (hPrevFont) SelectObject(hDC, hPrevFont);
}
-static void GB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
+static void GB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, int state, UINT dtFlags, BOOL focused)
{
- static const int states[] = { GBS_NORMAL, GBS_DISABLED, GBS_NORMAL, GBS_NORMAL, GBS_NORMAL };
-
RECT bgRect, textRect, contentRect;
- int state = states[ drawState ];
WCHAR *text = get_button_text(infoPtr);
LOGFONTW lf;
HFONT font, hPrevFont = NULL;
--
2.18.0
2
1
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/tests/button.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c
index b27ab844b7..1fd644b6f2 100644
--- a/dlls/comctl32/tests/button.c
+++ b/dlls/comctl32/tests/button.c
@@ -1406,6 +1406,22 @@ static void test_get_set_textmargin(void)
}
}
+static void test_state(void)
+{
+ HWND hwnd;
+ DWORD type;
+ LONG state;
+
+ /* Initial button state */
+ for (type = BS_PUSHBUTTON; type <= BS_DEFCOMMANDLINK; type++)
+ {
+ hwnd = create_button(type, NULL);
+ state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
+ ok(state == BST_UNCHECKED, "Expect state 0x%08x, got 0x%08x\n", BST_UNCHECKED, state);
+ DestroyWindow(hwnd);
+ }
+}
+
START_TEST(button)
{
ULONG_PTR ctx_cookie;
@@ -1426,6 +1442,7 @@ START_TEST(button)
test_bm_get_set_image();
test_get_set_imagelist();
test_get_set_textmargin();
+ test_state();
unload_v6_module(ctx_cookie, hCtx);
}
--
2.18.0
2
1
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/xmllite/reader.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/xmllite/reader.c b/dlls/xmllite/reader.c
index 9cb7f3bd77..f10c718d80 100644
--- a/dlls/xmllite/reader.c
+++ b/dlls/xmllite/reader.c
@@ -1019,9 +1019,9 @@ static void readerinput_switchencoding(xmlreaderinput *readerinput, xml_encoding
encoded_buffer *src = &readerinput->buffer->encoded;
encoded_buffer *dest = &readerinput->buffer->utf16;
int len, dest_len;
+ UINT cp = ~0u;
HRESULT hr;
WCHAR *ptr;
- UINT cp;
hr = get_code_page(enc, &cp);
if (FAILED(hr)) return;
--
2.18.0
1
0
05 Sep '18
From: Józef Kucia <jkucia(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
tests/d3d12.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 283 insertions(+)
diff --git a/tests/d3d12.c b/tests/d3d12.c
index 38e757a28748..34b4fdf101fb 100644
--- a/tests/d3d12.c
+++ b/tests/d3d12.c
@@ -18921,6 +18921,288 @@ static void test_clip_distance(void)
destroy_test_context(&context);
}
+static void test_combined_clip_and_cull_distances(void)
+{
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
+ ID3D12GraphicsCommandList *command_list;
+ D3D12_INPUT_LAYOUT_DESC input_layout;
+ D3D12_VERTEX_BUFFER_VIEW vbv[2];
+ struct test_context_desc desc;
+ struct test_context context;
+ struct resource_readback rb;
+ ID3D12CommandQueue *queue;
+ ID3D12Resource *vb[2];
+ ID3D12Device *device;
+ unsigned int i, j, k;
+ HRESULT hr;
+
+ static const DWORD vs_code[] =
+ {
+#if 0
+ struct input
+ {
+ float4 position : POSITION;
+ float clip0 : CLIP_DISTANCE0;
+ float clip1 : CLIP_DISTANCE1;
+ float clip2 : CLIP_DISTANCE2;
+ float clip3 : CLIP_DISTANCE3;
+ float cull0 : CULL_DISTANCE0;
+ float cull1 : CULL_DISTANCE1;
+ float cull2 : CULL_DISTANCE2;
+ float cull3 : CULL_DISTANCE3;
+ };
+
+ struct vertex
+ {
+ float4 position : SV_Position;
+ float3 clip0 : SV_ClipDistance1;
+ float3 cull0 : SV_CullDistance1;
+ float clip1 : SV_ClipDistance2;
+ float cull1 : SV_CullDistance2;
+ };
+
+ void main(input vin, out vertex vertex)
+ {
+ vertex.position = vin.position;
+ vertex.clip0 = float3(vin.clip0, vin.clip1, vin.clip2);
+ vertex.cull0 = float3(vin.cull0, vin.cull1, vin.cull2);
+ vertex.clip1 = vin.clip3;
+ vertex.cull1 = vin.cull3;
+ }
+#endif
+ 0x43425844, 0xa24fb3ea, 0x92e2c2b0, 0xb599b1b9, 0xd671f830, 0x00000001, 0x00000374, 0x00000003,
+ 0x0000002c, 0x0000013c, 0x000001f0, 0x4e475349, 0x00000108, 0x00000009, 0x00000008, 0x000000e0,
+ 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x000000e9, 0x00000000, 0x00000000,
+ 0x00000003, 0x00000001, 0x00000101, 0x000000e9, 0x00000001, 0x00000000, 0x00000003, 0x00000002,
+ 0x00000101, 0x000000e9, 0x00000002, 0x00000000, 0x00000003, 0x00000003, 0x00000101, 0x000000e9,
+ 0x00000003, 0x00000000, 0x00000003, 0x00000004, 0x00000101, 0x000000f7, 0x00000000, 0x00000000,
+ 0x00000003, 0x00000005, 0x00000101, 0x000000f7, 0x00000001, 0x00000000, 0x00000003, 0x00000006,
+ 0x00000101, 0x000000f7, 0x00000002, 0x00000000, 0x00000003, 0x00000007, 0x00000101, 0x000000f7,
+ 0x00000003, 0x00000000, 0x00000003, 0x00000008, 0x00000101, 0x49534f50, 0x4e4f4954, 0x494c4300,
+ 0x49445f50, 0x4e415453, 0x43004543, 0x5f4c4c55, 0x54534944, 0x45434e41, 0xababab00, 0x4e47534f,
+ 0x000000ac, 0x00000005, 0x00000008, 0x00000080, 0x00000000, 0x00000001, 0x00000003, 0x00000000,
+ 0x0000000f, 0x0000008c, 0x00000000, 0x00000002, 0x00000003, 0x00000001, 0x00000807, 0x0000008c,
+ 0x00000001, 0x00000002, 0x00000003, 0x00000001, 0x00000708, 0x0000009c, 0x00000000, 0x00000003,
+ 0x00000003, 0x00000002, 0x00000807, 0x0000009c, 0x00000001, 0x00000003, 0x00000003, 0x00000002,
+ 0x00000708, 0x505f5653, 0x7469736f, 0x006e6f69, 0x435f5653, 0x4470696c, 0x61747369, 0x0065636e,
+ 0x435f5653, 0x446c6c75, 0x61747369, 0x0065636e, 0x52444853, 0x0000017c, 0x00010040, 0x0000005f,
+ 0x0300005f, 0x001010f2, 0x00000000, 0x0300005f, 0x00101012, 0x00000001, 0x0300005f, 0x00101012,
+ 0x00000002, 0x0300005f, 0x00101012, 0x00000003, 0x0300005f, 0x00101012, 0x00000004, 0x0300005f,
+ 0x00101012, 0x00000005, 0x0300005f, 0x00101012, 0x00000006, 0x0300005f, 0x00101012, 0x00000007,
+ 0x0300005f, 0x00101012, 0x00000008, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x04000067,
+ 0x00102072, 0x00000001, 0x00000002, 0x04000067, 0x00102082, 0x00000001, 0x00000002, 0x04000067,
+ 0x00102072, 0x00000002, 0x00000003, 0x04000067, 0x00102082, 0x00000002, 0x00000003, 0x05000036,
+ 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x05000036, 0x00102012, 0x00000001, 0x0010100a,
+ 0x00000001, 0x05000036, 0x00102022, 0x00000001, 0x0010100a, 0x00000002, 0x05000036, 0x00102042,
+ 0x00000001, 0x0010100a, 0x00000003, 0x05000036, 0x00102082, 0x00000001, 0x0010100a, 0x00000004,
+ 0x05000036, 0x00102012, 0x00000002, 0x0010100a, 0x00000005, 0x05000036, 0x00102022, 0x00000002,
+ 0x0010100a, 0x00000006, 0x05000036, 0x00102042, 0x00000002, 0x0010100a, 0x00000007, 0x05000036,
+ 0x00102082, 0x00000002, 0x0010100a, 0x00000008, 0x0100003e,
+ };
+ static const D3D12_SHADER_BYTECODE vs = {vs_code, sizeof(vs_code)};
+ static const D3D12_INPUT_ELEMENT_DESC layout_desc[] =
+ {
+ {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CLIP_DISTANCE", 0, DXGI_FORMAT_R32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CLIP_DISTANCE", 1, DXGI_FORMAT_R32_FLOAT, 1, 4, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CLIP_DISTANCE", 2, DXGI_FORMAT_R32_FLOAT, 1, 8, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CLIP_DISTANCE", 3, DXGI_FORMAT_R32_FLOAT, 1, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CULL_DISTANCE", 0, DXGI_FORMAT_R32_FLOAT, 1, 16, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CULL_DISTANCE", 1, DXGI_FORMAT_R32_FLOAT, 1, 20, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CULL_DISTANCE", 2, DXGI_FORMAT_R32_FLOAT, 1, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CULL_DISTANCE", 3, DXGI_FORMAT_R32_FLOAT, 1, 28, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ };
+ static const struct vec4 quad[] =
+ {
+ {-1.0f, -1.0f},
+ {-1.0f, 1.0f},
+ { 1.0f, -1.0f},
+ { 1.0f, 1.0f},
+ };
+ struct
+ {
+ float clip_distance[4];
+ float cull_distance[4];
+ }
+ vertices[4] =
+ {
+ {{1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+ {{1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+ {{1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+ {{1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+ };
+ static const struct test
+ {
+ float vertices[4];
+ BOOL triangle_visible[2];
+ }
+ cull_distance_tests[] =
+ {
+ {{-1.0f, 1.0f, 1.0f, 1.0f}, {TRUE, TRUE}},
+ {{ 1.0f, -1.0f, 1.0f, 1.0f}, {TRUE, TRUE}},
+ {{ 1.0f, 1.0f, 1.0f, -1.0f}, {TRUE, TRUE}},
+ {{-1.0f, -1.0f, 1.0f, 1.0f}, {TRUE, TRUE}},
+ {{-1.0f, 1.0f, -1.0f, 1.0f}, {TRUE, TRUE}},
+ {{-1.0f, 1.0f, 1.0f, -1.0f}, {TRUE, TRUE}},
+ {{ 1.0f, -1.0f, -1.0f, 1.0f}, {TRUE, TRUE}},
+ {{ 1.0f, -1.0f, 1.0f, -1.0f}, {TRUE, TRUE}},
+ {{ 1.0f, 1.0f, -1.0f, -1.0f}, {TRUE, TRUE}},
+
+ {{-1.0f, -1.0f, -1.0f, 1.0f}, {FALSE, TRUE}},
+ {{-1.0f, -1.0f, 1.0f, -1.0f}, {TRUE, TRUE}},
+ {{-1.0f, -1.0f, 1.0f, -1.0f}, {TRUE, TRUE}},
+ {{-1.0f, 1.0f, -1.0f, -1.0f}, {TRUE, TRUE}},
+ {{ 1.0f, -1.0f, -1.0f, -1.0f}, {TRUE, FALSE}},
+
+ {{-1.0f, -1.0f, -1.0f, -1.0f}, {FALSE, FALSE}},
+ };
+ static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ memset(&desc, 0, sizeof(desc));
+ desc.rt_width = 640;
+ desc.rt_height = 480;
+ desc.root_signature_flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+ desc.no_pipeline = true;
+ if (!init_test_context(&context, &desc))
+ return;
+ device = context.device;
+ command_list = context.list;
+ queue = context.queue;
+
+ input_layout.pInputElementDescs = layout_desc;
+ input_layout.NumElements = ARRAY_SIZE(layout_desc);
+
+ init_pipeline_state_desc(&pso_desc, context.root_signature,
+ context.render_target_desc.Format, &vs, NULL, &input_layout);
+ hr = ID3D12Device_CreateGraphicsPipelineState(device, &pso_desc,
+ &IID_ID3D12PipelineState, (void **)&context.pipeline_state);
+ ok(hr == S_OK, "Failed to create pipeline state, hr %#x.\n", hr);
+
+ vb[0] = create_upload_buffer(device, sizeof(quad), quad);
+ vbv[0].BufferLocation = ID3D12Resource_GetGPUVirtualAddress(vb[0]);
+ vbv[0].StrideInBytes = sizeof(*quad);
+ vbv[0].SizeInBytes = sizeof(quad);
+
+ vb[1] = create_upload_buffer(device, sizeof(vertices), vertices);
+ vbv[1].BufferLocation = ID3D12Resource_GetGPUVirtualAddress(vb[1]);
+ vbv[1].StrideInBytes = sizeof(*vertices);
+ vbv[1].SizeInBytes = sizeof(vertices);
+
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0);
+
+ reset_command_list(command_list, context.allocator);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ for (i = 0; i < ARRAY_SIZE(vertices->cull_distance); ++i)
+ {
+ for (j = 0; j < ARRAY_SIZE(cull_distance_tests); ++j)
+ {
+ const struct test *test = &cull_distance_tests[j];
+ unsigned int expected_color[ARRAY_SIZE(test->triangle_visible)];
+ unsigned int color;
+
+ for (k = 0; k < ARRAY_SIZE(vertices); ++k)
+ vertices[k].cull_distance[i] = test->vertices[k];
+ update_buffer_data(vb[1], 0, sizeof(vertices), vertices);
+
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+
+ for (k = 0; k < ARRAY_SIZE(expected_color); ++k)
+ expected_color[k] = test->triangle_visible[k] ? 0xff00ff00 : 0xffffffff;
+
+ if (expected_color[0] == expected_color[1])
+ {
+ check_sub_resource_uint(context.render_target, 0, queue, command_list, expected_color[0], 0);
+ }
+ else
+ {
+ get_texture_readback_with_command_list(context.render_target, 0, &rb, queue, command_list);
+ color = get_readback_uint(&rb, 160, 240, 0);
+ ok(color == expected_color[0], "Got unexpected color 0x%08x.\n", color);
+ color = get_readback_uint(&rb, 480, 240, 0);
+ ok(color == expected_color[1], "Got unexpected color 0x%08x.\n", color);
+ release_resource_readback(&rb);
+ }
+
+ reset_command_list(command_list, context.allocator);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+ }
+
+ for (j = 0; j < ARRAY_SIZE(vertices); ++j)
+ vertices[j].cull_distance[i] = 1.0f;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(vertices->clip_distance); ++i)
+ {
+ for (j = 0; j < ARRAY_SIZE(vertices); ++j)
+ vertices[j].clip_distance[i] = -1.0f;
+ update_buffer_data(vb[1], 0, sizeof(vertices), vertices);
+
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+
+ check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xffffffff, 0);
+
+ reset_command_list(command_list, context.allocator);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ for (j = 0; j < ARRAY_SIZE(vertices); ++j)
+ vertices[j].clip_distance[i] = 1.0f;
+ }
+
+ memset(vertices, 0, sizeof(vertices));
+ update_buffer_data(vb[1], 0, sizeof(vertices), vertices);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0);
+
+ for (i = 0; i < ARRAY_SIZE(vb); ++i)
+ ID3D12Resource_Release(vb[i]);
+ destroy_test_context(&context);
+}
+
START_TEST(d3d12)
{
bool enable_debug_layer = false;
@@ -19036,4 +19318,5 @@ START_TEST(d3d12)
run_test(test_render_a8);
run_test(test_cpu_descriptors_lifetime);
run_test(test_clip_distance);
+ run_test(test_combined_clip_and_cull_distances);
}
--
2.16.4
2
1
From: Józef Kucia <jkucia(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
tests/d3d12.c | 577 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 577 insertions(+)
diff --git a/tests/d3d12.c b/tests/d3d12.c
index 1c6b65fa758a..38e757a28748 100644
--- a/tests/d3d12.c
+++ b/tests/d3d12.c
@@ -18345,6 +18345,582 @@ static void test_cpu_descriptors_lifetime(void)
destroy_test_context(&context);
}
+static void check_clip_distance(struct test_context *context,
+ ID3D12PipelineState *pso, D3D12_VERTEX_BUFFER_VIEW vbv[2], ID3D12Resource *vb,
+ ID3D12Resource *vs_cb, ID3D12Resource *gs_cb)
+{
+ static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ struct vertex
+ {
+ float clip_distance0;
+ float clip_distance1;
+ };
+
+ ID3D12GraphicsCommandList *command_list = context->list;
+ ID3D12CommandQueue *queue = context->queue;
+ struct resource_readback rb;
+ struct vertex vertices[4];
+ unsigned int i;
+ D3D12_BOX box;
+
+ for (i = 0; i < ARRAY_SIZE(vertices); ++i)
+ vertices[i].clip_distance0 = 1.0f;
+ update_buffer_data(vb, 0, sizeof(vertices), vertices);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context->rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context->root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context->viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context->scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 2, vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context->rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context->render_target, 0, queue, command_list, 0xff00ff00, 0);
+
+ reset_command_list(command_list, context->allocator);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ for (i = 0; i < ARRAY_SIZE(vertices); ++i)
+ vertices[i].clip_distance0 = 0.0f;
+ update_buffer_data(vb, 0, sizeof(vertices), vertices);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context->rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context->root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context->viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context->scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 2, vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context->rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context->render_target, 0, queue, command_list, 0xff00ff00, 0);
+
+ reset_command_list(command_list, context->allocator);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ for (i = 0; i < ARRAY_SIZE(vertices); ++i)
+ vertices[i].clip_distance0 = -1.0f;
+ update_buffer_data(vb, 0, sizeof(vertices), vertices);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context->rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context->root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context->viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context->scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 2, vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context->rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context->render_target, 0, queue, command_list, 0xffffffff, 0);
+
+ reset_command_list(command_list, context->allocator);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ for (i = 0; i < ARRAY_SIZE(vertices); ++i)
+ vertices[i].clip_distance0 = i < 2 ? 1.0f : -1.0f;
+ update_buffer_data(vb, 0, sizeof(vertices), vertices);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context->rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context->root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context->viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context->scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 2, vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context->rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ get_texture_readback_with_command_list(context->render_target, 0, &rb, queue, command_list);
+ set_box(&box, 0, 0, 0, 320, 480, 1);
+ check_readback_data_uint(&rb, &box, 0xff00ff00, 1);
+ set_box(&box, 320, 0, 0, 320, 480, 1);
+ check_readback_data_uint(&rb, &box, 0xffffffff, 1);
+ release_resource_readback(&rb);
+
+ reset_command_list(command_list, context->allocator);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ for (i = 0; i < ARRAY_SIZE(vertices); ++i)
+ vertices[i].clip_distance0 = i % 2 ? 1.0f : -1.0f;
+ update_buffer_data(vb, 0, sizeof(vertices), vertices);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context->rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context->root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context->viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context->scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 2, vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context->rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ get_texture_readback_with_command_list(context->render_target, 0, &rb, queue, command_list);
+ set_box(&box, 0, 0, 0, 640, 240, 1);
+ check_readback_data_uint(&rb, &box, 0xff00ff00, 0);
+ set_box(&box, 0, 240, 0, 640, 240, 1);
+ check_readback_data_uint(&rb, &box, 0xffffffff, 0);
+ release_resource_readback(&rb);
+
+ reset_command_list(command_list, context->allocator);
+ transition_resource_state(command_list, context->render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+}
+
+static void test_clip_distance(void)
+{
+ D3D12_ROOT_SIGNATURE_DESC root_signature_desc;
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
+ D3D12_ROOT_PARAMETER root_parameters[3];
+ ID3D12GraphicsCommandList *command_list;
+ ID3D12Resource *vs_cb, *gs_cb, *vb[2];
+ D3D12_INPUT_LAYOUT_DESC input_layout;
+ D3D12_VERTEX_BUFFER_VIEW vbv[2];
+ struct test_context_desc desc;
+ struct resource_readback rb;
+ struct test_context context;
+ ID3D12CommandQueue *queue;
+ ID3D12PipelineState *pso;
+ ID3D12Device *device;
+ unsigned int i;
+ D3D12_BOX box;
+ HRESULT hr;
+
+ static const DWORD vs_code[] =
+ {
+#if 0
+ bool use_constant;
+ float clip_distance;
+
+ struct input
+ {
+ float4 position : POSITION;
+ float distance0 : CLIP_DISTANCE0;
+ float distance1 : CLIP_DISTANCE1;
+ };
+
+ struct vertex
+ {
+ float4 position : SV_POSITION;
+ float user_clip : CLIP_DISTANCE;
+ float clip : SV_ClipDistance;
+ };
+
+ void main(input vin, out vertex vertex)
+ {
+ vertex.position = vin.position;
+ vertex.user_clip = vin.distance0;
+ vertex.clip = vin.distance0;
+ if (use_constant)
+ vertex.clip = clip_distance;
+ }
+#endif
+ 0x43425844, 0x09dfef58, 0x88570f2e, 0x1ebcf953, 0x9f97e22a, 0x00000001, 0x000001dc, 0x00000003,
+ 0x0000002c, 0x0000009c, 0x00000120, 0x4e475349, 0x00000068, 0x00000003, 0x00000008, 0x00000050,
+ 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x00000059, 0x00000000, 0x00000000,
+ 0x00000003, 0x00000001, 0x00000101, 0x00000059, 0x00000001, 0x00000000, 0x00000003, 0x00000002,
+ 0x00000001, 0x49534f50, 0x4e4f4954, 0x494c4300, 0x49445f50, 0x4e415453, 0xab004543, 0x4e47534f,
+ 0x0000007c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, 0x00000003, 0x00000000,
+ 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000e01, 0x0000006a,
+ 0x00000000, 0x00000002, 0x00000003, 0x00000002, 0x00000e01, 0x505f5653, 0x5449534f, 0x004e4f49,
+ 0x50494c43, 0x5349445f, 0x434e4154, 0x56530045, 0x696c435f, 0x73694470, 0x636e6174, 0xabab0065,
+ 0x52444853, 0x000000b4, 0x00010040, 0x0000002d, 0x04000059, 0x00208e46, 0x00000000, 0x00000001,
+ 0x0300005f, 0x001010f2, 0x00000000, 0x0300005f, 0x00101012, 0x00000001, 0x04000067, 0x001020f2,
+ 0x00000000, 0x00000001, 0x03000065, 0x00102012, 0x00000001, 0x04000067, 0x00102012, 0x00000002,
+ 0x00000002, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000000, 0x05000036, 0x00102012,
+ 0x00000001, 0x0010100a, 0x00000001, 0x0b000037, 0x00102012, 0x00000002, 0x0020800a, 0x00000000,
+ 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x0010100a, 0x00000001, 0x0100003e,
+ };
+ static const D3D12_SHADER_BYTECODE vs = {vs_code, sizeof(vs_code)};
+ static const DWORD vs_multiple_code[] =
+ {
+#if 0
+ bool use_constant;
+ float clip_distance0;
+ float clip_distance1;
+
+ struct input
+ {
+ float4 position : POSITION;
+ float distance0 : CLIP_DISTANCE0;
+ float distance1 : CLIP_DISTANCE1;
+ };
+
+ struct vertex
+ {
+ float4 position : SV_POSITION;
+ float user_clip : CLIP_DISTANCE;
+ float2 clip : SV_ClipDistance;
+ };
+
+ void main(input vin, out vertex vertex)
+ {
+ vertex.position = vin.position;
+ vertex.user_clip = vin.distance0;
+ vertex.clip.x = vin.distance0;
+ if (use_constant)
+ vertex.clip.x = clip_distance0;
+ vertex.clip.y = vin.distance1;
+ if (use_constant)
+ vertex.clip.y = clip_distance1;
+ }
+#endif
+ 0x43425844, 0xef5cc236, 0xe2fbfa69, 0x560b6591, 0x23037999, 0x00000001, 0x00000214, 0x00000003,
+ 0x0000002c, 0x0000009c, 0x00000120, 0x4e475349, 0x00000068, 0x00000003, 0x00000008, 0x00000050,
+ 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000f0f, 0x00000059, 0x00000000, 0x00000000,
+ 0x00000003, 0x00000001, 0x00000101, 0x00000059, 0x00000001, 0x00000000, 0x00000003, 0x00000002,
+ 0x00000101, 0x49534f50, 0x4e4f4954, 0x494c4300, 0x49445f50, 0x4e415453, 0xab004543, 0x4e47534f,
+ 0x0000007c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, 0x00000003, 0x00000000,
+ 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000e01, 0x0000006a,
+ 0x00000000, 0x00000002, 0x00000003, 0x00000002, 0x00000c03, 0x505f5653, 0x5449534f, 0x004e4f49,
+ 0x50494c43, 0x5349445f, 0x434e4154, 0x56530045, 0x696c435f, 0x73694470, 0x636e6174, 0xabab0065,
+ 0x52444853, 0x000000ec, 0x00010040, 0x0000003b, 0x04000059, 0x00208e46, 0x00000000, 0x00000001,
+ 0x0300005f, 0x001010f2, 0x00000000, 0x0300005f, 0x00101012, 0x00000001, 0x0300005f, 0x00101012,
+ 0x00000002, 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x00102012, 0x00000001,
+ 0x04000067, 0x00102032, 0x00000002, 0x00000002, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46,
+ 0x00000000, 0x05000036, 0x00102012, 0x00000001, 0x0010100a, 0x00000001, 0x0b000037, 0x00102012,
+ 0x00000002, 0x0020800a, 0x00000000, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x0010100a,
+ 0x00000001, 0x0b000037, 0x00102022, 0x00000002, 0x0020800a, 0x00000000, 0x00000000, 0x0020802a,
+ 0x00000000, 0x00000000, 0x0010100a, 0x00000002, 0x0100003e,
+ };
+ static const D3D12_SHADER_BYTECODE vs_multiple = {vs_multiple_code, sizeof(vs_multiple_code)};
+ static const DWORD gs_code[] =
+ {
+#if 0
+ bool use_constant;
+ float clip_distance;
+
+ struct vertex
+ {
+ float4 position : SV_POSITION;
+ float user_clip : CLIP_DISTANCE;
+ float clip : SV_ClipDistance;
+ };
+
+ [maxvertexcount(3)]
+ void main(triangle vertex input[3], inout TriangleStream<vertex> output)
+ {
+ vertex o;
+ o = input[0];
+ o.clip = input[0].user_clip;
+ if (use_constant)
+ o.clip = clip_distance;
+ output.Append(o);
+ o = input[1];
+ o.clip = input[1].user_clip;
+ if (use_constant)
+ o.clip = clip_distance;
+ output.Append(o);
+ o = input[2];
+ o.clip = input[2].user_clip;
+ if (use_constant)
+ o.clip = clip_distance;
+ output.Append(o);
+ }
+#endif
+ 0x43425844, 0x9b0823e9, 0xab3ed100, 0xba0ff618, 0x1bbd1cb8, 0x00000001, 0x00000338, 0x00000003,
+ 0x0000002c, 0x000000b0, 0x00000134, 0x4e475349, 0x0000007c, 0x00000003, 0x00000008, 0x00000050,
+ 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x00000f0f, 0x0000005c, 0x00000000, 0x00000000,
+ 0x00000003, 0x00000001, 0x00000101, 0x0000006a, 0x00000000, 0x00000002, 0x00000003, 0x00000002,
+ 0x00000001, 0x505f5653, 0x5449534f, 0x004e4f49, 0x50494c43, 0x5349445f, 0x434e4154, 0x56530045,
+ 0x696c435f, 0x73694470, 0x636e6174, 0xabab0065, 0x4e47534f, 0x0000007c, 0x00000003, 0x00000008,
+ 0x00000050, 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000,
+ 0x00000000, 0x00000003, 0x00000001, 0x00000e01, 0x0000006a, 0x00000000, 0x00000002, 0x00000003,
+ 0x00000002, 0x00000e01, 0x505f5653, 0x5449534f, 0x004e4f49, 0x50494c43, 0x5349445f, 0x434e4154,
+ 0x56530045, 0x696c435f, 0x73694470, 0x636e6174, 0xabab0065, 0x52444853, 0x000001fc, 0x00020040,
+ 0x0000007f, 0x04000059, 0x00208e46, 0x00000000, 0x00000001, 0x05000061, 0x002010f2, 0x00000003,
+ 0x00000000, 0x00000001, 0x0400005f, 0x00201012, 0x00000003, 0x00000001, 0x0400005f, 0x00201012,
+ 0x00000003, 0x00000002, 0x02000068, 0x00000001, 0x0100185d, 0x0100285c, 0x04000067, 0x001020f2,
+ 0x00000000, 0x00000001, 0x03000065, 0x00102012, 0x00000001, 0x04000067, 0x00102012, 0x00000002,
+ 0x00000002, 0x0200005e, 0x00000003, 0x06000036, 0x001020f2, 0x00000000, 0x00201e46, 0x00000000,
+ 0x00000000, 0x06000036, 0x00102012, 0x00000001, 0x0020100a, 0x00000000, 0x00000001, 0x0c000037,
+ 0x00100012, 0x00000000, 0x0020800a, 0x00000000, 0x00000000, 0x0020801a, 0x00000000, 0x00000000,
+ 0x0020100a, 0x00000000, 0x00000001, 0x05000036, 0x00102012, 0x00000002, 0x0010000a, 0x00000000,
+ 0x01000013, 0x06000036, 0x001020f2, 0x00000000, 0x00201e46, 0x00000001, 0x00000000, 0x06000036,
+ 0x00102012, 0x00000001, 0x0020100a, 0x00000001, 0x00000001, 0x0c000037, 0x00100012, 0x00000000,
+ 0x0020800a, 0x00000000, 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x0020100a, 0x00000001,
+ 0x00000001, 0x05000036, 0x00102012, 0x00000002, 0x0010000a, 0x00000000, 0x01000013, 0x06000036,
+ 0x001020f2, 0x00000000, 0x00201e46, 0x00000002, 0x00000000, 0x06000036, 0x00102012, 0x00000001,
+ 0x0020100a, 0x00000002, 0x00000001, 0x0c000037, 0x00100012, 0x00000000, 0x0020800a, 0x00000000,
+ 0x00000000, 0x0020801a, 0x00000000, 0x00000000, 0x0020100a, 0x00000002, 0x00000001, 0x05000036,
+ 0x00102012, 0x00000002, 0x0010000a, 0x00000000, 0x01000013, 0x0100003e,
+ };
+ static const D3D12_SHADER_BYTECODE gs = {gs_code, sizeof(gs_code)};
+ static const D3D12_INPUT_ELEMENT_DESC layout_desc[] =
+ {
+ {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CLIP_DISTANCE", 0, DXGI_FORMAT_R32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ {"CLIP_DISTANCE", 1, DXGI_FORMAT_R32_FLOAT, 1, 4, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
+ };
+ static const struct vec4 quad[] =
+ {
+ {-1.0f, -1.0f},
+ {-1.0f, 1.0f},
+ { 1.0f, -1.0f},
+ { 1.0f, 1.0f},
+ };
+ struct
+ {
+ float clip_distance0;
+ float clip_distance1;
+ }
+ vertices[] =
+ {
+ {1.0f, 1.0f},
+ {1.0f, 1.0f},
+ {1.0f, 1.0f},
+ {1.0f, 1.0f},
+ };
+ static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ struct
+ {
+ BOOL use_constant;
+ float clip_distance0;
+ float clip_distance1;
+ float padding;
+ } cb_data;
+
+ memset(&desc, 0, sizeof(desc));
+ desc.rt_width = 640;
+ desc.rt_height = 480;
+ desc.no_root_signature = true;
+ if (!init_test_context(&context, &desc))
+ return;
+ device = context.device;
+ command_list = context.list;
+ queue = context.queue;
+
+ root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+ root_parameters[0].Descriptor.ShaderRegister = 0;
+ root_parameters[0].Descriptor.RegisterSpace = 0;
+ root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+ root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+ root_parameters[1].Descriptor.ShaderRegister = 1;
+ root_parameters[1].Descriptor.RegisterSpace = 0;
+ root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ root_parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
+ root_parameters[2].Descriptor.ShaderRegister = 0;
+ root_parameters[2].Descriptor.RegisterSpace = 0;
+ root_parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_GEOMETRY;
+ root_signature_desc.NumParameters = ARRAY_SIZE(root_parameters);
+ root_signature_desc.pParameters = root_parameters;
+ root_signature_desc.NumStaticSamplers = 0;
+ root_signature_desc.pStaticSamplers = NULL;
+ root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+ hr = create_root_signature(device, &root_signature_desc, &context.root_signature);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ input_layout.pInputElementDescs = layout_desc;
+ input_layout.NumElements = ARRAY_SIZE(layout_desc);
+
+ init_pipeline_state_desc(&pso_desc, context.root_signature,
+ context.render_target_desc.Format, &vs, NULL, &input_layout);
+ hr = ID3D12Device_CreateGraphicsPipelineState(device, &pso_desc,
+ &IID_ID3D12PipelineState, (void **)&pso);
+ ok(hr == S_OK, "Failed to create pipeline state, hr %#x.\n", hr);
+
+ vb[0] = create_upload_buffer(device, sizeof(quad), quad);
+ vbv[0].BufferLocation = ID3D12Resource_GetGPUVirtualAddress(vb[0]);
+ vbv[0].StrideInBytes = sizeof(*quad);
+ vbv[0].SizeInBytes = sizeof(quad);
+
+ vb[1] = create_upload_buffer(device, sizeof(vertices), vertices);
+ vbv[1].BufferLocation = ID3D12Resource_GetGPUVirtualAddress(vb[1]);
+ vbv[1].StrideInBytes = sizeof(*vertices);
+ vbv[1].SizeInBytes = sizeof(vertices);
+
+ memset(&cb_data, 0, sizeof(cb_data));
+ vs_cb = create_upload_buffer(device, sizeof(cb_data), &cb_data);
+ gs_cb = create_upload_buffer(device, sizeof(cb_data), &cb_data);
+
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+
+ /* vertex shader */
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0);
+
+ reset_command_list(command_list, context.allocator);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+ check_clip_distance(&context, pso, vbv, vb[1], vs_cb, gs_cb);
+
+ cb_data.use_constant = TRUE;
+ cb_data.clip_distance0 = -1.0f;
+ update_buffer_data(vs_cb, 0, sizeof(cb_data), &cb_data);
+
+ ID3D12PipelineState_Release(pso);
+
+ /* geometry shader */
+ pso_desc.GS = gs;
+ hr = ID3D12Device_CreateGraphicsPipelineState(device, &pso_desc,
+ &IID_ID3D12PipelineState, (void **)&pso);
+ ok(hr == S_OK, "Failed to create pipeline state, hr %#x.\n", hr);
+
+ check_clip_distance(&context, pso, vbv, vb[1], vs_cb, gs_cb);
+
+ cb_data.use_constant = TRUE;
+ cb_data.clip_distance0 = 1.0f;
+ update_buffer_data(gs_cb, 0, sizeof(cb_data), &cb_data);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0);
+
+ ID3D12PipelineState_Release(pso);
+ reset_command_list(command_list, context.allocator);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ /* multiple clip distances */
+ pso_desc.VS = vs_multiple;
+ memset(&pso_desc.GS, 0, sizeof(pso_desc.GS));
+ hr = ID3D12Device_CreateGraphicsPipelineState(device, &pso_desc,
+ &IID_ID3D12PipelineState, (void **)&pso);
+ ok(hr == S_OK, "Failed to create pipeline state, hr %#x.\n", hr);
+
+ cb_data.use_constant = FALSE;
+ update_buffer_data(vs_cb, 0, sizeof(cb_data), &cb_data);
+
+ for (i = 0; i < ARRAY_SIZE(vertices); ++i)
+ vertices[i].clip_distance0 = 1.0f;
+ update_buffer_data(vb[1], 0, sizeof(vertices), vertices);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0);
+
+ reset_command_list(command_list, context.allocator);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ for (i = 0; i < ARRAY_SIZE(vertices); ++i)
+ {
+ vertices[i].clip_distance0 = i < 2 ? 1.0f : -1.0f;
+ vertices[i].clip_distance1 = i % 2 ? 1.0f : -1.0f;
+ }
+ update_buffer_data(vb[1], 0, sizeof(vertices), vertices);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+
+ get_texture_readback_with_command_list(context.render_target, 0, &rb, queue, command_list);
+ set_box(&box, 0, 0, 0, 320, 240, 1);
+ check_readback_data_uint(&rb, &box, 0xff00ff00, 1);
+ set_box(&box, 0, 240, 0, 320, 480, 1);
+ check_readback_data_uint(&rb, &box, 0xffffffff, 1);
+ set_box(&box, 320, 0, 0, 640, 480, 1);
+ check_readback_data_uint(&rb, &box, 0xffffffff, 1);
+ release_resource_readback(&rb);
+
+ reset_command_list(command_list, context.allocator);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
+
+ cb_data.use_constant = TRUE;
+ cb_data.clip_distance0 = 0.0f;
+ cb_data.clip_distance1 = 0.0f;
+ update_buffer_data(vs_cb, 0, sizeof(cb_data), &cb_data);
+ ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL);
+ ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature);
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
+ ID3D12Resource_GetGPUVirtualAddress(vs_cb));
+ ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 2,
+ ID3D12Resource_GetGPUVirtualAddress(gs_cb));
+ ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
+ ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
+ ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport);
+ ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect);
+ ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, ARRAY_SIZE(vbv), vbv);
+ ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL);
+ ID3D12GraphicsCommandList_DrawInstanced(command_list, 4, 1, 0, 0);
+ transition_resource_state(command_list, context.render_target,
+ D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
+ check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0);
+
+ ID3D12PipelineState_Release(pso);
+ for (i = 0; i < ARRAY_SIZE(vb); ++i)
+ ID3D12Resource_Release(vb[i]);
+ ID3D12Resource_Release(vs_cb);
+ ID3D12Resource_Release(gs_cb);
+ destroy_test_context(&context);
+}
+
START_TEST(d3d12)
{
bool enable_debug_layer = false;
@@ -18459,4 +19035,5 @@ START_TEST(d3d12)
run_test(test_layered_rendering);
run_test(test_render_a8);
run_test(test_cpu_descriptors_lifetime);
+ run_test(test_clip_distance);
}
--
2.16.4
2
1
[PATCH vkd3d 4/6] vkd3d-shader: Correctly handle multiple clip/cull distance output registers.
by Józef Kucia 05 Sep '18
by Józef Kucia 05 Sep '18
05 Sep '18
From: Józef Kucia <jkucia(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
libs/vkd3d-shader/spirv.c | 45 ++++++++++++++++++++++++++-------------------
1 file changed, 26 insertions(+), 19 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index ca463f85a4d1..1181c8404f35 100644
--- a/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d-shader/spirv.c
@@ -1867,7 +1867,7 @@ struct vkd3d_dxbc_compiler
{
uint32_t id;
enum vkd3d_component_type component_type;
- bool is_spirv_array;
+ uint32_t array_element_mask;
} *output_info;
uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
uint32_t output_setup_function_id;
@@ -3306,6 +3306,7 @@ static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_
clip_distance_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
SpvStorageClassOutput, builtin->component_type, builtin->component_count, count);
vkd3d_spirv_add_iface_variable(builder, clip_distance_id);
+ vkd3d_dxbc_compiler_decorate_builtin(compiler, clip_distance_id, builtin->spirv_builtin);
}
if (cull_distance_mask)
@@ -3315,6 +3316,7 @@ static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_
cull_distance_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
SpvStorageClassOutput, builtin->component_type, builtin->component_count, count);
vkd3d_spirv_add_iface_variable(builder, cull_distance_id);
+ vkd3d_dxbc_compiler_decorate_builtin(compiler, cull_distance_id, builtin->spirv_builtin);
}
for (i = 0; i < output_signature->element_count; ++i)
@@ -3325,10 +3327,12 @@ static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_
{
case VKD3D_SV_CLIP_DISTANCE:
compiler->output_info[i].id = clip_distance_id;
+ compiler->output_info[i].array_element_mask = clip_distance_mask;
break;
case VKD3D_SV_CULL_DISTANCE:
compiler->output_info[i].id = cull_distance_id;
+ compiler->output_info[i].array_element_mask = cull_distance_mask;
break;
default:
@@ -3388,24 +3392,23 @@ static void vkd3d_dxbc_compiler_emit_output(struct vkd3d_dxbc_compiler *compiler
id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
storage_class, component_type, output_component_count);
vkd3d_spirv_add_iface_variable(builder, id);
- }
- if (builtin)
- {
- vkd3d_dxbc_compiler_decorate_builtin(compiler, id, builtin->spirv_builtin);
- if (component_idx)
- FIXME("Unhandled component index %u.\n", component_idx);
- }
- else
- {
- vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, reg->idx[0].offset);
- if (component_idx)
- vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationComponent, component_idx);
+ if (builtin)
+ {
+ vkd3d_dxbc_compiler_decorate_builtin(compiler, id, builtin->spirv_builtin);
+ if (component_idx)
+ FIXME("Unhandled component index %u.\n", component_idx);
+ }
+ else
+ {
+ vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, reg->idx[0].offset);
+ if (component_idx)
+ vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationComponent, component_idx);
+ }
}
compiler->output_info[signature_idx].id = id;
compiler->output_info[signature_idx].component_type = component_type;
- compiler->output_info[signature_idx].is_spirv_array = builtin && builtin->is_spirv_array;
use_private_variable = component_type != VKD3D_TYPE_FLOAT || component_count != VKD3D_VEC4_SIZE
|| get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_NO_SWIZZLE
@@ -6361,10 +6364,10 @@ static void vkd3d_dxbc_compiler_emit_store_shader_output(struct vkd3d_dxbc_compi
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id;
- uint32_t write_mask, use_mask, uninit_mask, swizzle;
+ uint32_t write_mask, use_mask, uninit_mask, swizzle, mask;
+ uint32_t output_id, indexes[1];
unsigned int component_count;
unsigned int i, index;
- uint32_t output_id;
write_mask = output->mask & 0xff;
use_mask = (output->mask >> 8) & 0xff;
@@ -6392,7 +6395,7 @@ static void vkd3d_dxbc_compiler_emit_store_shader_output(struct vkd3d_dxbc_compi
output_id = output_info->id;
- if (!output_info->is_spirv_array)
+ if (!output_info->array_element_mask)
{
vkd3d_spirv_build_op_store(builder, output_id, val_id, SpvMemoryAccessMaskNone);
return;
@@ -6400,10 +6403,14 @@ static void vkd3d_dxbc_compiler_emit_store_shader_output(struct vkd3d_dxbc_compi
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, 1);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
- for (i = 0, index = output->semantic_index * VKD3D_VEC4_SIZE; i < component_count; ++i, ++index)
+ mask = output_info->array_element_mask;
+ mask &= (1u << (output->semantic_index * VKD3D_VEC4_SIZE)) - 1;
+ for (i = 0, index = vkd3d_popcount(mask); i < VKD3D_VEC4_SIZE; ++i)
{
- uint32_t indexes[] = {vkd3d_dxbc_compiler_get_constant_uint(compiler, index)};
+ if (!(write_mask & (VKD3DSP_WRITEMASK_0 << i)))
+ continue;
+ indexes[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, index++);
chain_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
output_id, indexes, ARRAY_SIZE(indexes));
object_id = vkd3d_dxbc_compiler_emit_swizzle_ext(compiler, val_id,
--
2.16.4
2
1
From: Józef Kucia <jkucia(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
libs/vkd3d-shader/spirv.c | 51 +++++++++++++++++++++++++++++++++++------------
1 file changed, 38 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index 2e8c5cf4ef7f..ca463f85a4d1 100644
--- a/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d-shader/spirv.c
@@ -2978,6 +2978,7 @@ vkd3d_system_value_builtins[] =
{VKD3D_SIV_IS_FRONT_FACE, {VKD3D_TYPE_BOOL, 1, SpvBuiltInFrontFacing, sv_front_face_fixup}},
{VKD3D_SIV_CLIP_DISTANCE, {VKD3D_TYPE_FLOAT, 1, SpvBuiltInClipDistance, NULL, true}},
+ {VKD3D_SIV_CULL_DISTANCE, {VKD3D_TYPE_FLOAT, 1, SpvBuiltInCullDistance, NULL, true}},
};
static const struct
{
@@ -3257,12 +3258,25 @@ static unsigned int get_shader_output_swizzle(struct vkd3d_dxbc_compiler *compil
return compile_args->output_swizzles[register_idx];
}
+static void calculate_clip_or_cull_distance_mask(const struct vkd3d_shader_signature_element *e,
+ uint32_t *mask)
+{
+ if (e->semantic_index >= sizeof(*mask) * CHAR_BIT / VKD3D_VEC4_SIZE)
+ {
+ FIXME("Invalid semantic index %u for clip/cull distance.\n", e->semantic_index);
+ return;
+ }
+
+ *mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
+}
+
/* Emits arrayed SPIR-V built-in variables. */
static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_compiler *compiler)
{
const struct vkd3d_shader_signature *output_signature = compiler->output_signature;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t clip_distance_mask = 0, clip_distance_id = 0;
+ uint32_t cull_distance_mask = 0, cull_distance_id = 0;
const struct vkd3d_spirv_builtin *builtin;
unsigned int i, count;
@@ -3273,13 +3287,11 @@ static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_
switch (e->sysval_semantic)
{
case VKD3D_SV_CLIP_DISTANCE:
- if (e->semantic_index >= sizeof(clip_distance_mask) * CHAR_BIT / VKD3D_VEC4_SIZE)
- {
- ERR("Invalid semantic index %u for clip distance.\n", e->semantic_index);
- break;
- }
+ calculate_clip_or_cull_distance_mask(e, &clip_distance_mask);
+ break;
- clip_distance_mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
+ case VKD3D_SV_CULL_DISTANCE:
+ calculate_clip_or_cull_distance_mask(e, &cull_distance_mask);
break;
default:
@@ -3287,14 +3299,23 @@ static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_
}
}
- if (!clip_distance_mask)
- return;
+ if (clip_distance_mask)
+ {
+ count = vkd3d_popcount(clip_distance_mask);
+ builtin = get_spirv_builtin_for_sysval(VKD3D_SIV_CLIP_DISTANCE);
+ clip_distance_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+ SpvStorageClassOutput, builtin->component_type, builtin->component_count, count);
+ vkd3d_spirv_add_iface_variable(builder, clip_distance_id);
+ }
- count = vkd3d_popcount(clip_distance_mask);
- builtin = get_spirv_builtin_for_sysval(VKD3D_SIV_CLIP_DISTANCE);
- clip_distance_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
- SpvStorageClassOutput, builtin->component_type, builtin->component_count, count);
- vkd3d_spirv_add_iface_variable(builder, clip_distance_id);
+ if (cull_distance_mask)
+ {
+ count = vkd3d_popcount(cull_distance_mask);
+ builtin = get_spirv_builtin_for_sysval(VKD3D_SIV_CULL_DISTANCE);
+ cull_distance_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+ SpvStorageClassOutput, builtin->component_type, builtin->component_count, count);
+ vkd3d_spirv_add_iface_variable(builder, cull_distance_id);
+ }
for (i = 0; i < output_signature->element_count; ++i)
{
@@ -3306,6 +3327,10 @@ static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_
compiler->output_info[i].id = clip_distance_id;
break;
+ case VKD3D_SV_CULL_DISTANCE:
+ compiler->output_info[i].id = cull_distance_id;
+ break;
+
default:
break;
}
--
2.16.4
2
1
05 Sep '18
From: Józef Kucia <jkucia(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
libs/vkd3d-shader/spirv.c | 64 ++++++++++++++++++++---------------------------
1 file changed, 27 insertions(+), 37 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index d40350f18f4d..96d660136755 100644
--- a/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d-shader/spirv.c
@@ -2150,6 +2150,22 @@ static uint32_t vkd3d_dxbc_compiler_get_constant_float_vector(struct vkd3d_dxbc_
VKD3D_TYPE_FLOAT, component_count, (const uint32_t *)values);
}
+static uint32_t vkd3d_dxbc_compiler_get_type_id_for_reg(struct vkd3d_dxbc_compiler *compiler,
+ const struct vkd3d_shader_register *reg, DWORD write_mask)
+{
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+
+ return vkd3d_spirv_get_type_id(builder,
+ vkd3d_component_type_from_data_type(reg->data_type),
+ vkd3d_write_mask_component_count(write_mask));
+}
+
+static uint32_t vkd3d_dxbc_compiler_get_type_id_for_dst(struct vkd3d_dxbc_compiler *compiler,
+ const struct vkd3d_shader_dst_param *dst)
+{
+ return vkd3d_dxbc_compiler_get_type_id_for_reg(compiler, &dst->reg, dst->write_mask);
+}
+
static bool vkd3d_dxbc_compiler_get_register_name(char *buffer, unsigned int buffer_size,
const struct vkd3d_shader_register *reg)
{
@@ -2655,12 +2671,10 @@ static uint32_t vkd3d_dxbc_compiler_emit_abs(struct vkd3d_dxbc_compiler *compile
static uint32_t vkd3d_dxbc_compiler_emit_neg(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
{
- unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id;
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(reg->data_type), component_count);
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_reg(compiler, reg, write_mask);
if (reg->data_type == VKD3D_DATA_FLOAT)
return vkd3d_spirv_build_op_fnegate(builder, type_id, val_id);
else if (reg->data_type == VKD3D_DATA_INT)
@@ -2771,8 +2785,7 @@ static uint32_t vkd3d_dxbc_compiler_emit_sat(struct vkd3d_dxbc_compiler *compile
zero_id = vkd3d_dxbc_compiler_get_constant_float_vector(compiler, 0.0f, component_count);
one_id = vkd3d_dxbc_compiler_get_constant_float_vector(compiler, 1.0f, component_count);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(reg->data_type), component_count);
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_reg(compiler, reg, write_mask);
if (reg->data_type == VKD3D_DATA_FLOAT)
return vkd3d_spirv_build_op_glsl_std450_nclamp(builder, type_id, val_id, zero_id, one_id);
@@ -4092,7 +4105,6 @@ static void vkd3d_dxbc_compiler_emit_alu_instruction(struct vkd3d_dxbc_compiler
const struct vkd3d_shader_dst_param *dst = instruction->dst;
const struct vkd3d_shader_src_param *src = instruction->src;
uint32_t src_ids[VKD3D_DXBC_MAX_SOURCE_COUNT];
- unsigned int component_count;
uint32_t type_id, val_id;
unsigned int i;
SpvOp op;
@@ -4107,9 +4119,7 @@ static void vkd3d_dxbc_compiler_emit_alu_instruction(struct vkd3d_dxbc_compiler
assert(instruction->dst_count == 1);
assert(instruction->src_count <= VKD3D_DXBC_MAX_SOURCE_COUNT);
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst->reg.data_type), component_count);
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst);
for (i = 0; i < instruction->src_count; ++i)
src_ids[i] = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[i], dst->write_mask);
@@ -4169,7 +4179,6 @@ static void vkd3d_dxbc_compiler_emit_ext_glsl_instruction(struct vkd3d_dxbc_comp
const struct vkd3d_shader_src_param *src = instruction->src;
uint32_t src_id[VKD3D_DXBC_MAX_SOURCE_COUNT];
uint32_t instr_set_id, type_id, val_id;
- unsigned int component_count;
enum GLSLstd450 glsl_inst;
unsigned int i;
@@ -4185,9 +4194,7 @@ static void vkd3d_dxbc_compiler_emit_ext_glsl_instruction(struct vkd3d_dxbc_comp
assert(instruction->dst_count == 1);
assert(instruction->src_count <= VKD3D_DXBC_MAX_SOURCE_COUNT);
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst->reg.data_type), component_count);
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst);
for (i = 0; i < instruction->src_count; ++i)
src_id[i] = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[i], dst->write_mask);
@@ -4353,8 +4360,7 @@ static void vkd3d_dxbc_compiler_emit_rcp(struct vkd3d_dxbc_compiler *compiler,
unsigned int component_count;
component_count = vkd3d_write_mask_component_count(dst->write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst->reg.data_type), component_count);
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst);
src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst->write_mask);
val_id = vkd3d_spirv_build_op_fdiv(builder, type_id,
@@ -4370,14 +4376,10 @@ static void vkd3d_dxbc_compiler_emit_sincos(struct vkd3d_dxbc_compiler *compiler
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const struct vkd3d_shader_src_param *src = instruction->src;
uint32_t type_id, src_id, sin_id = 0, cos_id = 0;
- unsigned int component_count;
if (dst_sin->reg.type != VKD3DSPR_NULL)
{
- component_count = vkd3d_write_mask_component_count(dst_sin->write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst_sin->reg.data_type), component_count);
-
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst_sin);
src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst_sin->write_mask);
sin_id = vkd3d_spirv_build_op_glsl_std450_sin(builder, type_id, src_id);
@@ -4387,10 +4389,7 @@ static void vkd3d_dxbc_compiler_emit_sincos(struct vkd3d_dxbc_compiler *compiler
{
if (dst_sin->reg.type == VKD3DSPR_NULL || dst_cos->write_mask != dst_sin->write_mask)
{
- component_count = vkd3d_write_mask_component_count(dst_cos->write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst_cos->reg.data_type), component_count);
-
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst_cos);
src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst_cos->write_mask);
}
@@ -4411,7 +4410,6 @@ static void vkd3d_dxbc_compiler_emit_imul(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_dst_param *dst = instruction->dst;
const struct vkd3d_shader_src_param *src = instruction->src;
uint32_t type_id, val_id, src0_id, src1_id;
- unsigned int component_count;
if (dst[0].reg.type != VKD3DSPR_NULL)
FIXME("Extended multiplies not implemented.\n"); /* SpvOpSMulExtended */
@@ -4419,9 +4417,7 @@ static void vkd3d_dxbc_compiler_emit_imul(struct vkd3d_dxbc_compiler *compiler,
if (dst[1].reg.type == VKD3DSPR_NULL)
return;
- component_count = vkd3d_write_mask_component_count(dst[1].write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst[1].reg.data_type), component_count);
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, &dst[1]);
src0_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst[1].write_mask);
src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst[1].write_mask);
@@ -4464,8 +4460,7 @@ static void vkd3d_dxbc_compiler_emit_udiv(struct vkd3d_dxbc_compiler *compiler,
if (dst[0].reg.type != VKD3DSPR_NULL)
{
component_count = vkd3d_write_mask_component_count(dst[0].write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst[0].reg.data_type), component_count);
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, &dst[0]);
src0_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst[0].write_mask);
src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst[0].write_mask);
@@ -4487,8 +4482,7 @@ static void vkd3d_dxbc_compiler_emit_udiv(struct vkd3d_dxbc_compiler *compiler,
if (!component_count || dst[0].write_mask != dst[1].write_mask)
{
component_count = vkd3d_write_mask_component_count(dst[1].write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst[1].reg.data_type), component_count);
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, &dst[1]);
src0_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[0], dst[1].write_mask);
src1_id = vkd3d_dxbc_compiler_emit_load_src(compiler, &src[1], dst[1].write_mask);
@@ -5023,7 +5017,6 @@ static void vkd3d_dxbc_compiler_emit_deriv_instruction(struct vkd3d_dxbc_compile
const struct vkd3d_shader_src_param *src = instruction->src;
const struct instruction_info *info;
uint32_t type_id, src_id, val_id;
- unsigned int component_count;
unsigned int i;
static const struct instruction_info
@@ -5063,10 +5056,7 @@ static void vkd3d_dxbc_compiler_emit_deriv_instruction(struct vkd3d_dxbc_compile
assert(instruction->dst_count == 1);
assert(instruction->src_count == 1);
- component_count = vkd3d_write_mask_component_count(dst->write_mask);
- type_id = vkd3d_spirv_get_type_id(builder,
- vkd3d_component_type_from_data_type(dst->reg.data_type), component_count);
-
+ type_id = vkd3d_dxbc_compiler_get_type_id_for_dst(compiler, dst);
src_id = vkd3d_dxbc_compiler_emit_load_src(compiler, src, dst->write_mask);
val_id = vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, info->op, type_id, src_id);
vkd3d_dxbc_compiler_emit_store_dst(compiler, dst, val_id);
--
2.16.4
2
1
From: Józef Kucia <jkucia(a)codeweavers.com>
Signed-off-by: Józef Kucia <jkucia(a)codeweavers.com>
---
libs/vkd3d-shader/spirv.c | 112 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 104 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c
index 96d660136755..2e8c5cf4ef7f 100644
--- a/libs/vkd3d-shader/spirv.c
+++ b/libs/vkd3d-shader/spirv.c
@@ -1867,6 +1867,7 @@ struct vkd3d_dxbc_compiler
{
uint32_t id;
enum vkd3d_component_type component_type;
+ bool is_spirv_array;
} *output_info;
uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */
uint32_t output_setup_function_id;
@@ -1877,6 +1878,8 @@ struct vkd3d_dxbc_compiler
const struct vkd3d_shader_scan_info *scan_info;
};
+static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_compiler *compiler);
+
struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,
const struct vkd3d_shader_desc *shader_desc, uint32_t compiler_options,
const struct vkd3d_shader_interface *shader_interface,
@@ -1951,6 +1954,8 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader
compiler->scan_info = scan_info;
+ vkd3d_dxbc_compiler_emit_shader_signature_outputs(compiler);
+
return compiler;
}
@@ -2950,6 +2955,7 @@ struct vkd3d_spirv_builtin
unsigned int component_count;
SpvBuiltIn spirv_builtin;
vkd3d_spirv_builtin_fixup_pfn fixup_pfn;
+ bool is_spirv_array;
};
/*
@@ -2970,6 +2976,8 @@ vkd3d_system_value_builtins[] =
{VKD3D_SIV_RENDER_TARGET_ARRAY_INDEX, {VKD3D_TYPE_INT, 1, SpvBuiltInLayer}},
{VKD3D_SIV_IS_FRONT_FACE, {VKD3D_TYPE_BOOL, 1, SpvBuiltInFrontFacing, sv_front_face_fixup}},
+
+ {VKD3D_SIV_CLIP_DISTANCE, {VKD3D_TYPE_FLOAT, 1, SpvBuiltInClipDistance, NULL, true}},
};
static const struct
{
@@ -3249,6 +3257,61 @@ static unsigned int get_shader_output_swizzle(struct vkd3d_dxbc_compiler *compil
return compile_args->output_swizzles[register_idx];
}
+/* Emits arrayed SPIR-V built-in variables. */
+static void vkd3d_dxbc_compiler_emit_shader_signature_outputs(struct vkd3d_dxbc_compiler *compiler)
+{
+ const struct vkd3d_shader_signature *output_signature = compiler->output_signature;
+ struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t clip_distance_mask = 0, clip_distance_id = 0;
+ const struct vkd3d_spirv_builtin *builtin;
+ unsigned int i, count;
+
+ for (i = 0; i < output_signature->element_count; ++i)
+ {
+ const struct vkd3d_shader_signature_element *e = &output_signature->elements[i];
+
+ switch (e->sysval_semantic)
+ {
+ case VKD3D_SV_CLIP_DISTANCE:
+ if (e->semantic_index >= sizeof(clip_distance_mask) * CHAR_BIT / VKD3D_VEC4_SIZE)
+ {
+ ERR("Invalid semantic index %u for clip distance.\n", e->semantic_index);
+ break;
+ }
+
+ clip_distance_mask |= (e->mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!clip_distance_mask)
+ return;
+
+ count = vkd3d_popcount(clip_distance_mask);
+ builtin = get_spirv_builtin_for_sysval(VKD3D_SIV_CLIP_DISTANCE);
+ clip_distance_id = vkd3d_dxbc_compiler_emit_array_variable(compiler, &builder->global_stream,
+ SpvStorageClassOutput, builtin->component_type, builtin->component_count, count);
+ vkd3d_spirv_add_iface_variable(builder, clip_distance_id);
+
+ for (i = 0; i < output_signature->element_count; ++i)
+ {
+ const struct vkd3d_shader_signature_element *e = &output_signature->elements[i];
+
+ switch (e->sysval_semantic)
+ {
+ case VKD3D_SV_CLIP_DISTANCE:
+ compiler->output_info[i].id = clip_distance_id;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
static void vkd3d_dxbc_compiler_emit_output(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval)
{
@@ -3276,22 +3339,32 @@ static void vkd3d_dxbc_compiler_emit_output(struct vkd3d_dxbc_compiler *compiler
component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask);
component_count = vkd3d_write_mask_component_count(dst->write_mask);
+ output_component_count = vkd3d_write_mask_component_count(signature_element->mask & 0xff);
if (builtin)
{
component_type = builtin->component_type;
- output_component_count = builtin->component_count;
+ if (!builtin->is_spirv_array)
+ output_component_count = builtin->component_count;
}
else
{
component_type = signature_element->component_type;
- output_component_count = vkd3d_write_mask_component_count(signature_element->mask & 0xff);
}
assert(component_count <= output_component_count);
storage_class = SpvStorageClassOutput;
- id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
- storage_class, component_type, output_component_count);
- vkd3d_spirv_add_iface_variable(builder, id);
+
+ if (compiler->output_info[signature_idx].id)
+ {
+ id = compiler->output_info[signature_idx].id;
+ }
+ else
+ {
+ id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
+ storage_class, component_type, output_component_count);
+ vkd3d_spirv_add_iface_variable(builder, id);
+ }
+
if (builtin)
{
vkd3d_dxbc_compiler_decorate_builtin(compiler, id, builtin->spirv_builtin);
@@ -3307,9 +3380,11 @@ static void vkd3d_dxbc_compiler_emit_output(struct vkd3d_dxbc_compiler *compiler
compiler->output_info[signature_idx].id = id;
compiler->output_info[signature_idx].component_type = component_type;
+ compiler->output_info[signature_idx].is_spirv_array = builtin && builtin->is_spirv_array;
use_private_variable = component_type != VKD3D_TYPE_FLOAT || component_count != VKD3D_VEC4_SIZE
- || get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_NO_SWIZZLE;
+ || get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_NO_SWIZZLE
+ || (builtin && builtin->is_spirv_array);
if (use_private_variable)
storage_class = SpvStorageClassPrivate;
@@ -6260,9 +6335,11 @@ static void vkd3d_dxbc_compiler_emit_store_shader_output(struct vkd3d_dxbc_compi
const struct vkd3d_shader_output_info *output_info, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
+ uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id;
uint32_t write_mask, use_mask, uninit_mask, swizzle;
unsigned int component_count;
- uint32_t type_id, zero_id;
+ unsigned int i, index;
+ uint32_t output_id;
write_mask = output->mask & 0xff;
use_mask = (output->mask >> 8) & 0xff;
@@ -6288,7 +6365,26 @@ static void vkd3d_dxbc_compiler_emit_store_shader_output(struct vkd3d_dxbc_compi
val_id, zero_id, uninit_mask, output_info->component_type, component_count);
}
- vkd3d_spirv_build_op_store(builder, output_info->id, val_id, SpvMemoryAccessMaskNone);
+ output_id = output_info->id;
+
+ if (!output_info->is_spirv_array)
+ {
+ vkd3d_spirv_build_op_store(builder, output_id, val_id, SpvMemoryAccessMaskNone);
+ return;
+ }
+
+ type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, 1);
+ ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id);
+ for (i = 0, index = output->semantic_index * VKD3D_VEC4_SIZE; i < component_count; ++i, ++index)
+ {
+ uint32_t indexes[] = {vkd3d_dxbc_compiler_get_constant_uint(compiler, index)};
+
+ chain_id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
+ output_id, indexes, ARRAY_SIZE(indexes));
+ object_id = vkd3d_dxbc_compiler_emit_swizzle_ext(compiler, val_id,
+ write_mask, output_info->component_type, VKD3D_NO_SWIZZLE, VKD3DSP_WRITEMASK_0 << i);
+ vkd3d_spirv_build_op_store(builder, chain_id, object_id, SpvMemoryAccessMaskNone);
+ }
}
static void vkd3d_dxbc_compiler_emit_output_setup_function(struct vkd3d_dxbc_compiler *compiler)
--
2.16.4
2
1